mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-12 13:48:06 +00:00
wip;
This commit is contained in:
parent
4dbdd4a805
commit
625cfdac75
@ -130,6 +130,18 @@ b.e.[1].value: 4
|
||||
test.AssertResult(t, expectedOutput, result.Output)
|
||||
}
|
||||
|
||||
func TestReadDeepSplatWithSuffixCmd(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "read -p kv examples/sample.yaml b.**.name")
|
||||
if result.Error != nil {
|
||||
t.Error(result.Error)
|
||||
}
|
||||
expectedOutput := `b.e.[0].name: fred
|
||||
b.e.[1].name: sam
|
||||
`
|
||||
test.AssertResult(t, expectedOutput, result.Output)
|
||||
}
|
||||
|
||||
func TestReadWithKeyCmd(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "read -p k examples/sample.yaml b.c")
|
||||
@ -408,15 +420,18 @@ func TestReadCmd_ArrayYaml_ErrorBadPath(t *testing.T) {
|
||||
if result.Error == nil {
|
||||
t.Error("Expected command to fail due to missing arg")
|
||||
}
|
||||
expectedOutput := `Error reading path in document index 0: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
expectedOutput := `Error reading path in document index 0: Error parsing array index 'x' for '': strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
}
|
||||
|
||||
func TestReadCmd_ArrayYaml_Splat_ErrorBadPath(t *testing.T) {
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, "read examples/array.yaml [*].roles[x]")
|
||||
expectedOutput := ``
|
||||
test.AssertResult(t, expectedOutput, result.Output)
|
||||
if result.Error == nil {
|
||||
t.Error("Expected command to fail due to missing arg")
|
||||
}
|
||||
expectedOutput := `Error reading path in document index 0: Error parsing array index 'x' for '[0].roles': strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
}
|
||||
|
||||
func TestReadCmd_Error(t *testing.T) {
|
||||
@ -469,8 +484,8 @@ func TestReadCmd_ErrorBadPath(t *testing.T) {
|
||||
|
||||
cmd := getRootCommand()
|
||||
result := test.RunCmd(cmd, fmt.Sprintf("read %s b.d.*.[x]", filename))
|
||||
expectedOutput := ``
|
||||
test.AssertResult(t, expectedOutput, result.Output)
|
||||
expectedOutput := `Error reading path in document index 0: Error parsing array index 'x' for 'b.d.e': strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||
}
|
||||
|
||||
func TestReadCmd_Verbose(t *testing.T) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
errors "github.com/pkg/errors"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@ -34,8 +34,15 @@ func (n *navigator) Traverse(value *yaml.Node, path []string) error {
|
||||
func (n *navigator) doTraverse(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||
log.Debug("head %v", head)
|
||||
DebugNode(value)
|
||||
var errorDeepSplatting error
|
||||
if head == "**" && value.Kind != yaml.ScalarNode {
|
||||
return n.recurse(value, head, tail, pathStack)
|
||||
errorDeepSplatting = n.recurse(value, head, tail, pathStack)
|
||||
// ignore errors here, we are deep splatting so we may accidently give a string key
|
||||
// to an array sequence
|
||||
if len(tail) > 0 {
|
||||
n.recurse(value, tail[0], tail[1:], pathStack)
|
||||
}
|
||||
return errorDeepSplatting
|
||||
}
|
||||
|
||||
if len(tail) > 0 {
|
||||
@ -61,11 +68,11 @@ func (n *navigator) recurse(value *yaml.Node, head string, tail []string, pathSt
|
||||
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||
return n.recurseMap(value, head, tail, pathStack)
|
||||
case yaml.SequenceNode:
|
||||
log.Debug("its a sequence of %v things!, %v", len(value.Content))
|
||||
log.Debug("its a sequence of %v things!", len(value.Content))
|
||||
if head == "*" || head == "**" {
|
||||
return n.splatArray(value, head, tail, pathStack)
|
||||
} else if head == "+" {
|
||||
return n.appendArray(value, tail, pathStack)
|
||||
return n.appendArray(value, head, tail, pathStack)
|
||||
}
|
||||
return n.recurseArray(value, head, tail, pathStack)
|
||||
case yaml.AliasNode:
|
||||
@ -94,7 +101,7 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, pat
|
||||
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) == true {
|
||||
log.Debug("recurseMap: Going to traverse")
|
||||
traversedEntry = true
|
||||
contents[indexInMap+1] = n.getOrReplace(contents[indexInMap+1], guessKind(tail, contents[indexInMap+1].Kind))
|
||||
// contents[indexInMap+1] = n.getOrReplace(contents[indexInMap+1], guessKind(head, tail, contents[indexInMap+1].Kind))
|
||||
errorTraversing := n.doTraverse(contents[indexInMap+1], head, tail, newPathStack)
|
||||
log.Debug("recurseMap: Finished traversing")
|
||||
n.navigationStrategy.DebugVisitedNodes()
|
||||
@ -109,13 +116,13 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, pat
|
||||
return errorVisiting
|
||||
}
|
||||
|
||||
if traversedEntry == true || head == "*" || n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) == false {
|
||||
if traversedEntry == true || head == "*" || head == "**" || n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) == false {
|
||||
return nil
|
||||
}
|
||||
|
||||
mapEntryKey := yaml.Node{Value: head, Kind: yaml.ScalarNode}
|
||||
value.Content = append(value.Content, &mapEntryKey)
|
||||
mapEntryValue := yaml.Node{Kind: guessKind(tail, 0)}
|
||||
mapEntryValue := yaml.Node{Kind: guessKind(head, tail, 0)}
|
||||
value.Content = append(value.Content, &mapEntryValue)
|
||||
log.Debug("adding new node %v", head)
|
||||
return n.doTraverse(&mapEntryValue, head, tail, append(pathStack, head))
|
||||
@ -206,8 +213,7 @@ func (n *navigator) splatArray(value *yaml.Node, head string, tail []string, pat
|
||||
for index, childValue := range value.Content {
|
||||
log.Debug("processing")
|
||||
DebugNode(childValue)
|
||||
// head = fmt.Sprintf("%v", index)
|
||||
childValue = n.getOrReplace(childValue, guessKind(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 {
|
||||
return err
|
||||
@ -216,25 +222,22 @@ func (n *navigator) splatArray(value *yaml.Node, head string, tail []string, pat
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *navigator) appendArray(value *yaml.Node, tail []string, pathStack []interface{}) error {
|
||||
var newNode = yaml.Node{Kind: guessKind(tail, 0)}
|
||||
func (n *navigator) appendArray(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||
var newNode = yaml.Node{Kind: guessKind(head, tail, 0)}
|
||||
value.Content = append(value.Content, &newNode)
|
||||
log.Debug("appending a new node, %v", value.Content)
|
||||
head := fmt.Sprintf("%v", len(value.Content)-1)
|
||||
return n.doTraverse(&newNode, head, tail, append(pathStack, len(value.Content)-1))
|
||||
}
|
||||
|
||||
func (n *navigator) recurseArray(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||
var index, err = strconv.ParseInt(head, 10, 64) // nolint
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrapf(err, "Error parsing array index '%v' for '%v'", head, PathStackToString(pathStack))
|
||||
}
|
||||
if index >= int64(len(value.Content)) {
|
||||
return nil
|
||||
}
|
||||
value.Content[index] = n.getOrReplace(value.Content[index], guessKind(tail, value.Content[index].Kind))
|
||||
value.Content[index] = n.getOrReplace(value.Content[index], guessKind(head, tail, value.Content[index].Kind))
|
||||
|
||||
// THERES SOMETHING WRONG HERE, ./yq read -p kv examples/sample.yaml b.e.1.*
|
||||
// THERES SOMETHING WRONG HERE, ./yq read -p kv examples/sample.yaml b.e.1.name
|
||||
return n.doTraverse(value.Content[index], head, tail, append(pathStack, index))
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ func PathStackToString(pathStack []interface{}) string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func guessKind(tail []string, guess yaml.Kind) yaml.Kind {
|
||||
func guessKind(head string, tail []string, guess yaml.Kind) yaml.Kind {
|
||||
log.Debug("tail %v", tail)
|
||||
if len(tail) == 0 && guess == 0 {
|
||||
log.Debug("end of path, must be a scalar")
|
||||
@ -61,7 +61,7 @@ func guessKind(tail []string, guess yaml.Kind) yaml.Kind {
|
||||
if tail[0] == "+" || errorParsingInt == nil {
|
||||
return yaml.SequenceNode
|
||||
}
|
||||
if (tail[0] == "*" || tail[0] == "**") && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
|
||||
if (tail[0] == "*" || tail[0] == "**" || head == "**") && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
|
||||
return guess
|
||||
}
|
||||
if guess == yaml.AliasNode {
|
||||
@ -69,8 +69,8 @@ func guessKind(tail []string, guess yaml.Kind) yaml.Kind {
|
||||
return guess
|
||||
}
|
||||
log.Debug("forcing a mapping node")
|
||||
log.Debug("yaml.SequenceNode ?", guess == yaml.SequenceNode)
|
||||
log.Debug("yaml.ScalarNode ?", guess == yaml.ScalarNode)
|
||||
log.Debug("yaml.SequenceNode %v", guess == yaml.SequenceNode)
|
||||
log.Debug("yaml.ScalarNode %v", guess == yaml.ScalarNode)
|
||||
return yaml.MappingNode
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
|
||||
|
||||
func (l *lib) New(path string) yaml.Node {
|
||||
var paths = l.parser.ParsePath(path)
|
||||
newNode := yaml.Node{Kind: guessKind(paths, 0)}
|
||||
newNode := yaml.Node{Kind: guessKind("", paths, 0)}
|
||||
return newNode
|
||||
}
|
||||
|
||||
|
@ -78,12 +78,15 @@ func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
|
||||
if len(pathStack) == 0 {
|
||||
return true
|
||||
}
|
||||
log.Debug("tail len %v", len(nodeContext.Tail))
|
||||
// SOMETHING HERE!
|
||||
|
||||
if ns.alreadyVisited(pathStack) || len(nodeContext.Tail) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
nodeKey := fmt.Sprintf("%v", pathStack[len(pathStack)-1])
|
||||
log.Debug("nodeKey: %v, nodeContext.Head: %v", nodeKey, nodeContext.Head)
|
||||
parser := NewPathParser()
|
||||
|
||||
// only visit aliases if its an exact match
|
||||
|
@ -1,6 +1,7 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -27,6 +28,13 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
|
||||
if head == "**" || head == "*" {
|
||||
return true
|
||||
}
|
||||
if head == "+" {
|
||||
log.Debug("head is +, nodeKey is %v", nodeKey)
|
||||
var _, err = strconv.ParseInt(nodeKey, 10, 64) // nolint
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
var prefixMatch = strings.TrimSuffix(head, "*")
|
||||
if prefixMatch != head {
|
||||
log.Debug("prefix match, %v", strings.HasPrefix(nodeKey, prefixMatch))
|
||||
|
Loading…
Reference in New Issue
Block a user