-
Notifications
You must be signed in to change notification settings - Fork 0
/
env.go
385 lines (329 loc) · 7.71 KB
/
env.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
// env is a simple package for loading configuration, based loosly on
// Ruby's `dotenv` gem.
//
// Example:
//
// package main
//
// import (
// "github.com/jmervine/env"
//
// "fmt"
// )
//
// func init() {
// env.PanicOnRequire = true
// var err error
// err = env.Load("_example/example.env")
// if err != nil {
// // work in _example
// err = env.Load("example.env")
// if err != nil {
// panic(err)
// }
// }
//
// // ensure requires
// env.Require("DATABASE_URL")
// }
//
// func main() {
// fmt.Printf("dburl ::: %s\n", env.Get("DATABASE_URL"))
// fmt.Printf("addr ::: %s\n", env.Get("ADDR"))
// fmt.Printf("port ::: %d\n", env.GetInt("PORT"))
//
// if env.GetBool("IGNORED") {
// fmt.Printf("ignored ::: %v\n", env.GetBool("IGNORED"))
// }
//
// if env.GetBool("DEBUG") {
// fmt.Printf("debug ::: %v\n", env.GetBool("DEBUG"))
// }
// }
package env
import (
"fmt"
"os"
"strconv"
"strings"
"time"
dotenv "github.com/jmervine/env/Godeps/_workspace/src/github.com/joho/godotenv"
)
// PanicOnRequire forces panics when Require- methods fail
var PanicOnRequire = false
// Load loads a file containing standard os environment key/value pairs,
// doesn't override currently set variables
//
// e.g.: .env
//
// PORT=3000
// ADDR=0.0.0.0
// DEBUG=true
//
func Load(filenames ...string) error {
return dotenv.Load(filenames...)
}
// Overload does the same thing as Load, but overrides existing variables
func Overload(filenames ...string) error {
env, err := dotenv.Read(filenames...)
if err != nil {
return err
}
for key, val := range env {
os.Setenv(key, val)
}
return nil
}
// Set sets via an interface
func Set(key string, val interface{}) {
os.Setenv(key, toString(val))
}
// SetMap iterates over a map and sets keys to values
func SetMap(m map[string]interface{}) {
for key, val := range m {
Set(key, val)
}
}
// Get gets a key and returns a string
func Get(key string) string {
return os.Getenv(key)
}
// Require gets a key and returns a string or an error if it's set to "" in
// os.Getenv
func Require(key string) (val string, err error) {
val = Get(key)
if val == "" {
err = onError(fmt.Errorf("missing required string from %s", key))
}
return val, err
}
// GetOrSet gets a key and returns a string or set's the default
func GetOrSet(key string, val interface{}) string {
str := Get(key)
if str != "" {
return str
}
v := toString(val)
Set(key, v)
return v
}
// GetString is an alias to Get
func GetString(key string) string {
return Get(key)
}
// GetString is an alias to Require
func RequireString(key string) (string, error) {
return Require(key)
}
// GetOrSetString is an alias to GetOrSet, except it only takes a string
// as default value
func GetOrSetString(key, val string) string {
return GetOrSet(key, val)
}
// GetBytes gets get and converts value to []byte
func GetBytes(key string) []byte {
return []byte(Get(key))
}
// GetBytes requires key and converts value to []byte
func RequireBytes(key string) ([]byte, error) {
s, e := Require(key)
return []byte(s), e
}
// GetBytes gets or sets key and returns value as []byte
func GetOrSetBytes(key string, val []byte) []byte {
return []byte(GetOrSet(key, val))
}
// GetDuration gets key and returns value as time.Duration
func GetDuration(key string) time.Duration {
return toDur(Get(key))
}
// GetDuration requires key and returns value as time.Duration
func RequireDuration(key string) (time.Duration, error) {
str, err := Require(key)
if err != nil {
d := new(time.Duration)
return *d, onError(fmt.Errorf("missing required duration from %s", key))
}
return toDur(str), nil
}
// GetDuration gets or sets key and returns value as time.Duration
func GetOrSetDuration(key string, val time.Duration) time.Duration {
str := Get(key)
if str != "" {
return toDur(str)
}
Set(key, val)
return val
}
// GetInt gets a key and returns an int
func GetInt(key string) int {
return toInt(Get(key))
}
// GetOrSetInt gets or sets key and returns value as int
func GetOrSetInt(key string, val int) int {
str := Get(key)
if str != "" {
return toInt(str)
}
Set(key, val)
return val
}
func RequireInt(key string) (int, error) {
str := Get(key)
if str != "" {
return toInt(str), nil
}
return int(0), onError(fmt.Errorf("missing required int from %s", key))
}
// GetInt32 gets a key and returns an int32
func GetInt32(key string) int32 {
return toInt32(Get(key))
}
func GetOrSetInt32(key string, val int32) int32 {
str := Get(key)
if str != "" {
return toInt32(str)
}
Set(key, val)
return val
}
func RequireInt32(key string) (int32, error) {
str := Get(key)
if str == "" {
return int32(0), onError(fmt.Errorf("missing required int32 from %s", key))
}
return toInt32(str), nil
}
// GetInt64 gets a key and returns an int64
func GetInt64(key string) int64 {
return toInt64(Get(key))
}
func GetOrSetInt64(key string, val int64) int64 {
str := Get(key)
if str != "" {
return toInt64(str)
}
Set(key, val)
return val
}
func RequireInt64(key string) (int64, error) {
str := Get(key)
if str == "" {
return int64(0), onError(fmt.Errorf("missing required int64 from %s", key))
}
return toInt64(str), nil
}
// GetFloat32 gets a key and returns an float32
func GetFloat32(key string) float32 {
return toFloat32(Get(key))
}
func GetOrSetFloat32(key string, val float32) float32 {
str := Get(key)
if str != "" {
return toFloat32(str)
}
Set(key, val)
return val
}
func RequireFloat32(key string) (float32, error) {
str := Get(key)
if str == "" {
return float32(0), onError(fmt.Errorf("missing required float32 from %s", key))
}
return toFloat32(str), nil
}
// GetFloat64 gets a key and returns an float64
func GetFloat64(key string) float64 {
return toFloat64(Get(key))
}
func GetOrSetFloat64(key string, val float64) float64 {
str := Get(key)
if str != "" {
return toFloat64(str)
}
Set(key, val)
return val
}
func RequireFloat64(key string) (float64, error) {
str := Get(key)
if str == "" {
return float64(0), onError(fmt.Errorf("missing required float64 from %s", key))
}
return toFloat64(str), nil
}
// GetBool gets a key and sets to true, false or nil using the Truthy and Falsey
// variables
func GetBool(key string) bool {
return toBool(Get(key))
}
func GetOrSetBool(key string, val bool) bool {
str := Get(key)
if str != "" {
return toBool(str)
}
Set(key, val)
return val
}
func RequireBool(key string) (bool, error) {
str := Get(key)
if str == "" {
return false, onError(fmt.Errorf("missing required bool from %s", key))
}
return toBool(str), nil
}
// HELPERS
func toBool(val string) bool {
b, _ := strconv.ParseBool(val)
return b
}
func toString(v interface{}) string {
switch t := v.(type) {
case string:
// noop
return t
case []byte:
// special for []byte
return string(t)
case []string:
// easer eggs for later
return strings.Join(t, ",")
case []interface{}:
// easer eggs for later
strs := make([]string, 0)
for _, i := range t {
strs = append(strs, toString(i))
}
return strings.Join(strs, ",")
}
return fmt.Sprintf("%v", v)
}
func toDur(str string) time.Duration {
dur, _ := time.ParseDuration(str)
return dur
}
func toInt(val string) int {
i, _ := strconv.ParseInt(val, 10, 16)
return int(i)
}
func toInt32(val string) int32 {
i, _ := strconv.ParseInt(val, 10, 32)
return int32(i)
}
func toInt64(val string) int64 {
i, _ := strconv.ParseInt(val, 10, 64)
return int64(i)
}
func toFloat32(val string) float32 {
i, _ := strconv.ParseFloat(val, 32)
return float32(i)
}
func toFloat64(val string) float64 {
i, _ := strconv.ParseFloat(val, 64)
return float64(i)
}
func onError(e error) error {
if PanicOnRequire {
panic(e)
}
return e
}