Merge anchors - refactored

This commit is contained in:
Mike Farah 2019-12-22 15:33:54 +11:00
parent 949bf1c1d7
commit 865a55645c

View File

@ -248,13 +248,8 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, vis
// need to pass the node in, as it may be aliased // need to pass the node in, as it may be aliased
type mapVisitorFn func([]*yaml.Node, int) error type mapVisitorFn func([]*yaml.Node, int) error
func (n *navigator) visitMatchingEntries(contents []*yaml.Node, key string, visit mapVisitorFn) (bool, error) { func (n *navigator) visitDirectMatchingEntries(contents []*yaml.Node, key string, visit mapVisitorFn) (bool, error) {
visited := false visited := false
n.log.Debug("visitMatchingEntries %v in %v", key, contents)
// value.Content is a concatenated array of key, value,
// so keys are in the even indexes, values in odd.
// merge aliases are defined first, but we only want to traverse them
// if we don't find a match on this node first.
for index := 0; index < len(contents); index = index + 2 { for index := 0; index < len(contents); index = index + 2 {
content := contents[index] content := contents[index]
n.log.Debug("index %v, checking %v, %v", index, content.Value, content.Tag) n.log.Debug("index %v, checking %v, %v", index, content.Value, content.Tag)
@ -268,64 +263,69 @@ func (n *navigator) visitMatchingEntries(contents []*yaml.Node, key string, visi
visited = true visited = true
} }
} }
if visited == true || n.followAliases == false {
return visited, nil return visited, nil
} }
func (n *navigator) visitMatchingEntries(contents []*yaml.Node, key string, visit mapVisitorFn) (bool, error) {
n.log.Debug("visitMatchingEntries %v in %v", key, contents)
// value.Content is a concatenated array of key, value,
// so keys are in the even indexes, values in odd.
// merge aliases are defined first, but we only want to traverse them
// if we don't find a match directly on this node first.
visited, errorVisitedDirectEntries := n.visitDirectMatchingEntries(contents, key, visit)
if errorVisitedDirectEntries != nil || visited == true || n.followAliases == false {
return visited, errorVisitedDirectEntries
}
// didnt find a match, lets check the aliases. // didnt find a match, lets check the aliases.
return n.visitAliases(contents, key, visit)
}
func (n *navigator) visitAliases(contents []*yaml.Node, key string, visit mapVisitorFn) (bool, error) {
// merge aliases are defined first, but we only want to traverse them // merge aliases are defined first, but we only want to traverse them
// if we don't find a match on this node first. // if we don't find a match on this node first.
// traverse them backwards so that the last alias overrides the preceding. // traverse them backwards so that the last alias overrides the preceding.
// a node can either be
n.log.Debug("no entry in the map, checking for aliases") // an alias to one other node (e.g. <<: *blah)
// or a sequence of aliases (e.g. <<: [*blah, *foo])
n.log.Debug("checking for aliases")
for index := len(contents) - 2; index >= 0; index = index - 2 { for index := len(contents) - 2; index >= 0; index = index - 2 {
// content := contents[index]
n.log.Debug("looking for %v", yaml.AliasNode)
n.log.Debug("searching for aliases key %v kind %v", contents[index].Value, contents[index].Kind)
n.log.Debug("searching for aliases value %v kind %v", contents[index+1].Value, contents[index+1].Kind)
// only visit aliases if we didn't find a match in this object.
// NEED TO HANDLE A SEQUENCE OF ALIASES, and search each one.
// probably stop searching after we find a match, because overrides.
if contents[index+1].Kind == yaml.AliasNode { if contents[index+1].Kind == yaml.AliasNode {
valueNode := contents[index+1] valueNode := contents[index+1]
n.log.Debug("found an alias") n.log.Debug("found an alias")
n.DebugNode(contents[index]) n.DebugNode(contents[index])
n.DebugNode(valueNode) n.DebugNode(valueNode)
visitedAlias, errorInAlias := n.visitMatchingEntries(valueNode.Alias.Content, key, visit) visitedAlias, errorInAlias := n.visitMatchingEntries(valueNode.Alias.Content, key, visit)
if errorInAlias != nil { if visitedAlias == true || errorInAlias != nil {
return false, errorInAlias return visitedAlias, errorInAlias
}
if visitedAlias == true {
return true, nil
} }
} else if contents[index+1].Kind == yaml.SequenceNode { } else if contents[index+1].Kind == yaml.SequenceNode {
// could be an array of aliases...need to search this backwards too! // could be an array of aliases...need to search this backwards too!
possibleAliasArray := contents[index+1].Content visitedAliasSeq, errorVisitingAliasSeq := n.visitAliasSequence(contents[index+1].Content, key, visit)
if visitedAliasSeq == true || errorVisitingAliasSeq != nil {
return visitedAliasSeq, errorVisitingAliasSeq
}
}
}
n.log.Debug("nope no matching aliases found")
return false, nil
}
func (n *navigator) visitAliasSequence(possibleAliasArray []*yaml.Node, key string, visit mapVisitorFn) (bool, error) {
for aliasIndex := len(possibleAliasArray) - 1; aliasIndex >= 0; aliasIndex = aliasIndex - 1 { for aliasIndex := len(possibleAliasArray) - 1; aliasIndex >= 0; aliasIndex = aliasIndex - 1 {
child := possibleAliasArray[aliasIndex] child := possibleAliasArray[aliasIndex]
if child.Kind == yaml.AliasNode { if child.Kind == yaml.AliasNode {
n.log.Debug("found an alias") n.log.Debug("found an alias")
n.DebugNode(child) n.DebugNode(child)
visitedAlias, errorInAlias := n.visitMatchingEntries(child.Alias.Content, key, visit) visitedAlias, errorInAlias := n.visitMatchingEntries(child.Alias.Content, key, visit)
if errorInAlias != nil { if visitedAlias == true || errorInAlias != nil {
return false, errorInAlias return visitedAlias, errorInAlias
}
if visitedAlias == true {
return true, nil
} }
} }
} }
}
}
n.log.Debug("no aliases")
return false, nil return false, nil
} }