Allow embedded structs in env_options

This commit is contained in:
Joel Speed 2019-05-05 19:12:36 +01:00
parent 14d559939f
commit 2da89f8425
No known key found for this signature in database
GPG Key ID: 6E80578D6751DEFB
2 changed files with 41 additions and 8 deletions

View File

@ -15,14 +15,27 @@ type EnvOptions map[string]interface{}
// Fields in the options struct must have an `env` and `cfg` tag to be read // Fields in the options struct must have an `env` and `cfg` tag to be read
// from the environment // from the environment
func (cfg EnvOptions) LoadEnvForStruct(options interface{}) { func (cfg EnvOptions) LoadEnvForStruct(options interface{}) {
val := reflect.ValueOf(options).Elem() val := reflect.ValueOf(options)
typ := val.Type() var typ reflect.Type
if val.Kind() == reflect.Ptr {
typ = val.Elem().Type()
} else {
typ = val.Type()
}
for i := 0; i < typ.NumField(); i++ { for i := 0; i < typ.NumField(); i++ {
// pull out the struct tags: // pull out the struct tags:
// flag - the name of the command line flag // flag - the name of the command line flag
// deprecated - (optional) the name of the deprecated command line flag // deprecated - (optional) the name of the deprecated command line flag
// cfg - (optional, defaults to underscored flag) the name of the config file option // cfg - (optional, defaults to underscored flag) the name of the config file option
field := typ.Field(i) field := typ.Field(i)
fieldV := reflect.Indirect(val).Field(i)
if field.Type.Kind() == reflect.Struct && field.Anonymous {
cfg.LoadEnvForStruct(fieldV.Interface())
continue
}
flagName := field.Tag.Get("flag") flagName := field.Tag.Get("flag")
envName := field.Tag.Get("env") envName := field.Tag.Get("env")
cfgName := field.Tag.Get("cfg") cfgName := field.Tag.Get("cfg")

View File

@ -1,26 +1,46 @@
package main package main_test
import ( import (
"os" "os"
"testing" "testing"
proxy "github.com/pusher/oauth2_proxy"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type envTest struct { type EnvTest struct {
testField string `cfg:"target_field" env:"TEST_ENV_FIELD"` TestField string `cfg:"target_field" env:"TEST_ENV_FIELD"`
EnvTestEmbed
}
type EnvTestEmbed struct {
TestFieldEmbed string `cfg:"target_field_embed" env:"TEST_ENV_FIELD_EMBED"`
} }
func TestLoadEnvForStruct(t *testing.T) { func TestLoadEnvForStruct(t *testing.T) {
cfg := make(EnvOptions) cfg := make(proxy.EnvOptions)
cfg.LoadEnvForStruct(&envTest{}) cfg.LoadEnvForStruct(&EnvTest{})
_, ok := cfg["target_field"] _, ok := cfg["target_field"]
assert.Equal(t, ok, false) assert.Equal(t, ok, false)
os.Setenv("TEST_ENV_FIELD", "1234abcd") os.Setenv("TEST_ENV_FIELD", "1234abcd")
cfg.LoadEnvForStruct(&envTest{}) cfg.LoadEnvForStruct(&EnvTest{})
v := cfg["target_field"] v := cfg["target_field"]
assert.Equal(t, v, "1234abcd") assert.Equal(t, v, "1234abcd")
} }
func TestLoadEnvForStructWithEmbeddedFields(t *testing.T) {
cfg := make(proxy.EnvOptions)
cfg.LoadEnvForStruct(&EnvTest{})
_, ok := cfg["target_field_embed"]
assert.Equal(t, ok, false)
os.Setenv("TEST_ENV_FIELD_EMBED", "1234abcd")
cfg.LoadEnvForStruct(&EnvTest{})
v := cfg["target_field_embed"]
assert.Equal(t, v, "1234abcd")
}