Skip to content

Commit

Permalink
refactor: use structure to present the status of env var
Browse files Browse the repository at this point in the history
  • Loading branch information
raymond-chia committed Aug 12, 2020
1 parent b8ff723 commit 76f8d93
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 20 deletions.
32 changes: 20 additions & 12 deletions envconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,39 @@ import (
// 2. Duplicated field tags will be assigned with the same environment variable.
func Load(prefix string, out interface{}, opts ...Option) {
loader := loader{}
loader.envStatus = map[string]bool{}
loader.handleEnvironmentVariables = func(map[string]bool) {}
loader.envStatuses = map[string]*EnvStatus{}
loader.handleEnvironmentVariables = func(map[string]*EnvStatus) {}
for _, opt := range opts {
opt(&loader)
}

val := reflect.ValueOf(out).Elem()
loader.loadStruct(strings.ToUpper(prefix), &val)

loader.handleEnvironmentVariables(loader.envStatus)
loader.handleEnvironmentVariables(loader.envStatuses)
}

type loader struct {
handleEnvironmentVariables func(map[string]bool)
envStatus map[string]bool
handleEnvironmentVariables func(map[string]*EnvStatus)
envStatuses map[string]*EnvStatus
}

func (l *loader) useKey(name string) error {
if _, ok := l.envStatus[name]; ok {
if _, ok := l.envStatuses[name]; ok {
return fmt.Errorf("Duplicated key %v", name)
}
l.envStatus[name] = false
l.envStatuses[name] = &EnvStatus{}
return nil
}

type EnvStatus struct {
Loaded bool
}

func (e *EnvStatus) SetLoaded() {
e.Loaded = true
}

var stringSliceType = reflect.TypeOf([]string{})

func (l *loader) loadField(name string, out *reflect.Value) {
Expand Down Expand Up @@ -141,7 +149,7 @@ func (l *loader) loadString(name string, out *reflect.Value) {
if !found {
return
}
l.envStatus[name] = true
l.envStatuses[name].SetLoaded()

out.SetString(data)
}
Expand All @@ -151,7 +159,7 @@ func (l *loader) loadInt(name string, out *reflect.Value) {
if !found {
return
}
l.envStatus[name] = true
l.envStatuses[name].SetLoaded()

d, err := strconv.ParseInt(data, 10, 64)
if err != nil {
Expand All @@ -166,7 +174,7 @@ func (l *loader) loadUint(name string, out *reflect.Value) {
if !found {
return
}
l.envStatus[name] = true
l.envStatuses[name].SetLoaded()

d, err := strconv.ParseUint(data, 10, 64)
if err != nil {
Expand All @@ -181,7 +189,7 @@ func (l *loader) loadBool(name string, out *reflect.Value) {
if !found {
return
}
l.envStatus[name] = true
l.envStatuses[name].SetLoaded()

isTrue := data == "true" || data == "TRUE" || data == "True" || data == "1"
isFalse := data == "false" || data == "FALSE" || data == "False" || data == "0"
Expand All @@ -198,7 +206,7 @@ func (l *loader) loadStringSlice(name string, out *reflect.Value) {
if !found {
return
}
l.envStatus[name] = true
l.envStatuses[name].SetLoaded()

strListRaw := strings.Split(data, ",")
strList := []string{}
Expand Down
12 changes: 9 additions & 3 deletions envconf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ func TestLogger(t *testing.T) {
os.Setenv("TEST_INTEGER", "-3")
os.Setenv("TEST_UNSIGNED_INTEGER", "3")

result := map[string]bool{}
result := map[string]*EnvStatus{}
config := struct {
String string `env:"string"`
Integer int `env:"integer"`
Expand All @@ -328,10 +328,16 @@ func TestLogger(t *testing.T) {
StrSlice []string `env:"string_slice"`
} `env:",inline"`
}{}
Load("TEST", &config, CustomHandleEnvVarsOption(func(status map[string]bool) {
Load("TEST", &config, CustomHandleEnvVarsOption(func(status map[string]*EnvStatus) {
result = status
}))

expected := map[string]bool{"TEST_STRING": false, "TEST_INTEGER": true, "TEST_UNSIGNED_INTEGER": true, "TEST_BOOL": false, "TEST_STRING_SLICE": false}
expected := map[string]*EnvStatus{
"TEST_STRING": {false},
"TEST_INTEGER": {true},
"TEST_UNSIGNED_INTEGER": {true},
"TEST_BOOL": {false},
"TEST_STRING_SLICE": {false},
}
assertEqual(t, "", expected, result)
}
2 changes: 1 addition & 1 deletion option.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type Option func(*loader)
//
// The map keys are the environment variable names that are checked by envconf,
// and the values present whether the corresponding environment variables are set.
func CustomHandleEnvVarsOption(cb func(map[string]bool)) Option {
func CustomHandleEnvVarsOption(cb func(map[string]*EnvStatus)) Option {
return func(l *loader) {
l.handleEnvironmentVariables = cb
}
Expand Down
8 changes: 5 additions & 3 deletions options/predefined.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"encoding/json"
"io"
"log"

"gitlab.rayark.com/backend/envconf"
)

// LogStatusOfEnvVars will log the status of environment variables used by given structure.
// MakeJSONLogger will log the status of environment variables used by given structure.
// The message is in JSON format.
func LogStatusOfEnvVars(w io.Writer) func(map[string]bool) {
return func(status map[string]bool) {
func MakeJSONLogger(w io.Writer) func(map[string]*envconf.EnvStatus) {
return func(status map[string]*envconf.EnvStatus) {
logger := log.New(w, "", 0)

result := map[string]interface{}{}
Expand Down
2 changes: 1 addition & 1 deletion options/predefined_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestLogger(t *testing.T) {
Integer int `env:"integer"`
}{}
buf := bytes.NewBuffer(nil)
envconf.Load("TEST", &config, envconf.CustomHandleEnvVarsOption(options.LogStatusOfEnvVars(buf)))
envconf.Load("TEST", &config, envconf.CustomHandleEnvVarsOption(options.MakeJSONLogger(buf)))

if buf.String() == "" {
t.Errorf("failed to log environment variable status")
Expand Down

0 comments on commit 76f8d93

Please sign in to comment.