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 return err
} }
v.postProcessingSliceFields(map[string]bool{}, structKeyMap, "") v.postProcessingSliceFields(structKeyMap, "")
return nil return nil
} }
// TODO remove shadow func (v *Viper) postProcessingSliceFields(m map[string]any, prefix string) {
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)
}
var m2 map[string]any var m2 map[string]any
if prefix != "" { if prefix != "" {
@ -1173,16 +1165,17 @@ func (v *Viper) postProcessingSliceFields(shadow map[string]bool, m map[string]a
if valValue.Kind() == reflect.Slice { if valValue.Kind() == reflect.Slice {
for i := 0; i < valValue.Len(); i++ { for i := 0; i < valValue.Len(); i++ {
item := valValue.Index(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 continue
} }
if item.Kind() == reflect.Struct {
itemType := item.Type() itemType := item.Type()
for j := 0; j < item.NumField(); j++ { for j := 0; j < item.NumField(); j++ {
field := itemType.Field(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 := prefix + k + v.keyDelim + iStr + v.keyDelim + field.Name
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) // fmt.Printf("%s is slice\n", sliceKey)
if val, ok := v.getEnv(v.mergeWithEnvPrefix(sliceKey)); ok { if val, ok := v.getEnv(v.mergeWithEnvPrefix(sliceKey)); ok {
@ -1190,6 +1183,13 @@ func (v *Viper) postProcessingSliceFields(shadow map[string]bool, m map[string]a
item.Field(j).SetString(val) item.Field(j).SetString(val)
} }
} }
} else {
sliceKey := prefix + k + v.keyDelim + iStr
if val, ok := v.getEnv(v.mergeWithEnvPrefix(sliceKey)); ok {
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 continue
} }
// recursively merge to shadow map // 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) { func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {

View File

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