func setValueContext()

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
}