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)
|
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) {
|
func TestReadWithKeyCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p k examples/sample.yaml b.c")
|
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 {
|
if result.Error == nil {
|
||||||
t.Error("Expected command to fail due to missing arg")
|
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())
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadCmd_ArrayYaml_Splat_ErrorBadPath(t *testing.T) {
|
func TestReadCmd_ArrayYaml_Splat_ErrorBadPath(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read examples/array.yaml [*].roles[x]")
|
result := test.RunCmd(cmd, "read examples/array.yaml [*].roles[x]")
|
||||||
expectedOutput := ``
|
if result.Error == nil {
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
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) {
|
func TestReadCmd_Error(t *testing.T) {
|
||||||
@ -469,8 +484,8 @@ func TestReadCmd_ErrorBadPath(t *testing.T) {
|
|||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, fmt.Sprintf("read %s b.d.*.[x]", filename))
|
result := test.RunCmd(cmd, fmt.Sprintf("read %s b.d.*.[x]", filename))
|
||||||
expectedOutput := ``
|
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.Output)
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadCmd_Verbose(t *testing.T) {
|
func TestReadCmd_Verbose(t *testing.T) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
errors "github.com/pkg/errors"
|
||||||
yaml "gopkg.in/yaml.v3"
|
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 {
|
func (n *navigator) doTraverse(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||||
log.Debug("head %v", head)
|
log.Debug("head %v", head)
|
||||||
DebugNode(value)
|
DebugNode(value)
|
||||||
|
var errorDeepSplatting error
|
||||||
if head == "**" && value.Kind != yaml.ScalarNode {
|
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 {
|
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)
|
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||||
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!, %v", len(value.Content))
|
log.Debug("its a sequence of %v things!", len(value.Content))
|
||||||
if head == "*" || head == "**" {
|
if head == "*" || 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, tail, pathStack)
|
return n.appendArray(value, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
return n.recurseArray(value, head, tail, pathStack)
|
return n.recurseArray(value, head, tail, pathStack)
|
||||||
case yaml.AliasNode:
|
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 {
|
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) == true {
|
||||||
log.Debug("recurseMap: Going to traverse")
|
log.Debug("recurseMap: Going to traverse")
|
||||||
traversedEntry = true
|
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)
|
errorTraversing := n.doTraverse(contents[indexInMap+1], head, tail, newPathStack)
|
||||||
log.Debug("recurseMap: Finished traversing")
|
log.Debug("recurseMap: Finished traversing")
|
||||||
n.navigationStrategy.DebugVisitedNodes()
|
n.navigationStrategy.DebugVisitedNodes()
|
||||||
@ -109,13 +116,13 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []string, pat
|
|||||||
return errorVisiting
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mapEntryKey := yaml.Node{Value: head, Kind: yaml.ScalarNode}
|
mapEntryKey := yaml.Node{Value: head, Kind: yaml.ScalarNode}
|
||||||
value.Content = append(value.Content, &mapEntryKey)
|
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)
|
value.Content = append(value.Content, &mapEntryValue)
|
||||||
log.Debug("adding new node %v", head)
|
log.Debug("adding new node %v", head)
|
||||||
return n.doTraverse(&mapEntryValue, head, tail, append(pathStack, 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 {
|
for index, childValue := range value.Content {
|
||||||
log.Debug("processing")
|
log.Debug("processing")
|
||||||
DebugNode(childValue)
|
DebugNode(childValue)
|
||||||
// head = fmt.Sprintf("%v", index)
|
childValue = n.getOrReplace(childValue, guessKind(head, tail, childValue.Kind))
|
||||||
childValue = n.getOrReplace(childValue, guessKind(tail, childValue.Kind))
|
|
||||||
var err = n.doTraverse(childValue, head, tail, append(pathStack, index))
|
var err = n.doTraverse(childValue, head, tail, append(pathStack, index))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -216,25 +222,22 @@ func (n *navigator) splatArray(value *yaml.Node, head string, tail []string, pat
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *navigator) appendArray(value *yaml.Node, tail []string, pathStack []interface{}) error {
|
func (n *navigator) appendArray(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||||
var newNode = yaml.Node{Kind: guessKind(tail, 0)}
|
var newNode = yaml.Node{Kind: guessKind(head, tail, 0)}
|
||||||
value.Content = append(value.Content, &newNode)
|
value.Content = append(value.Content, &newNode)
|
||||||
log.Debug("appending a new node, %v", value.Content)
|
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))
|
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 {
|
func (n *navigator) recurseArray(value *yaml.Node, head string, tail []string, pathStack []interface{}) error {
|
||||||
var index, err = strconv.ParseInt(head, 10, 64) // nolint
|
var index, err = strconv.ParseInt(head, 10, 64) // nolint
|
||||||
if err != nil {
|
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)) {
|
if index >= int64(len(value.Content)) {
|
||||||
return nil
|
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))
|
return n.doTraverse(value.Content[index], head, tail, append(pathStack, index))
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func PathStackToString(pathStack []interface{}) string {
|
|||||||
return sb.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)
|
log.Debug("tail %v", tail)
|
||||||
if len(tail) == 0 && guess == 0 {
|
if len(tail) == 0 && guess == 0 {
|
||||||
log.Debug("end of path, must be a scalar")
|
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 {
|
if tail[0] == "+" || errorParsingInt == nil {
|
||||||
return yaml.SequenceNode
|
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
|
return guess
|
||||||
}
|
}
|
||||||
if guess == yaml.AliasNode {
|
if guess == yaml.AliasNode {
|
||||||
@ -69,8 +69,8 @@ func guessKind(tail []string, guess yaml.Kind) yaml.Kind {
|
|||||||
return guess
|
return guess
|
||||||
}
|
}
|
||||||
log.Debug("forcing a mapping node")
|
log.Debug("forcing a mapping node")
|
||||||
log.Debug("yaml.SequenceNode ?", guess == yaml.SequenceNode)
|
log.Debug("yaml.SequenceNode %v", guess == yaml.SequenceNode)
|
||||||
log.Debug("yaml.ScalarNode ?", guess == yaml.ScalarNode)
|
log.Debug("yaml.ScalarNode %v", guess == yaml.ScalarNode)
|
||||||
return yaml.MappingNode
|
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 {
|
func (l *lib) New(path string) yaml.Node {
|
||||||
var paths = l.parser.ParsePath(path)
|
var paths = l.parser.ParsePath(path)
|
||||||
newNode := yaml.Node{Kind: guessKind(paths, 0)}
|
newNode := yaml.Node{Kind: guessKind("", paths, 0)}
|
||||||
return newNode
|
return newNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,12 +78,15 @@ func (ns *NavigationStrategyImpl) shouldVisit(nodeContext NodeContext) bool {
|
|||||||
if len(pathStack) == 0 {
|
if len(pathStack) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
log.Debug("tail len %v", len(nodeContext.Tail))
|
||||||
|
// SOMETHING HERE!
|
||||||
|
|
||||||
if ns.alreadyVisited(pathStack) || len(nodeContext.Tail) != 0 {
|
if ns.alreadyVisited(pathStack) || len(nodeContext.Tail) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeKey := fmt.Sprintf("%v", pathStack[len(pathStack)-1])
|
nodeKey := fmt.Sprintf("%v", pathStack[len(pathStack)-1])
|
||||||
|
log.Debug("nodeKey: %v, nodeContext.Head: %v", nodeKey, nodeContext.Head)
|
||||||
parser := NewPathParser()
|
parser := NewPathParser()
|
||||||
|
|
||||||
// only visit aliases if its an exact match
|
// only visit aliases if its an exact match
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +28,13 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
|
|||||||
if head == "**" || head == "*" {
|
if head == "**" || head == "*" {
|
||||||
return true
|
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, "*")
|
var prefixMatch = strings.TrimSuffix(head, "*")
|
||||||
if prefixMatch != head {
|
if prefixMatch != head {
|
||||||
log.Debug("prefix match, %v", strings.HasPrefix(nodeKey, prefixMatch))
|
log.Debug("prefix match, %v", strings.HasPrefix(nodeKey, prefixMatch))
|
||||||
|
Loading…
Reference in New Issue
Block a user