diff options
-rw-r--r-- | common/maps/params.go | 21 | ||||
-rw-r--r-- | common/maps/params_test.go | 12 | ||||
-rw-r--r-- | config/defaultConfigProvider.go | 10 | ||||
-rw-r--r-- | config/defaultConfigProvider_test.go | 20 |
4 files changed, 58 insertions, 5 deletions
diff --git a/common/maps/params.go b/common/maps/params.go index e5a1bd07d..c14026df7 100644 --- a/common/maps/params.go +++ b/common/maps/params.go @@ -52,6 +52,24 @@ func (p Params) Set(pp Params) { } } +// IsZero returns true if p is considered empty. +func (p Params) IsZero() bool { + if p == nil || len(p) == 0 { + return true + } + + if len(p) > 1 { + return false + } + + for k, _ := range p { + return k == mergeStrategyKey + } + + return false + +} + // Merge transfers values from pp to p for new keys. // This is done recursively. func (p Params) Merge(pp Params) { @@ -82,12 +100,9 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) { if pv, ok := v.(Params); ok { vvv.merge(ms, pv) } - } - } else if !noUpdate { p[k] = v - } } diff --git a/common/maps/params_test.go b/common/maps/params_test.go index 8859bb86b..5c799aae1 100644 --- a/common/maps/params_test.go +++ b/common/maps/params_test.go @@ -156,3 +156,15 @@ func TestParamsSetAndMerge(t *testing.T) { }) } + +func TestParamsIsZero(t *testing.T) { + c := qt.New(t) + + var nilParams Params + + c.Assert(Params{}.IsZero(), qt.IsTrue) + c.Assert(nilParams.IsZero(), qt.IsTrue) + c.Assert(Params{"foo": "bar"}.IsZero(), qt.IsFalse) + c.Assert(Params{"_merge": "foo", "foo": "bar"}.IsZero(), qt.IsFalse) + c.Assert(Params{"_merge": "foo"}.IsZero(), qt.IsTrue) +} diff --git a/config/defaultConfigProvider.go b/config/defaultConfigProvider.go index a5e2d09fd..80353664e 100644 --- a/config/defaultConfigProvider.go +++ b/config/defaultConfigProvider.go @@ -214,6 +214,7 @@ func (c *defaultConfigProvider) Merge(k string, v interface{}) { if p, ok := maps.ToParamsAndPrepare(v); ok { // As there may be keys in p not in root, we need to handle // those as a special case. + var keysToDelete []string for kk, vv := range p { if pp, ok := vv.(maps.Params); ok { if pppi, ok := c.root[kk]; ok { @@ -261,14 +262,19 @@ func (c *defaultConfigProvider) Merge(k string, v interface{}) { strategy := c.determineMergeStrategy(KeyParams{Key: "", Params: c.root}, KeyParams{Key: kk, Params: np}) np.SetDefaultMergeStrategy(strategy) np.Merge(pp) - if len(np) > 0 { - c.root[kk] = np + c.root[kk] = np + if np.IsZero() { + // Just keep it until merge is done. + keysToDelete = append(keysToDelete, kk) } } } } // Merge the rest. c.root.Merge(p) + for _, k := range keysToDelete { + delete(c.root, k) + } } else { panic(fmt.Sprintf("unsupported type %T received in Merge", v)) } diff --git a/config/defaultConfigProvider_test.go b/config/defaultConfigProvider_test.go index 6752ab2e5..7ab8c049a 100644 --- a/config/defaultConfigProvider_test.go +++ b/config/defaultConfigProvider_test.go @@ -283,6 +283,26 @@ func TestDefaultConfigProvider(t *testing.T) { }) + // Issue #8701 + c.Run("Prevent _merge only maps", func(c *qt.C) { + cfg := New() + + cfg.Set("", map[string]interface{}{ + "B": "bv", + }) + + cfg.Merge("", map[string]interface{}{ + "c": map[string]interface{}{ + "_merge": "shallow", + "d": "dv2", + }, + }) + + c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{ + "b": "bv", + }) + }) + c.Run("IsSet", func(c *qt.C) { cfg := New() |