it works! wip

This commit is contained in:
Mike Farah 2020-01-11 18:52:15 +11:00
parent 96955ffa9c
commit 74c7a4e027
7 changed files with 77 additions and 24 deletions

View File

@ -94,6 +94,15 @@ func TestReadCmd(t *testing.T) {
test.AssertResult(t, "2", result.Output)
}
func TestReadWithAdvancedFilterCmd(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "read examples/sample.yaml b.e(name == sam).value")
if result.Error != nil {
t.Error(result.Error)
}
test.AssertResult(t, "4", result.Output)
}
func TestReadWithKeyAndValueCmd(t *testing.T) {
cmd := getRootCommand()
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.c")

View File

@ -1,9 +1,4 @@
a: true
b:
c: 2
d: [3, 4, 5]
e:
- name: fred
value: 3
- name: sam
value: 4
- name: fred
value: 3
- name: sam
value: 4

View File

@ -2,6 +2,7 @@ package yqlib
import (
"strconv"
"strings"
errors "github.com/pkg/errors"
yaml "gopkg.in/yaml.v3"
@ -69,7 +70,7 @@ func (n *navigator) recurse(value *yaml.Node, head string, tail []string, pathSt
return n.recurseMap(value, head, tail, pathStack)
case yaml.SequenceNode:
log.Debug("its a sequence of %v things!", len(value.Content))
if head == "*" || head == "**" {
if head == "*" || head == "**" || strings.Contains(head, "==") {
return n.splatArray(value, head, tail, pathStack)
} else if head == "+" {
return n.appendArray(value, head, tail, pathStack)
@ -96,7 +97,7 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, pat
newPathStack := append(pathStack, contents[indexInMap].Value)
log.Debug("appended %v", contents[indexInMap].Value)
n.navigationStrategy.DebugVisitedNodes()
log.Debug("should I traverse? %v, %v", head, pathStackToString(newPathStack))
log.Debug("should I traverse? head: %v, path: %v", head, pathStackToString(newPathStack))
DebugNode(value)
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) {
log.Debug("recurseMap: Going to traverse")
@ -214,9 +215,13 @@ func (n *navigator) splatArray(value *yaml.Node, head string, tail []string, pat
log.Debug("processing")
DebugNode(childValue)
childValue = n.getOrReplace(childValue, guessKind(head, tail, childValue.Kind))
var err = n.doTraverse(childValue, head, tail, append(pathStack, index))
if err != nil {
return err
newPathStack := append(pathStack, index)
if n.navigationStrategy.ShouldTraverse(NewNodeContext(childValue, head, tail, newPathStack), childValue.Value) {
var err = n.doTraverse(childValue, head, tail, newPathStack)
if err != nil {
return err
}
}
}
return nil

View File

@ -0,0 +1,20 @@
package yqlib
func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy {
return &NavigationStrategyImpl{
visitedNodes: []*NodeContext{},
followAlias: func(nodeContext NodeContext) bool {
return true
},
autoCreateMap: func(nodeContext NodeContext) bool {
return false
},
visit: func(nodeContext NodeContext) error {
return nil
},
shouldVisitExtraFn: func(nodeContext NodeContext) bool {
log.Debug("does %v match %v ? %v", nodeContext.Node.Value, value, nodeContext.Node.Value == value)
return nodeContext.Node.Value == value
},
}
}

View File

@ -108,10 +108,10 @@ func NewYqLib() YqLib {
func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
var paths = l.parser.ParsePath(path)
NavigationStrategy := ReadNavigationStrategy()
navigator := NewDataNavigator(NavigationStrategy)
navigationStrategy := ReadNavigationStrategy()
navigator := NewDataNavigator(navigationStrategy)
error := navigator.Traverse(rootNode, paths)
return NavigationStrategy.GetVisitedNodes(), error
return navigationStrategy.GetVisitedNodes(), error
}

View File

@ -39,10 +39,11 @@ type NavigationStrategy interface {
}
type NavigationStrategyImpl struct {
followAlias func(nodeContext NodeContext) bool
autoCreateMap func(nodeContext NodeContext) bool
visit func(nodeContext NodeContext) error
visitedNodes []*NodeContext
followAlias func(nodeContext NodeContext) bool
autoCreateMap func(nodeContext NodeContext) bool
visit func(nodeContext NodeContext) error
shouldVisitExtraFn func(nodeContext NodeContext) bool
visitedNodes []*NodeContext
}
func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
@ -90,8 +91,8 @@ func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
parser := NewPathParser()
// only visit aliases if its an exact match
return (nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" &&
parser.MatchesNextPathElement(nodeContext, nodeKey))
return ((nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" &&
parser.MatchesNextPathElement(nodeContext, nodeKey))) && (ns.shouldVisitExtraFn == nil || ns.shouldVisitExtraFn(nodeContext))
}
func (ns *NavigationStrategyImpl) Visit(nodeContext NodeContext) error {

View File

@ -28,6 +28,26 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
if head == "**" || head == "*" {
return true
}
if strings.Contains(head, "==") {
log.Debug("ooh deep recursion time")
result := strings.SplitN(head, "==", 2)
path := strings.TrimSpace(result[0])
value := strings.TrimSpace(result[1])
log.Debug("path %v", path)
log.Debug("value %v", value)
DebugNode(nodeContext.Node)
navigationStrategy := FilterMatchingNodesNavigationStrategy(value)
navigator := NewDataNavigator(navigationStrategy)
err := navigator.Traverse(nodeContext.Node, p.ParsePath(path))
if err != nil {
log.Error(err.Error())
}
//crap handle error
log.Debug("done deep recursing, found %v matches", len(navigationStrategy.GetVisitedNodes()))
return len(navigationStrategy.GetVisitedNodes()) > 0
}
if head == "+" {
log.Debug("head is +, nodeKey is %v", nodeKey)
var _, err = strconv.ParseInt(nodeKey, 10, 64) // nolint
@ -66,9 +86,12 @@ func (p *pathParser) nextYamlPath(path string) (pathElement string, remaining st
case '"':
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
return p.search(path[1:], []uint8{'"'}, true)
case '(':
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
return p.search(path[1:], []uint8{')'}, true)
default:
// e.g "a.blah.cat" -> return "a" and "blah.cat"
return p.search(path[0:], []uint8{'.', '['}, false)
return p.search(path[0:], []uint8{'.', '[', '"', '('}, false)
}
}