Esempio n. 1
0
func processMerges(orig yaml.Node, root []yaml.Node, env Environment) ([]yaml.Node, bool, bool, []string, string) {
	spliced := []yaml.Node{}
	process := true
	keyName := orig.KeyName()
	replaced := orig.ReplaceFlag()
	redirectPath := orig.RedirectPath()

	for _, val := range root {
		if val == nil {
			continue
		}

		inlineNode, ok := yaml.UnresolvedListEntryMerge(val)
		if ok {
			debug.Debug("*** %+v\n", inlineNode.Value())
			_, initial := inlineNode.Value().(string)
			result := flow(inlineNode, env, false)
			if result.KeyName() != "" {
				keyName = result.KeyName()
			}
			debug.Debug("=== (%s)%+v\n", keyName, result)
			_, ok := result.Value().(dynaml.Expression)
			if ok {
				if simpleMergeCompatibilityCheck(initial, inlineNode) {
					continue
				}
				newMap := make(map[string]yaml.Node)
				newMap["<<"] = result
				val = yaml.SubstituteNode(newMap, orig)
				process = false
			} else {
				inline, ok := result.Value().([]yaml.Node)

				if ok {
					inlineNew := newEntries(inline, root, keyName)
					replaced = result.ReplaceFlag()
					redirectPath = result.RedirectPath()
					if replaced {
						spliced = inlineNew
						process = false
						break
					} else {
						spliced = append(spliced, inlineNew...)
					}
				}
				continue
			}
		}

		val, newKey := ProcessKeyTag(val)
		if newKey != "" {
			keyName = newKey
		}
		spliced = append(spliced, val)
	}

	debug.Debug("--> %+v  proc=%v replaced=%v redirect=%v key=%s\n", spliced, process, replaced, redirectPath, keyName)
	return spliced, process, replaced, redirectPath, keyName
}
Esempio n. 2
0
func flow(root yaml.Node, env Environment, shouldOverride bool) yaml.Node {
	if root == nil {
		return root
	}

	replace := root.ReplaceFlag()
	redirect := root.RedirectPath()
	preferred := root.Preferred()
	merged := root.Merged()
	keyName := root.KeyName()

	if redirect != nil {
		env = env.RedirectOverwrite(redirect)
	}

	if !replace {
		switch val := root.Value().(type) {
		case map[string]yaml.Node:
			return flowMap(root, env)

		case []yaml.Node:
			return flowList(root, env)

		case dynaml.Expression:
			debug.Debug("??? eval %+v\n", val)
			result, info, ok := val.Evaluate(env)
			if !ok {
				root = yaml.IssueNode(root, info.Issue)
				debug.Debug("??? failed ---> KEEP\n")
				if !shouldOverride {
					return root
				}
				replace = replace || info.Replace
			} else {
				_, ok = result.Value().(string)
				if ok {
					// map result to potential expression
					result = flowString(result, env)
				}
				_, expr := result.Value().(dynaml.Expression)

				// preserve accumulated node attributes
				if preferred || info.Preferred {
					debug.Debug("   PREFERRED")
					result = yaml.PreferredNode(result)
				}

				if info.KeyName != "" {
					keyName = info.KeyName
					result = yaml.KeyNameNode(result, keyName)
				}
				if len(info.RedirectPath) > 0 {
					redirect = info.RedirectPath
				}
				if len(redirect) > 0 {
					debug.Debug("   REDIRECT -> %v\n", redirect)
					result = yaml.RedirectNode(result.Value(), result, redirect)
				}

				if replace || info.Replace {
					debug.Debug("   REPLACE\n")
					result = yaml.ReplaceNode(result.Value(), result, redirect)
				} else {
					if merged || info.Merged {
						debug.Debug("   MERGED\n")
						result = yaml.MergedNode(result)
					}
				}
				if expr || result.Merged() || !shouldOverride || result.Preferred() {
					debug.Debug("   prefer expression over override")
					debug.Debug("??? ---> %+v\n", result)
					return result
				}
				debug.Debug("???   try override")
				replace = result.ReplaceFlag()
				root = result
			}

		case string:
			result := flowString(root, env)
			if result != nil {
				_, ok := result.Value().(dynaml.Expression)
				if ok {
					// analyse expression before overriding
					return result
				}
			}
		}
	}

	if !merged && shouldOverride {
		debug.Debug("/// lookup stub %v -> %v\n", env.Path, env.StubPath)
		overridden, found := env.FindInStubs(env.StubPath)
		if found {
			root = overridden
			if keyName != "" {
				root = yaml.KeyNameNode(root, keyName)
			}
			if replace {
				return yaml.ReplaceNode(root.Value(), root, redirect)
			}
			if redirect != nil {
				return yaml.RedirectNode(root.Value(), root, redirect)
			}
			if merged {
				return yaml.MergedNode(root)
			}
		}
	}

	return root
}
Esempio n. 3
0
func flowMap(root yaml.Node, env Environment) yaml.Node {
	processed := true
	rootMap := root.Value().(map[string]yaml.Node)

	env = env.WithScope(rootMap)

	redirect := root.RedirectPath()
	replace := root.ReplaceFlag()
	newMap := make(map[string]yaml.Node)

	sortedKeys := getSortedKeys(rootMap)

	debug.Debug("HANDLE MAP %v\n", env.Path)

	// iteration order matters for the "<<" operator, it must be the first key in the map that is handled
	for i := range sortedKeys {
		key := sortedKeys[i]
		val := rootMap[key]

		if key == "<<" {
			_, initial := val.Value().(string)
			base := flow(val, env, false)
			_, ok := base.Value().(dynaml.Expression)
			if ok {
				if simpleMergeCompatibilityCheck(initial, base) {
					continue
				}
				val = base
				processed = false
			} else {
				baseMap, ok := base.Value().(map[string]yaml.Node)
				if base != nil && base.RedirectPath() != nil {
					redirect = base.RedirectPath()
					env = env.RedirectOverwrite(redirect)
				}
				if ok {
					for k, v := range baseMap {
						newMap[k] = v
					}
				}
				replace = base.ReplaceFlag()
				if replace {
					break
				}
				continue
			}
		} else {
			if processed {
				val = flow(val, env.WithPath(key), true)
			}
		}

		debug.Debug("MAP (%s)%s\n", val.KeyName(), key)
		newMap[key] = val
	}

	debug.Debug("MAP DONE %v\n", env.Path)
	if replace {
		return yaml.ReplaceNode(newMap, root, redirect)
	}
	return yaml.RedirectNode(newMap, root, redirect)
}