-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGoEnvConfig.go
82 lines (64 loc) · 2.06 KB
/
GoEnvConfig.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
/* Package goenvconfig provides immutability for configuration automatically loaded from environment variables. */
package goenvconfig
import (
"errors"
"os"
"reflect"
"strconv"
"unsafe"
)
const (
envKey = "env"
envDefaultKey = "default"
)
/* GoEnvParser represents an object capable of parsing environment variables into a struct, given specific tags. */
type GoEnvParser interface {
Parse(object interface{}) error
}
type goEnvParser struct{}
/* NewGoEnvParser returns a new GoEnvParser. */
func NewGoEnvParser() GoEnvParser {
return &goEnvParser{}
}
/* Parse accepts a struct pointer and populates private properties according to "env" and "default" tag keys. */
func (*goEnvParser) Parse(object interface{}) error {
if reflect.TypeOf(object).Kind() != reflect.Ptr {
return errors.New("objects passed to env.Parse() must be of kind pointer")
}
addressableCopy := createAddressableCopy(object)
for i := 0; i < addressableCopy.NumField(); i++ {
fieldRef := addressableCopy.Field(i)
fieldRef = reflect.NewAt(fieldRef.Type(), unsafe.Pointer(fieldRef.UnsafeAddr())).Elem()
newValue := getValueForTag(reflect.TypeOf(object).Elem(), i)
switch fieldRef.Type().Kind() {
case reflect.Int:
if newInt, err := strconv.ParseInt(newValue, 10, 32); err == nil {
fieldRef.SetInt(newInt)
}
case reflect.String:
fieldRef.SetString(newValue)
}
}
object = addressableCopy.Interface()
return nil
}
func createAddressableCopy(object interface{}) reflect.Value {
originalValue := reflect.ValueOf(object)
objectCopy := reflect.New(originalValue.Type()).Elem()
objectCopy.Set(originalValue)
if originalValue.Type().Kind() == reflect.Ptr {
objectCopy = objectCopy.Elem()
}
return objectCopy
}
func getValueForTag(addressableCopy reflect.Type, fieldNum int) string {
if envKey, ok := addressableCopy.Field(fieldNum).Tag.Lookup(envKey); ok {
if envVar, exists := os.LookupEnv(envKey); exists {
return envVar
}
}
if envDefaultValue, ok := addressableCopy.Field(fieldNum).Tag.Lookup(envDefaultKey); ok {
return envDefaultValue
}
return ""
}