mirror of
https://github.com/mikefarah/yq.git
synced 2025-01-27 17:05:35 +00:00
Merge anchors - wip
This commit is contained in:
parent
19fe718cfb
commit
949bf1c1d7
@ -121,6 +121,51 @@ func TestReadAnchorsCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, "1\n", result.Output)
|
test.AssertResult(t, "1\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsOriginalCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read examples/merge-anchor.yaml foobar.a")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "original\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsOverrideCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read examples/merge-anchor.yaml foobar.thing")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "ice\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsListOriginalCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read examples/merge-anchor.yaml foobarList.a")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "original\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsListOverrideInListCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read examples/merge-anchor.yaml foobarList.thing")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "coconut\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsListOverrideCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read examples/merge-anchor.yaml foobarList.c")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "newbar\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadInvalidDocumentIndexCmd(t *testing.T) {
|
func TestReadInvalidDocumentIndexCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -df examples/sample.yaml b.c")
|
result := test.RunCmd(cmd, "read -df examples/sample.yaml b.c")
|
||||||
|
@ -4,12 +4,12 @@ foo: &foo
|
|||||||
|
|
||||||
bar: &bar
|
bar: &bar
|
||||||
b: 2
|
b: 2
|
||||||
|
thing: coconut
|
||||||
|
c: oldbar
|
||||||
|
|
||||||
|
foobarList:
|
||||||
overrideA:
|
|
||||||
<<: [*foo,*bar]
|
<<: [*foo,*bar]
|
||||||
a: vanilla
|
c: newbar
|
||||||
c: 3
|
|
||||||
|
|
||||||
foobar:
|
foobar:
|
||||||
<<: *foo
|
<<: *foo
|
@ -254,24 +254,11 @@ func (n *navigator) visitMatchingEntries(contents []*yaml.Node, key string, visi
|
|||||||
// value.Content is a concatenated array of key, value,
|
// value.Content is a concatenated array of key, value,
|
||||||
// so keys are in the even indexes, values in odd.
|
// so keys are in the even indexes, values in odd.
|
||||||
// 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 dont find a match on this node first.
|
// if we don't find a match on this node first.
|
||||||
for index := len(contents) - 2; index >= 0; 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)
|
||||||
|
|
||||||
// only visit aliases if we didn't find a match in this object.
|
|
||||||
if n.followAliases && !visited && contents[index+1].Kind == yaml.AliasNode {
|
|
||||||
valueNode := contents[index+1]
|
|
||||||
|
|
||||||
n.log.Debug("need to visit the alias too")
|
|
||||||
n.DebugNode(valueNode)
|
|
||||||
visitedAlias, errorInAlias := n.visitMatchingEntries(valueNode.Alias.Content, key, visit)
|
|
||||||
if errorInAlias != nil {
|
|
||||||
return false, errorInAlias
|
|
||||||
}
|
|
||||||
visited = visited || visitedAlias
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.matchesKey(key, content.Value) {
|
if n.matchesKey(key, content.Value) {
|
||||||
n.log.Debug("found a match! %v", content.Value)
|
n.log.Debug("found a match! %v", content.Value)
|
||||||
errorVisiting := visit(contents, index)
|
errorVisiting := visit(contents, index)
|
||||||
@ -281,7 +268,65 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// didnt find a match, lets check the aliases.
|
||||||
|
// merge aliases are defined first, but we only want to traverse them
|
||||||
|
// if we don't find a match on this node first.
|
||||||
|
// traverse them backwards so that the last alias overrides the preceding.
|
||||||
|
|
||||||
|
n.log.Debug("no entry in the map, checking for aliases")
|
||||||
|
|
||||||
|
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 {
|
||||||
|
valueNode := contents[index+1]
|
||||||
|
|
||||||
|
n.log.Debug("found an alias")
|
||||||
|
n.DebugNode(contents[index])
|
||||||
|
n.DebugNode(valueNode)
|
||||||
|
visitedAlias, errorInAlias := n.visitMatchingEntries(valueNode.Alias.Content, key, visit)
|
||||||
|
if errorInAlias != nil {
|
||||||
|
return false, errorInAlias
|
||||||
|
}
|
||||||
|
if visitedAlias == true {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
} else if contents[index+1].Kind == yaml.SequenceNode {
|
||||||
|
// could be an array of aliases...need to search this backwards too!
|
||||||
|
possibleAliasArray := contents[index+1].Content
|
||||||
|
for aliasIndex := len(possibleAliasArray) - 1; aliasIndex >= 0; aliasIndex = aliasIndex - 1 {
|
||||||
|
child := possibleAliasArray[aliasIndex]
|
||||||
|
if child.Kind == yaml.AliasNode {
|
||||||
|
n.log.Debug("found an alias")
|
||||||
|
n.DebugNode(child)
|
||||||
|
visitedAlias, errorInAlias := n.visitMatchingEntries(child.Alias.Content, key, visit)
|
||||||
|
if errorInAlias != nil {
|
||||||
|
return false, errorInAlias
|
||||||
|
}
|
||||||
|
if visitedAlias == true {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
n.log.Debug("no aliases")
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *navigator) matchesKey(key string, actual string) bool {
|
func (n *navigator) matchesKey(key string, actual string) bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user