support multiple env params for single value

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2022-11-26 15:38:29 +03:00
parent 9ef42ec0e9
commit 3ac95bcf83
2 changed files with 108 additions and 11 deletions

29
env.go
View File

@ -219,13 +219,14 @@ func (c *envConfig) setValues(ctx context.Context, valueOf reflect.Value) error
continue continue
} }
tag, ok := field.Tag.Lookup(c.opts.StructTag) tags, ok := field.Tag.Lookup(c.opts.StructTag)
if !ok { if !ok {
continue continue
} }
for _, tag := range strings.Split(tags, ",") {
if err := os.Setenv(tag, fmt.Sprintf("%v", value.Interface())); err != nil && !c.opts.AllowFail { if err := os.Setenv(tag, fmt.Sprintf("%v", value.Interface())); err != nil && !c.opts.AllowFail {
return err return err
}
} }
} }
@ -278,16 +279,24 @@ func fillValues(ctx context.Context, valueOf reflect.Value, structTag string) er
} }
continue continue
} }
tag, ok := field.Tag.Lookup(structTag) tags, ok := field.Tag.Lookup(structTag)
if !ok {
continue
}
val, ok := os.LookupEnv(tag)
if !ok { if !ok {
continue continue
} }
if err := fillValue(ctx, value, val); err != nil { var eval string
for _, tag := range strings.Split(tags, ",") {
if val, ok := os.LookupEnv(tag); !ok {
continue
} else {
eval = val
}
}
if eval == "" {
continue
}
if err := fillValue(ctx, value, eval); err != nil {
return err return err
} }
} }

View File

@ -11,7 +11,7 @@ import (
) )
type Config struct { type Config struct {
StringValue string `env:"STRING_VALUE"` StringValue string `env:"STRING_VALUE,STRING_VALUE2"`
BoolValue bool `env:"BOOL_VALUE"` BoolValue bool `env:"BOOL_VALUE"`
StringSlice []string `env:"STRING_SLICE"` StringSlice []string `env:"STRING_SLICE"`
IntSlice []int `env:"INT_SLICE"` IntSlice []int `env:"INT_SLICE"`
@ -20,6 +20,14 @@ type Config struct {
} }
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
defer func() {
for _, v := range []string{"STRING_VALUE", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}()
ctx := context.Background() ctx := context.Background()
type Nested struct { type Nested struct {
Name string `env:"NAME_VALUE"` Name string `env:"NAME_VALUE"`
@ -47,6 +55,9 @@ func TestMerge(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
}() }()
if err != nil {
t.Fatal(err)
}
os.Setenv("NAME_VALUE", "after") os.Setenv("NAME_VALUE", "after")
changes, err := w.Next() changes, err := w.Next()
@ -66,6 +77,14 @@ func TestMerge(t *testing.T) {
} }
func TestLoad(t *testing.T) { func TestLoad(t *testing.T) {
defer func() {
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}()
ctx := context.Background() ctx := context.Background()
conf := &Config{StringValue: "before_load"} conf := &Config{StringValue: "before_load"}
cfg := NewConfig(config.Struct(conf)) cfg := NewConfig(config.Struct(conf))
@ -111,9 +130,23 @@ func TestLoad(t *testing.T) {
if len(conf.MapIntValue) != 2 { if len(conf.MapIntValue) != 2 {
t.Fatalf("something wrong with env config: %#+v", conf.MapIntValue) t.Fatalf("something wrong with env config: %#+v", conf.MapIntValue)
} }
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
} }
func TestSave(t *testing.T) { func TestSave(t *testing.T) {
defer func() {
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}()
ctx := context.Background() ctx := context.Background()
conf := &Config{StringValue: "MICRO_CONFIG_ENV"} conf := &Config{StringValue: "MICRO_CONFIG_ENV"}
cfg := NewConfig(config.Struct(conf)) cfg := NewConfig(config.Struct(conf))
@ -149,4 +182,59 @@ func TestSave(t *testing.T) {
t.Fatalf("env value %s=%s set", tv, v) t.Fatalf("env value %s=%s set", tv, v)
} }
} }
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}
func TestLoadMultiple(t *testing.T) {
defer func() {
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}()
ctx := context.Background()
conf := &Config{StringValue: "before_load"}
cfg := NewConfig(config.Struct(conf))
if err := cfg.Init(); err != nil {
t.Fatal(err)
}
if err := cfg.Load(ctx, config.LoadOverride(true), config.LoadAppend(true)); err != nil {
t.Fatal(err)
}
if conf.StringValue != "before_load" {
t.Fatalf("something wrong with env config: %#+v", conf)
}
os.Setenv("STRING_VALUE", "STRING_VALUE1")
os.Setenv("STRING_VALUE2", "STRING_VALUE2")
defer func() {
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
}()
if err := cfg.Load(ctx, config.LoadOverride(true), config.LoadAppend(true)); err != nil {
t.Fatal(err)
}
if conf.StringValue != "STRING_VALUE2" {
t.Fatalf("something wrong with env config: %#+v", conf)
}
for _, v := range []string{"STRING_VALUE", "STRING_VALUE2", "BOOL_VALUE", "STRING_SLICE", "INT_SLICE", "MAP_STRING", "MAP_INT"} {
if err := os.Unsetenv(v); err != nil {
t.Fatal(err)
}
}
} }