mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 05:38:04 +00:00
it works! wip
This commit is contained in:
parent
96955ffa9c
commit
74c7a4e027
@ -94,6 +94,15 @@ func TestReadCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, "2", result.Output)
|
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) {
|
func TestReadWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.c")
|
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.c")
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
a: true
|
- name: fred
|
||||||
b:
|
value: 3
|
||||||
c: 2
|
- name: sam
|
||||||
d: [3, 4, 5]
|
value: 4
|
||||||
e:
|
|
||||||
- name: fred
|
|
||||||
value: 3
|
|
||||||
- name: sam
|
|
||||||
value: 4
|
|
@ -2,6 +2,7 @@ package yqlib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
errors "github.com/pkg/errors"
|
errors "github.com/pkg/errors"
|
||||||
yaml "gopkg.in/yaml.v3"
|
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)
|
return n.recurseMap(value, head, tail, pathStack)
|
||||||
case yaml.SequenceNode:
|
case yaml.SequenceNode:
|
||||||
log.Debug("its a sequence of %v things!", len(value.Content))
|
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)
|
return n.splatArray(value, head, tail, pathStack)
|
||||||
} else if head == "+" {
|
} else if head == "+" {
|
||||||
return n.appendArray(value, head, tail, pathStack)
|
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)
|
newPathStack := append(pathStack, contents[indexInMap].Value)
|
||||||
log.Debug("appended %v", contents[indexInMap].Value)
|
log.Debug("appended %v", contents[indexInMap].Value)
|
||||||
n.navigationStrategy.DebugVisitedNodes()
|
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)
|
DebugNode(value)
|
||||||
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) {
|
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) {
|
||||||
log.Debug("recurseMap: Going to traverse")
|
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")
|
log.Debug("processing")
|
||||||
DebugNode(childValue)
|
DebugNode(childValue)
|
||||||
childValue = n.getOrReplace(childValue, guessKind(head, tail, childValue.Kind))
|
childValue = n.getOrReplace(childValue, guessKind(head, tail, childValue.Kind))
|
||||||
var err = n.doTraverse(childValue, head, tail, append(pathStack, index))
|
|
||||||
if err != nil {
|
newPathStack := append(pathStack, index)
|
||||||
return err
|
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
|
return nil
|
||||||
|
20
pkg/yqlib/filter_matching_node_navigation_strategy.go
Normal file
20
pkg/yqlib/filter_matching_node_navigation_strategy.go
Normal 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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -108,10 +108,10 @@ func NewYqLib() YqLib {
|
|||||||
|
|
||||||
func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
|
func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
|
||||||
var paths = l.parser.ParsePath(path)
|
var paths = l.parser.ParsePath(path)
|
||||||
NavigationStrategy := ReadNavigationStrategy()
|
navigationStrategy := ReadNavigationStrategy()
|
||||||
navigator := NewDataNavigator(NavigationStrategy)
|
navigator := NewDataNavigator(navigationStrategy)
|
||||||
error := navigator.Traverse(rootNode, paths)
|
error := navigator.Traverse(rootNode, paths)
|
||||||
return NavigationStrategy.GetVisitedNodes(), error
|
return navigationStrategy.GetVisitedNodes(), error
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,10 +39,11 @@ type NavigationStrategy interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type NavigationStrategyImpl struct {
|
type NavigationStrategyImpl struct {
|
||||||
followAlias func(nodeContext NodeContext) bool
|
followAlias func(nodeContext NodeContext) bool
|
||||||
autoCreateMap func(nodeContext NodeContext) bool
|
autoCreateMap func(nodeContext NodeContext) bool
|
||||||
visit func(nodeContext NodeContext) error
|
visit func(nodeContext NodeContext) error
|
||||||
visitedNodes []*NodeContext
|
shouldVisitExtraFn func(nodeContext NodeContext) bool
|
||||||
|
visitedNodes []*NodeContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
|
func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
|
||||||
@ -90,8 +91,8 @@ func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
|
|||||||
parser := NewPathParser()
|
parser := NewPathParser()
|
||||||
|
|
||||||
// only visit aliases if its an exact match
|
// only visit aliases if its an exact match
|
||||||
return (nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" &&
|
return ((nodeKey == "<<" && nodeContext.Head == "<<") || (nodeKey != "<<" &&
|
||||||
parser.MatchesNextPathElement(nodeContext, nodeKey))
|
parser.MatchesNextPathElement(nodeContext, nodeKey))) && (ns.shouldVisitExtraFn == nil || ns.shouldVisitExtraFn(nodeContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) Visit(nodeContext NodeContext) error {
|
func (ns *NavigationStrategyImpl) Visit(nodeContext NodeContext) error {
|
||||||
|
@ -28,6 +28,26 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
|
|||||||
if head == "**" || head == "*" {
|
if head == "**" || head == "*" {
|
||||||
return true
|
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 == "+" {
|
if head == "+" {
|
||||||
log.Debug("head is +, nodeKey is %v", nodeKey)
|
log.Debug("head is +, nodeKey is %v", nodeKey)
|
||||||
var _, err = strconv.ParseInt(nodeKey, 10, 64) // nolint
|
var _, err = strconv.ParseInt(nodeKey, 10, 64) // nolint
|
||||||
@ -66,9 +86,12 @@ func (p *pathParser) nextYamlPath(path string) (pathElement string, remaining st
|
|||||||
case '"':
|
case '"':
|
||||||
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
|
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
|
||||||
return p.search(path[1:], []uint8{'"'}, true)
|
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:
|
default:
|
||||||
// e.g "a.blah.cat" -> return "a" and "blah.cat"
|
// e.g "a.blah.cat" -> return "a" and "blah.cat"
|
||||||
return p.search(path[0:], []uint8{'.', '['}, false)
|
return p.search(path[0:], []uint8{'.', '[', '"', '('}, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user