summaryrefslogtreecommitdiffstats
path: root/common/maps
diff options
context:
space:
mode:
Diffstat (limited to 'common/maps')
-rw-r--r--common/maps/maps.go35
-rw-r--r--common/maps/maps_test.go8
-rw-r--r--common/maps/params.go98
-rw-r--r--common/maps/params_test.go16
4 files changed, 117 insertions, 40 deletions
diff --git a/common/maps/maps.go b/common/maps/maps.go
index 2d8a122ca..6aefde927 100644
--- a/common/maps/maps.go
+++ b/common/maps/maps.go
@@ -43,25 +43,25 @@ func ToStringMapE(in any) (map[string]any, error) {
// ToParamsAndPrepare converts in to Params and prepares it for use.
// If in is nil, an empty map is returned.
// See PrepareParams.
-func ToParamsAndPrepare(in any) (Params, bool) {
+func ToParamsAndPrepare(in any) (Params, error) {
if types.IsNil(in) {
- return Params{}, true
+ return Params{}, nil
}
m, err := ToStringMapE(in)
if err != nil {
- return nil, false
+ return nil, err
}
PrepareParams(m)
- return m, true
+ return m, nil
}
// MustToParamsAndPrepare calls ToParamsAndPrepare and panics if it fails.
func MustToParamsAndPrepare(in any) Params {
- if p, ok := ToParamsAndPrepare(in); ok {
- return p
- } else {
- panic(fmt.Sprintf("cannot convert %T to maps.Params", in))
+ p, err := ToParamsAndPrepare(in)
+ if err != nil {
+ panic(fmt.Sprintf("cannot convert %T to maps.Params: %s", in, err))
}
+ return p
}
// ToStringMap converts in to map[string]interface{}.
@@ -96,6 +96,8 @@ func ToSliceStringMap(in any) ([]map[string]any, error) {
switch v := in.(type) {
case []map[string]any:
return v, nil
+ case Params:
+ return []map[string]any{v}, nil
case []any:
var s []map[string]any
for _, entry := range v {
@@ -123,6 +125,23 @@ func LookupEqualFold[T any | string](m map[string]T, key string) (T, bool) {
return s, false
}
+// MergeShallow merges src into dst, but only if the key does not already exist in dst.
+// The keys are compared case insensitively.
+func MergeShallow(dst, src map[string]any) {
+ for k, v := range src {
+ found := false
+ for dk := range dst {
+ if strings.EqualFold(dk, k) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ dst[k] = v
+ }
+ }
+}
+
type keyRename struct {
pattern glob.Glob
newKey string
diff --git a/common/maps/maps_test.go b/common/maps/maps_test.go
index 0b84d2dd7..0e8589d34 100644
--- a/common/maps/maps_test.go
+++ b/common/maps/maps_test.go
@@ -116,11 +116,11 @@ func TestToSliceStringMap(t *testing.T) {
func TestToParamsAndPrepare(t *testing.T) {
c := qt.New(t)
- _, ok := ToParamsAndPrepare(map[string]any{"A": "av"})
- c.Assert(ok, qt.IsTrue)
+ _, err := ToParamsAndPrepare(map[string]any{"A": "av"})
+ c.Assert(err, qt.IsNil)
- params, ok := ToParamsAndPrepare(nil)
- c.Assert(ok, qt.IsTrue)
+ params, err := ToParamsAndPrepare(nil)
+ c.Assert(err, qt.IsNil)
c.Assert(params, qt.DeepEquals, Params{})
}
diff --git a/common/maps/params.go b/common/maps/params.go
index 4bf95f43b..eb60fbbfc 100644
--- a/common/maps/params.go
+++ b/common/maps/params.go
@@ -23,30 +23,37 @@ import (
// Params is a map where all keys are lower case.
type Params map[string]any
-// Get does a lower case and nested search in this map.
+// KeyParams is an utility struct for the WalkParams method.
+type KeyParams struct {
+ Key string
+ Params Params
+}
+
+// GetNested does a lower case and nested search in this map.
// It will return nil if none found.
-func (p Params) Get(indices ...string) any {
+// Make all of these methods internal somehow.
+func (p Params) GetNested(indices ...string) any {
v, _, _ := getNested(p, indices)
return v
}
-// Set overwrites values in p with values in pp for common or new keys.
+// Set overwrites values in dst with values in src for common or new keys.
// This is done recursively.
-func (p Params) Set(pp Params) {
- for k, v := range pp {
- vv, found := p[k]
+func SetParams(dst, src Params) {
+ for k, v := range src {
+ vv, found := dst[k]
if !found {
- p[k] = v
+ dst[k] = v
} else {
switch vvv := vv.(type) {
case Params:
if pv, ok := v.(Params); ok {
- vvv.Set(pv)
+ SetParams(vvv, pv)
} else {
- p[k] = v
+ dst[k] = v
}
default:
- p[k] = v
+ dst[k] = v
}
}
}
@@ -70,18 +77,17 @@ func (p Params) IsZero() bool {
}
-// Merge transfers values from pp to p for new keys.
+// MergeParamsWithStrategy transfers values from src to dst for new keys using the merge strategy given.
// This is done recursively.
-func (p Params) Merge(pp Params) {
- p.merge("", pp)
+func MergeParamsWithStrategy(strategy string, dst, src Params) {
+ dst.merge(ParamsMergeStrategy(strategy), src)
}
-// MergeRoot transfers values from pp to p for new keys where p is the
-// root of the tree.
+// MergeParamsWithStrategy transfers values from src to dst for new keys using the merge encoded in dst.
// This is done recursively.
-func (p Params) MergeRoot(pp Params) {
- ms, _ := p.GetMergeStrategy()
- p.merge(ms, pp)
+func MergeParams(dst, src Params) {
+ ms, _ := dst.GetMergeStrategy()
+ dst.merge(ms, src)
}
func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
@@ -116,6 +122,7 @@ func (p Params) merge(ps ParamsMergeStrategy, pp Params) {
}
}
+// For internal use.
func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
if v, found := p[mergeStrategyKey]; found {
if s, ok := v.(ParamsMergeStrategy); ok {
@@ -125,6 +132,7 @@ func (p Params) GetMergeStrategy() (ParamsMergeStrategy, bool) {
return ParamsMergeStrategyShallow, false
}
+// For internal use.
func (p Params) DeleteMergeStrategy() bool {
if _, found := p[mergeStrategyKey]; found {
delete(p, mergeStrategyKey)
@@ -133,7 +141,8 @@ func (p Params) DeleteMergeStrategy() bool {
return false
}
-func (p Params) SetDefaultMergeStrategy(s ParamsMergeStrategy) {
+// For internal use.
+func (p Params) SetMergeStrategy(s ParamsMergeStrategy) {
switch s {
case ParamsMergeStrategyDeep, ParamsMergeStrategyNone, ParamsMergeStrategyShallow:
default:
@@ -187,7 +196,7 @@ func GetNestedParam(keyStr, separator string, candidates ...Params) (any, error)
keySegments := strings.Split(keyStr, separator)
for _, m := range candidates {
- if v := m.Get(keySegments...); v != nil {
+ if v := m.GetNested(keySegments...); v != nil {
return v, nil
}
}
@@ -236,6 +245,55 @@ const (
mergeStrategyKey = "_merge"
)
+// CleanConfigStringMapString removes any processing instructions from m,
+// m will never be modified.
+func CleanConfigStringMapString(m map[string]string) map[string]string {
+ if m == nil || len(m) == 0 {
+ return m
+ }
+ if _, found := m[mergeStrategyKey]; !found {
+ return m
+ }
+ // Create a new map and copy all the keys except the merge strategy key.
+ m2 := make(map[string]string, len(m)-1)
+ for k, v := range m {
+ if k != mergeStrategyKey {
+ m2[k] = v
+ }
+ }
+ return m2
+}
+
+// CleanConfigStringMap is the same as CleanConfigStringMapString but for
+// map[string]any.
+func CleanConfigStringMap(m map[string]any) map[string]any {
+ if m == nil || len(m) == 0 {
+ return m
+ }
+ if _, found := m[mergeStrategyKey]; !found {
+ return m
+ }
+ // Create a new map and copy all the keys except the merge strategy key.
+ m2 := make(map[string]any, len(m)-1)
+ for k, v := range m {
+ if k != mergeStrategyKey {
+ m2[k] = v
+ }
+ switch v2 := v.(type) {
+ case map[string]any:
+ m2[k] = CleanConfigStringMap(v2)
+ case Params:
+ var p Params = CleanConfigStringMap(v2)
+ m2[k] = p
+ case map[string]string:
+ m2[k] = CleanConfigStringMapString(v2)
+ }
+
+ }
+ return m2
+
+}
+
func toMergeStrategy(v any) ParamsMergeStrategy {
s := ParamsMergeStrategy(cast.ToString(v))
switch s {
diff --git a/common/maps/params_test.go b/common/maps/params_test.go
index a070e6f60..7e1dbbae7 100644
--- a/common/maps/params_test.go
+++ b/common/maps/params_test.go
@@ -81,7 +81,7 @@ func TestParamsSetAndMerge(t *testing.T) {
p1, p2 := createParamsPair()
- p1.Set(p2)
+ SetParams(p1, p2)
c.Assert(p1, qt.DeepEquals, Params{
"a": "abv",
@@ -97,7 +97,7 @@ func TestParamsSetAndMerge(t *testing.T) {
p1, p2 = createParamsPair()
- p1.Merge(p2)
+ MergeParamsWithStrategy("", p1, p2)
// Default is to do a shallow merge.
c.Assert(p1, qt.DeepEquals, Params{
@@ -111,8 +111,8 @@ func TestParamsSetAndMerge(t *testing.T) {
})
p1, p2 = createParamsPair()
- p1.SetDefaultMergeStrategy(ParamsMergeStrategyNone)
- p1.Merge(p2)
+ p1.SetMergeStrategy(ParamsMergeStrategyNone)
+ MergeParamsWithStrategy("", p1, p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{
@@ -125,8 +125,8 @@ func TestParamsSetAndMerge(t *testing.T) {
})
p1, p2 = createParamsPair()
- p1.SetDefaultMergeStrategy(ParamsMergeStrategyShallow)
- p1.Merge(p2)
+ p1.SetMergeStrategy(ParamsMergeStrategyShallow)
+ MergeParamsWithStrategy("", p1, p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{
@@ -140,8 +140,8 @@ func TestParamsSetAndMerge(t *testing.T) {
})
p1, p2 = createParamsPair()
- p1.SetDefaultMergeStrategy(ParamsMergeStrategyDeep)
- p1.Merge(p2)
+ p1.SetMergeStrategy(ParamsMergeStrategyDeep)
+ MergeParamsWithStrategy("", p1, p2)
p1.DeleteMergeStrategy()
c.Assert(p1, qt.DeepEquals, Params{