better merge of values
This commit is contained in:
@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
@ -62,15 +63,44 @@ func newRenderContext(host *clustersconfig.Host, cfg *clustersconfig.Config) (ct
|
||||
|
||||
func mapMerge(target, source map[string]interface{}) {
|
||||
for k, v := range source {
|
||||
if tMap, targetIsMap := target[k].(map[string]interface{}); targetIsMap {
|
||||
if sMap, sourceIsMap := v.(map[string]interface{}); sourceIsMap {
|
||||
mapMerge(tMap, sMap)
|
||||
target[k] = genericMerge(target[k], v)
|
||||
}
|
||||
}
|
||||
|
||||
func genericMerge(target, source interface{}) (result interface{}) {
|
||||
srcV := reflect.ValueOf(source)
|
||||
tgtV := reflect.ValueOf(target)
|
||||
|
||||
if srcV.Kind() == reflect.Map && tgtV.Kind() == reflect.Map {
|
||||
// XXX maybe more specific later
|
||||
result = map[interface{}]interface{}{}
|
||||
resultV := reflect.ValueOf(result)
|
||||
|
||||
tgtIt := tgtV.MapRange()
|
||||
for tgtIt.Next() {
|
||||
sv := srcV.MapIndex(tgtIt.Key())
|
||||
if sv.Kind() == 0 {
|
||||
resultV.SetMapIndex(tgtIt.Key(), tgtIt.Value())
|
||||
continue
|
||||
}
|
||||
|
||||
merged := genericMerge(tgtIt.Value().Interface(), sv.Interface())
|
||||
resultV.SetMapIndex(tgtIt.Key(), reflect.ValueOf(merged))
|
||||
}
|
||||
|
||||
target[k] = v
|
||||
srcIt := srcV.MapRange()
|
||||
for srcIt.Next() {
|
||||
if resultV.MapIndex(srcIt.Key()).Kind() != 0 {
|
||||
continue // already done
|
||||
}
|
||||
|
||||
resultV.SetMapIndex(srcIt.Key(), srcIt.Value())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
func (ctx *renderContext) Config() string {
|
||||
|
54
cmd/dkl-dir2config/render-context_test.go
Normal file
54
cmd/dkl-dir2config/render-context_test.go
Normal file
@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
if v := genericMerge("a", "b"); v != "b" {
|
||||
t.Errorf("got %q", v)
|
||||
}
|
||||
|
||||
if v := unparse(genericMerge(parse(`
|
||||
a: t
|
||||
b: t
|
||||
m:
|
||||
a1: t
|
||||
b1: t
|
||||
`), parse(`
|
||||
a: s
|
||||
c: s
|
||||
m:
|
||||
a1: s
|
||||
c1: s
|
||||
`))); "\n"+v != `
|
||||
a: s
|
||||
b: t
|
||||
c: s
|
||||
m:
|
||||
a1: s
|
||||
b1: t
|
||||
c1: s
|
||||
` {
|
||||
t.Errorf("got\n%s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func parse(s string) (r interface{}) {
|
||||
r = map[string]interface{}{}
|
||||
err := yaml.Unmarshal([]byte(s), r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func unparse(v interface{}) (s string) {
|
||||
ba, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(ba)
|
||||
}
|
Reference in New Issue
Block a user