mirror of https://github.com/status-im/consul.git
decode: recursively unslice opaque config
Also handle []interface{} in HookWeakDecodeFromSlice Without this change only the top level []map[string]interface{} will be unpacked as a single item. With this change any nested config will be unpacked.
This commit is contained in:
parent
166a8b2a58
commit
a46ce3d841
|
@ -7,6 +7,8 @@ package decode
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/reflectwalk"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HookTranslateKeys is a mapstructure decode hook which translates keys in a
|
// HookTranslateKeys is a mapstructure decode hook which translates keys in a
|
||||||
|
@ -120,15 +122,39 @@ func HookWeakDecodeFromSlice(from, to reflect.Type, data interface{}) (interface
|
||||||
|
|
||||||
switch d := data.(type) {
|
switch d := data.(type) {
|
||||||
case []map[string]interface{}:
|
case []map[string]interface{}:
|
||||||
switch {
|
if len(d) == 1 {
|
||||||
case len(d) == 0:
|
return unSlice(d[0])
|
||||||
return nil, nil
|
}
|
||||||
case len(d) == 1:
|
// the JSON decoder can apparently decode slices as []interface{}
|
||||||
return d[0], nil
|
case []interface{}:
|
||||||
default:
|
if len(d) == 1 {
|
||||||
return data, nil
|
return unSlice(d[0])
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return data, nil
|
|
||||||
}
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unSlice(data interface{}) (interface{}, error) {
|
||||||
|
err := reflectwalk.Walk(data, &unSliceWalker{})
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type unSliceWalker struct{}
|
||||||
|
|
||||||
|
func (u *unSliceWalker) Map(_ reflect.Value) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *unSliceWalker) MapElem(m, k, v reflect.Value) error {
|
||||||
|
if !v.IsValid() || v.Kind() != reflect.Interface {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v.Elem() // unpack the value from the interface{}
|
||||||
|
if v.Kind() != reflect.Slice || v.Len() != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
m.SetMapIndex(k, v.Index(0))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,3 +272,39 @@ item {
|
||||||
}
|
}
|
||||||
require.Equal(t, target, expected)
|
require.Equal(t, target, expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHookWeakDecodeFromSlice_NestedOpaqueConfig(t *testing.T) {
|
||||||
|
source := `
|
||||||
|
service {
|
||||||
|
proxy {
|
||||||
|
config {
|
||||||
|
envoy_gateway_bind_addresses {
|
||||||
|
all-interfaces {
|
||||||
|
address = "0.0.0.0"
|
||||||
|
port = 8443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
target := map[string]interface{}{}
|
||||||
|
err := decodeHCLToMapStructure(source, &target)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expected := map[string]interface{}{
|
||||||
|
"service": map[string]interface{}{
|
||||||
|
"proxy": map[string]interface{}{
|
||||||
|
"config": map[string]interface{}{
|
||||||
|
"envoy_gateway_bind_addresses": map[string]interface{}{
|
||||||
|
"all-interfaces": map[string]interface{}{
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"port": 8443,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.Equal(t, target, expected)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue