From 0ac6b6fabacfde9bd66d736376a5fe67bb95ad34 Mon Sep 17 00:00:00 2001 From: Matt Keeler Date: Thu, 2 May 2019 14:43:54 -0400 Subject: [PATCH] Fix up the MapWalk function so that it properly handles nested map[interface{}]interface{} (#5774) --- go.mod | 2 +- go.sum | 4 +-- lib/map_walker.go | 25 +++++++++++++++- lib/map_walker_test.go | 29 ++++++++++--------- .../github.com/mitchellh/reflectwalk/go.mod | 1 + .../mitchellh/reflectwalk/reflectwalk.go | 3 +- vendor/modules.txt | 2 +- 7 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 vendor/github.com/mitchellh/reflectwalk/go.mod diff --git a/go.mod b/go.mod index 21d65112a1..1811ea4462 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,7 @@ require ( github.com/mitchellh/go-testing-interface v1.0.0 github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 github.com/mitchellh/mapstructure v1.1.2 - github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc + github.com/mitchellh/reflectwalk v1.0.1 github.com/oklog/run v0.0.0-20180308005104-6934b124db28 // indirect github.com/onsi/gomega v1.4.2 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 // indirect diff --git a/go.sum b/go.sum index 6d24f08e5b..8f0f717d8b 100644 --- a/go.sum +++ b/go.sum @@ -256,8 +256,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc h1:gqYjvctjtX4GHzgfutJxZpvZ7XhGwQLGR5BASwhpO2o= -github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= diff --git a/lib/map_walker.go b/lib/map_walker.go index 2f41fcf55e..95827a0eee 100644 --- a/lib/map_walker.go +++ b/lib/map_walker.go @@ -95,8 +95,31 @@ func (w *mapWalker) Map(m reflect.Value) error { func (w *mapWalker) MapElem(m, k, v reflect.Value) error { w.csData = k w.csKey = append(w.csKey, k) - w.lastValue = v + + // We're looking specifically for map[interface{}]interface{}, but the + // values in a map could be wrapped up in interface{} so we need to unwrap + // that first. Therefore, we do three checks: 1.) is it valid? so we + // don't panic, 2.) is it an interface{}? so we can unwrap it and 3.) + // after unwrapping the interface do we have the map we expect? + if !v.IsValid() { + return nil + } + + if v.Kind() != reflect.Interface { + return nil + } + + if inner := v.Elem(); inner.Type() == typMapIfaceIface { + // map[interface{}]interface{}, attempt to weakly decode into string keys + var target map[string]interface{} + if err := mapstructure.WeakDecode(v.Interface(), &target); err != nil { + return err + } + + m.SetMapIndex(k, reflect.ValueOf(target)) + } + return nil } diff --git a/lib/map_walker_test.go b/lib/map_walker_test.go index cbe8534c8e..45c8c0d5e7 100644 --- a/lib/map_walker_test.go +++ b/lib/map_walker_test.go @@ -38,20 +38,21 @@ func TestMapWalk(t *testing.T) { }, unexpected: true, }, - // TODO(banks): despite the doc comment, MapWalker doesn't actually fix - // these cases yet. Do that in a later PR. - // "map iface": tcase{ - // input: map[string]interface{}{ - // "foo": map[interface{}]interface{}{ - // "bar": "baz", - // }, - // }, - // expected: map[string]interface{}{ - // "foo": map[string]interface{}{ - // "bar": "baz", - // }, - // }, - // }, + // ensure nested maps get processed correctly + "nested": tcase{ + input: map[string]interface{}{ + "foo": map[interface{}]interface{}{ + "bar": []uint8("baz"), + }, + "bar": []uint8("baz"), + }, + expected: map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": "baz", + }, + "bar": "baz", + }, + }, } for name, tcase := range cases { diff --git a/vendor/github.com/mitchellh/reflectwalk/go.mod b/vendor/github.com/mitchellh/reflectwalk/go.mod new file mode 100644 index 0000000000..52bb7c469e --- /dev/null +++ b/vendor/github.com/mitchellh/reflectwalk/go.mod @@ -0,0 +1 @@ +module github.com/mitchellh/reflectwalk diff --git a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go index d7ab7b6d78..3a93a0b114 100644 --- a/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go +++ b/vendor/github.com/mitchellh/reflectwalk/reflectwalk.go @@ -230,7 +230,8 @@ func walkMap(v reflect.Value, w interface{}) error { ew.Enter(MapValue) } - if err := walk(kv, w); err != nil { + // get the map value again as it may have changed in the MapElem call + if err := walk(v.MapIndex(k), w); err != nil { return err } diff --git a/vendor/modules.txt b/vendor/modules.txt index 0e10ee7e29..f89db9577e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -377,7 +377,7 @@ github.com/mitchellh/go-testing-interface github.com/mitchellh/hashstructure # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure -# github.com/mitchellh/reflectwalk v0.0.0-20170726202117-63d60e9d0dbc +# github.com/mitchellh/reflectwalk v1.0.1 github.com/mitchellh/reflectwalk # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd github.com/modern-go/concurrent