From 290579ac7fc21b9770dd35aa4634b23aa69aa183 Mon Sep 17 00:00:00 2001 From: Mike Farah Date: Mon, 16 Dec 2019 20:38:55 +1100 Subject: [PATCH] Handle simple aliases --- commands_test.go | 9 +++++++++ examples/simple-anchor.yaml | 4 ++++ pkg/yqlib/data_navigator.go | 22 ++++++++++++++++++---- pkg/yqlib/lib.go | 20 +++++++++++--------- 4 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 examples/simple-anchor.yaml diff --git a/commands_test.go b/commands_test.go index 58d58e14..fa497bfd 100644 --- a/commands_test.go +++ b/commands_test.go @@ -112,6 +112,15 @@ func TestReadCmd(t *testing.T) { // test.AssertResult(t, "21\n", result.Output) // } +func TestReadAnchorsCmd(t *testing.T) { + cmd := getRootCommand() + result := test.RunCmd(cmd, "read examples/simple-anchor.yaml foobar.a") + if result.Error != nil { + t.Error(result.Error) + } + test.AssertResult(t, "1\n", result.Output) +} + func TestReadInvalidDocumentIndexCmd(t *testing.T) { cmd := getRootCommand() result := test.RunCmd(cmd, "read -df examples/sample.yaml b.c") diff --git a/examples/simple-anchor.yaml b/examples/simple-anchor.yaml new file mode 100644 index 00000000..c83b2dcf --- /dev/null +++ b/examples/simple-anchor.yaml @@ -0,0 +1,4 @@ +foo: &foo + a: 1 + +foobar: *foo \ No newline at end of file diff --git a/pkg/yqlib/data_navigator.go b/pkg/yqlib/data_navigator.go index 1e2d03e0..e1493eb3 100644 --- a/pkg/yqlib/data_navigator.go +++ b/pkg/yqlib/data_navigator.go @@ -18,14 +18,16 @@ type DataNavigator interface { } type navigator struct { - log *logging.Logger + log *logging.Logger + followAliases bool } type VisitorFn func(*yaml.Node) error -func NewDataNavigator(l *logging.Logger) DataNavigator { +func NewDataNavigator(l *logging.Logger, followAliases bool) DataNavigator { return &navigator{ - log: l, + log: l, + followAliases: followAliases, } } @@ -147,6 +149,10 @@ func (n *navigator) GuessKind(tail []string, guess yaml.Kind) yaml.Kind { if tail[0] == "*" && (guess == yaml.SequenceNode || guess == yaml.MappingNode) { return guess } + if guess == yaml.AliasNode { + n.log.Debug("guess was an alias, okey doke.") + return guess + } return yaml.MappingNode } @@ -172,6 +178,7 @@ func (n *navigator) DebugNode(value *yaml.Node) { } func (n *navigator) recurse(value *yaml.Node, head string, tail []string, visitor VisitorFn) error { + n.log.Debug("recursing, processing %v", head) switch value.Kind { case yaml.MappingNode: n.log.Debug("its a map with %v entries", len(value.Content)/2) @@ -187,6 +194,13 @@ func (n *navigator) recurse(value *yaml.Node, head string, tail []string, visito return n.appendArray(value, tail, visitor) } return n.recurseArray(value, head, tail, visitor) + case yaml.AliasNode: + n.log.Debug("its an alias, followAliases: %v", n.followAliases) + n.DebugNode(value.Alias) + if n.followAliases == true { + return n.recurse(value.Alias, head, tail, visitor) + } + return nil default: return nil } @@ -237,7 +251,7 @@ func (n *navigator) visitMatchingEntries(contents []*yaml.Node, key string, visi // so keys are in the even indexes, values in odd. for index := 0; index < len(contents); index = index + 2 { content := contents[index] - n.log.Debug("index %v, checking %v", index, content.Value) + n.log.Debug("index %v, checking %v", index, content.Value)) if n.matchesKey(key, content.Value) { errorVisiting := visit(index) if errorVisiting != nil { diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 2415daea..eb3dc6db 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -28,37 +28,39 @@ type lib struct { func NewYqLib(l *logging.Logger) YqLib { return &lib{ - navigator: NewDataNavigator(l), - parser: NewPathParser(), - log: l, + parser: NewPathParser(), + log: l, } } func (l *lib) DebugNode(node *yaml.Node) { - l.navigator.DebugNode(node) + navigator := NewDataNavigator(l.log, false) + navigator.DebugNode(node) } func (l *lib) Get(rootNode *yaml.Node, path string) (*yaml.Node, error) { var paths = l.parser.ParsePath(path) - return l.navigator.Get(rootNode, paths) + navigator := NewDataNavigator(l.log, true) + return navigator.Get(rootNode, paths) } func (l *lib) New(path string) yaml.Node { var paths = l.parser.ParsePath(path) - newNode := yaml.Node{Kind: l.navigator.GuessKind(paths, 0)} + navigator := NewDataNavigator(l.log, false) + newNode := yaml.Node{Kind: navigator.GuessKind(paths, 0)} return newNode } func (l *lib) Update(rootNode *yaml.Node, updateCommand UpdateCommand) error { - // later - support other command types + navigator := NewDataNavigator(l.log, false) l.log.Debugf("%v to %v", updateCommand.Command, updateCommand.Path) switch updateCommand.Command { case "update": var paths = l.parser.ParsePath(updateCommand.Path) - return l.navigator.Update(rootNode, paths, updateCommand.Value) + return navigator.Update(rootNode, paths, updateCommand.Value) case "delete": var paths = l.parser.ParsePath(updateCommand.Path) - return l.navigator.Delete(rootNode, paths) + return navigator.Delete(rootNode, paths) default: return fmt.Errorf("Unknown command %v", updateCommand.Command) }