handle int slice as well

This commit is contained in:
Jason Lee 2024-01-03 14:10:52 +08:00
parent c0546f7419
commit 44bde863fa
2 changed files with 30 additions and 23 deletions

View file

@ -1149,19 +1149,11 @@ func unmarshalPostProcess(input any, opts ...DecoderConfigOption) error {
return err
}
v.postProcessingSliceFields(map[string]bool{}, structKeyMap, "")
v.postProcessingSliceFields(structKeyMap, "")
return nil
}
// TODO remove shadow
func (v *Viper) postProcessingSliceFields(shadow map[string]bool, m map[string]any, prefix string) map[string]bool {
if shadow != nil && prefix != "" && shadow[prefix] {
// prefix is shadowed => nothing more to flatten
return shadow
}
if shadow == nil {
shadow = make(map[string]bool)
}
func (v *Viper) postProcessingSliceFields(m map[string]any, prefix string) {
var m2 map[string]any
if prefix != "" {
@ -1173,21 +1165,29 @@ func (v *Viper) postProcessingSliceFields(shadow map[string]bool, m map[string]a
if valValue.Kind() == reflect.Slice {
for i := 0; i < valValue.Len(); i++ {
item := valValue.Index(i)
if item.Kind() != reflect.Struct || !item.CanSet() {
iStr := strconv.FormatInt(int64(i), 10)
fmt.Printf("item %v\n", item)
if !item.CanSet() {
continue
}
itemType := item.Type()
for j := 0; j < item.NumField(); j++ {
field := itemType.Field(j)
// fmt.Printf("Field %d: Name=%s, Type=%v, Value=%v\n", j, field.Name, field.Type, item.Field(j).Interface())
sliceKey := fmt.Sprintf("%s%s%s%d%s%s", prefix, k, v.keyDelim, i, v.keyDelim, field.Name)
shadow[strings.ToLower(sliceKey)] = true
// fmt.Printf("%s is slice\n", sliceKey)
if item.Kind() == reflect.Struct {
itemType := item.Type()
for j := 0; j < item.NumField(); j++ {
field := itemType.Field(j)
sliceKey := prefix + k + v.keyDelim + iStr + v.keyDelim + field.Name
// fmt.Printf("%s is slice\n", sliceKey)
if val, ok := v.getEnv(v.mergeWithEnvPrefix(sliceKey)); ok {
// fmt.Printf("Val is %v\n", val)
item.Field(j).SetString(val)
}
}
} else {
sliceKey := prefix + k + v.keyDelim + iStr
if val, ok := v.getEnv(v.mergeWithEnvPrefix(sliceKey)); ok {
// fmt.Printf("Val is %v\n", val)
item.Field(j).SetString(val)
intValue, _ := strconv.ParseInt(val, 10, 32)
item.SetInt(intValue)
}
}
}
@ -1202,9 +1202,8 @@ func (v *Viper) postProcessingSliceFields(shadow map[string]bool, m map[string]a
continue
}
// recursively merge to shadow map
shadow = v.postProcessingSliceFields(shadow, m2, fullKey)
v.postProcessingSliceFields(m2, fullKey)
}
return shadow
}
func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {

View file

@ -2611,6 +2611,10 @@ name: Steve
port: 8080
auth:
secret: 88888-88888
modes:
- 1
- 2
- 3
clients:
- name: foo
- name: bar
@ -2641,6 +2645,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
Port int
Name string
Auth AuthConfig
Modes []int
Clients []ClientConfig
Proxy ProxyConfig
}
@ -2655,10 +2660,12 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
assert.Equal(t, "foo", v.GetString("clients.0.name"))
assert.Equal(t, "bar", v.GetString("clients.1.name"))
assert.Equal(t, "proxy_foo", v.GetString("proxy.clients.0.name"))
assert.Equal(t, []int{1, 2, 3}, v.GetIntSlice("modes"))
// Override with env variable
t.Setenv("NAME", "Steven")
t.Setenv("AUTH_SECRET", "99999-99999")
t.Setenv("MODES_2", "300")
t.Setenv("CLIENTS_1_NAME", "baz")
t.Setenv("PROXY_CLIENTS_0_NAME", "ProxyFoo")
@ -2672,6 +2679,7 @@ func TestSliceIndexAutomaticEnv(t *testing.T) {
assert.Equal(t, "Steven", config.Name)
assert.Equal(t, 8080, config.Port)
assert.Equal(t, "99999-99999", config.Auth.Secret)
assert.Equal(t, []int{1, 2, 300}, config.Modes)
assert.Equal(t, "foo", config.Clients[0].Name)
assert.Equal(t, "baz", config.Clients[1].Name)
assert.Equal(t, "ProxyFoo", config.Proxy.Clients[0].Name)