Handle simple aliases

This commit is contained in:
Mike Farah 2019-12-16 20:38:55 +11:00
parent d7392f7b58
commit 290579ac7f
4 changed files with 42 additions and 13 deletions

View File

@ -112,6 +112,15 @@ func TestReadCmd(t *testing.T) {
// test.AssertResult(t, "21\n", result.Output) // 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) { 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")

View File

@ -0,0 +1,4 @@
foo: &foo
a: 1
foobar: *foo

View File

@ -18,14 +18,16 @@ type DataNavigator interface {
} }
type navigator struct { type navigator struct {
log *logging.Logger log *logging.Logger
followAliases bool
} }
type VisitorFn func(*yaml.Node) error type VisitorFn func(*yaml.Node) error
func NewDataNavigator(l *logging.Logger) DataNavigator { func NewDataNavigator(l *logging.Logger, followAliases bool) DataNavigator {
return &navigator{ 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) { if tail[0] == "*" && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
return guess return guess
} }
if guess == yaml.AliasNode {
n.log.Debug("guess was an alias, okey doke.")
return guess
}
return yaml.MappingNode 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 { func (n *navigator) recurse(value *yaml.Node, head string, tail []string, visitor VisitorFn) error {
n.log.Debug("recursing, processing %v", head)
switch value.Kind { switch value.Kind {
case yaml.MappingNode: case yaml.MappingNode:
n.log.Debug("its a map with %v entries", len(value.Content)/2) 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.appendArray(value, tail, visitor)
} }
return n.recurseArray(value, head, 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: default:
return nil 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. // so keys are in the even indexes, values in odd.
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", index, content.Value) n.log.Debug("index %v, checking %v", index, content.Value))
if n.matchesKey(key, content.Value) { if n.matchesKey(key, content.Value) {
errorVisiting := visit(index) errorVisiting := visit(index)
if errorVisiting != nil { if errorVisiting != nil {

View File

@ -28,37 +28,39 @@ type lib struct {
func NewYqLib(l *logging.Logger) YqLib { func NewYqLib(l *logging.Logger) YqLib {
return &lib{ return &lib{
navigator: NewDataNavigator(l), parser: NewPathParser(),
parser: NewPathParser(), log: l,
log: l,
} }
} }
func (l *lib) DebugNode(node *yaml.Node) { 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) { func (l *lib) Get(rootNode *yaml.Node, path string) (*yaml.Node, error) {
var paths = l.parser.ParsePath(path) 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 { func (l *lib) New(path string) yaml.Node {
var paths = l.parser.ParsePath(path) 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 return newNode
} }
func (l *lib) Update(rootNode *yaml.Node, updateCommand UpdateCommand) error { 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) l.log.Debugf("%v to %v", updateCommand.Command, updateCommand.Path)
switch updateCommand.Command { switch updateCommand.Command {
case "update": case "update":
var paths = l.parser.ParsePath(updateCommand.Path) var paths = l.parser.ParsePath(updateCommand.Path)
return l.navigator.Update(rootNode, paths, updateCommand.Value) return navigator.Update(rootNode, paths, updateCommand.Value)
case "delete": case "delete":
var paths = l.parser.ParsePath(updateCommand.Path) var paths = l.parser.ParsePath(updateCommand.Path)
return l.navigator.Delete(rootNode, paths) return navigator.Delete(rootNode, paths)
default: default:
return fmt.Errorf("Unknown command %v", updateCommand.Command) return fmt.Errorf("Unknown command %v", updateCommand.Command)
} }