in pkg/dubboctl/internal/manifest/tree.go [327:413]
func setValueContext(nc *PathContext, value interface{}, merge bool) (bool, error) {
if nc.Parent == nil {
return false, nil
}
vv, mapFromString := tryToUnmarshalStringToYAML(value)
switch parentNode := nc.Parent.Node.(type) {
case *interface{}:
switch vParentNode := (*parentNode).(type) {
case []interface{}:
idx := nc.Parent.KeyToChild.(int)
if idx == -1 {
// Treat -1 as insert-at-end of list
idx = len(vParentNode)
}
if idx >= len(vParentNode) {
newElements := make([]interface{}, idx-len(vParentNode)+1)
vParentNode = append(vParentNode, newElements...)
*parentNode = vParentNode
}
merged, err := mergeConditional(vv, nc.Node, merge)
if err != nil {
return false, err
}
vParentNode[idx] = merged
nc.Node = merged
default:
return false, fmt.Errorf("don't know about vtype %T", vParentNode)
}
case map[string]interface{}:
key := nc.Parent.KeyToChild.(string)
// Update is treated differently depending on whether the value is a scalar or map type. If scalar,
// insert a new element into the terminal node, otherwise replace the terminal node with the new subtree.
if ncNode, ok := nc.Node.(*interface{}); ok && !mapFromString {
switch vNcNode := (*ncNode).(type) {
case []interface{}:
switch vv.(type) {
case map[string]interface{}:
// the vv is a map, and the node is a slice
mergedValue := append(vNcNode, vv)
parentNode[key] = mergedValue
case *interface{}:
merged, err := mergeConditional(vv, vNcNode, merge)
if err != nil {
return false, err
}
parentNode[key] = merged
nc.Node = merged
default:
// the vv is an basic JSON type (int, float, string, bool)
vv = append(vNcNode, vv)
parentNode[key] = vv
nc.Node = vv
}
default:
return false, fmt.Errorf("don't know about vnc type %T", vNcNode)
}
} else {
// For map passed as string type, the root is the new key.
if mapFromString {
if err := util.DeleteFromMap(nc.Parent.Node, nc.Parent.KeyToChild); err != nil {
return false, err
}
vm := vv.(map[string]interface{})
newKey := getTreeRoot(vm)
return false, util.InsertIntoMap(nc.Parent.Node, newKey, vm[newKey])
}
parentNode[key] = vv
nc.Node = vv
}
// TODO `map[interface{}]interface{}` is used by tests in operator/cmd/mesh, we should add our own tests
case map[interface{}]interface{}:
key := nc.Parent.KeyToChild.(string)
parentNode[key] = vv
nc.Node = vv
default:
return false, fmt.Errorf("don't know about type %T", parentNode)
}
return true, nil
}