mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
Print path is more accurate than keys (i think)
This commit is contained in:
parent
854f5f0fc9
commit
728cbe991a
@ -1,11 +1,55 @@
|
|||||||
|
|
||||||
# New Features
|
# New Features
|
||||||
- Keeps comments and formatting (e.g. inline arrays)!
|
- Keeps yaml comments and formatting (string blocks are saved, number formatting is preserved, so it won't drop off trailing 0s for values like 0.10, which is important when that's a version entry )
|
||||||
- Handles anchors!
|
|
||||||
- Can specify yaml tags (e.g. !!int), quoting values no longer sufficient, need to specify the tag value instead.
|
|
||||||
- JSON output works for all commands! Yaml files with multiple documents are printed out as one JSON document per line.
|
|
||||||
|
|
||||||
# Update scripts file format has changed to be more powerful. Comments can be added, and delete commands have been introduced.
|
- Handles anchors! (doc link)
|
||||||
|
- Can specify yaml tags (e.g. !!int), quoting values no longer sufficient, need to specify the tag value instead.
|
||||||
|
- Can print out matching paths and values when splatting (doc link)
|
||||||
|
- JSON output works for all commands! Yaml files with multiple documents are printed out as one JSON document per line.
|
||||||
|
- Deep splat (**) to match arbitrary paths, (doc link)
|
||||||
|
|
||||||
|
|
||||||
|
# Breaking changes
|
||||||
|
|
||||||
|
## Update scripts file format has changed to be more powerful.
|
||||||
|
Comments can be added, and delete commands have been introduced.
|
||||||
|
|
||||||
|
## Reading and splatting, matching results are printed once per line.
|
||||||
|
e.g:
|
||||||
|
|
||||||
|
```json
|
||||||
|
parent:
|
||||||
|
childA:
|
||||||
|
no: matches here
|
||||||
|
childB:
|
||||||
|
there: matches
|
||||||
|
hi: no match
|
||||||
|
there2: also matches
|
||||||
|
```
|
||||||
|
|
||||||
|
yq r sample.yaml 'parent.*.there*'
|
||||||
|
|
||||||
|
old
|
||||||
|
```yaml
|
||||||
|
- null
|
||||||
|
- - matches
|
||||||
|
- also matches
|
||||||
|
```
|
||||||
|
|
||||||
|
new
|
||||||
|
```yaml
|
||||||
|
matches
|
||||||
|
also matches
|
||||||
|
```
|
||||||
|
|
||||||
|
and you can print the matching paths:
|
||||||
|
|
||||||
|
yq r --printMode pv sample.yaml 'parent.*.there*'
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
parent.childB.there: matches
|
||||||
|
parent.childB.there2: also matches
|
||||||
|
```
|
||||||
|
|
||||||
# Merge command
|
# Merge command
|
||||||
- New flag 'autocreates' missing entries in target by default, new flag to turn that off.
|
- New flag 'autocreates' missing entries in target by default, new flag to turn that off.
|
||||||
|
@ -96,7 +96,7 @@ func TestReadCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadWithKeyAndValueCmd(t *testing.T) {
|
func TestReadWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/sample.yaml b.c")
|
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.c")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ func TestReadWithKeyAndValueCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadArrayCmd(t *testing.T) {
|
func TestReadArrayCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/sample.yaml b.e.1.name")
|
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.e.1.name")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func TestReadArrayCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadDeepSplatCmd(t *testing.T) {
|
func TestReadDeepSplatCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/sample.yaml b.**")
|
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.**")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ b.e.[1].value: 4
|
|||||||
|
|
||||||
func TestReadDeepSplatWithSuffixCmd(t *testing.T) {
|
func TestReadDeepSplatWithSuffixCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/sample.yaml b.**.name")
|
result := test.RunCmd(cmd, "read -p pv examples/sample.yaml b.**.name")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ b.e.[1].name: sam
|
|||||||
|
|
||||||
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 p examples/sample.yaml b.c")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ func TestReadAnchorsCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadAnchorsWithKeyAndValueCmd(t *testing.T) {
|
func TestReadAnchorsWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/simple-anchor.yaml foobar.a")
|
result := test.RunCmd(cmd, "read -p pv examples/simple-anchor.yaml foobar.a")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ func TestReadMergeAnchorsOverrideCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadMergeAnchorsPrefixMatchCmd(t *testing.T) {
|
func TestReadMergeAnchorsPrefixMatchCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "r -p kv examples/merge-anchor.yaml foobar.th*")
|
result := test.RunCmd(cmd, "r -p pv examples/merge-anchor.yaml foobar.th*")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -271,7 +271,7 @@ func TestReadMultiCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadMultiWithKeyAndValueCmd(t *testing.T) {
|
func TestReadMultiWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p vk -d 1 examples/multiple_docs.yaml another.document")
|
result := test.RunCmd(cmd, "read -p vp -d 1 examples/multiple_docs.yaml another.document")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -292,7 +292,7 @@ third document`, result.Output)
|
|||||||
|
|
||||||
func TestReadMultiAllWithKeyAndValueCmd(t *testing.T) {
|
func TestReadMultiAllWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv -d* examples/multiple_docs.yaml commonKey")
|
result := test.RunCmd(cmd, "read -p pv -d* examples/multiple_docs.yaml commonKey")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -372,7 +372,7 @@ gather_facts: true
|
|||||||
|
|
||||||
func TestReadCmd_ArrayYaml_SplatWithKeyAndValueCmd(t *testing.T) {
|
func TestReadCmd_ArrayYaml_SplatWithKeyAndValueCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p kv examples/array.yaml [*]")
|
result := test.RunCmd(cmd, "read -p pv examples/array.yaml [*]")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -394,7 +394,7 @@ func TestReadCmd_ArrayYaml_SplatWithKeyAndValueCmd(t *testing.T) {
|
|||||||
|
|
||||||
func TestReadCmd_ArrayYaml_SplatWithKeyCmd(t *testing.T) {
|
func TestReadCmd_ArrayYaml_SplatWithKeyCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -p k examples/array.yaml [*]")
|
result := test.RunCmd(cmd, "read -p p examples/array.yaml [*]")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -494,7 +494,7 @@ func TestReadCmd_Verbose(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "2\n", result.Output)
|
test.AssertResult(t, "2", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
// func TestReadCmd_ToJson(t *testing.T) {
|
// func TestReadCmd_ToJson(t *testing.T) {
|
||||||
@ -559,7 +559,7 @@ b:
|
|||||||
defer test.RemoveTempYamlFile(filename)
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, fmt.Sprintf("read -p kv %s b.there*.c", filename))
|
result := test.RunCmd(cmd, fmt.Sprintf("read -p pv %s b.there*.c", filename))
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -587,7 +587,7 @@ b:
|
|||||||
defer test.RemoveTempYamlFile(filename)
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, fmt.Sprintf("read -p k %s b.there*.c", filename))
|
result := test.RunCmd(cmd, fmt.Sprintf("read -p p %s b.there*.c", filename))
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@ -871,6 +871,28 @@ func TestWriteCmdScript(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteCmdEmptyScript(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
updateScript := ``
|
||||||
|
scriptFilename := test.WriteTempYamlFile(updateScript)
|
||||||
|
defer test.RemoveTempYamlFile(scriptFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write --script %s %s", scriptFilename, filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteMultiCmd(t *testing.T) {
|
func TestWriteMultiCmd(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: 3
|
c: 3
|
||||||
|
19
yq.go
19
yq.go
@ -107,7 +107,7 @@ yq r -- things.yaml --key-starting-with-dashes.blah
|
|||||||
RunE: readProperty,
|
RunE: readProperty,
|
||||||
}
|
}
|
||||||
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
cmdRead.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), k (keys), kv (key and value pairs)")
|
cmdRead.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||||
return cmdRead
|
return cmdRead
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +218,7 @@ Note that you can give a create script to perform more sophisticated yaml. This
|
|||||||
`,
|
`,
|
||||||
RunE: newProperty,
|
RunE: newProperty,
|
||||||
}
|
}
|
||||||
cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml")
|
cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for creating yaml")
|
||||||
cmdNew.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
|
cmdNew.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
|
||||||
return cmdNew
|
return cmdNew
|
||||||
}
|
}
|
||||||
@ -323,6 +323,11 @@ func appendDocument(originalMatchingNodes []*yqlib.NodeContext, dataBucket yaml.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printValue(node *yaml.Node, cmd *cobra.Command) error {
|
func printValue(node *yaml.Node, cmd *cobra.Command) error {
|
||||||
|
if node.Kind == yaml.ScalarNode {
|
||||||
|
cmd.Print(node.Value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
bufferedWriter := bufio.NewWriter(cmd.OutOrStdout())
|
bufferedWriter := bufio.NewWriter(cmd.OutOrStdout())
|
||||||
defer safelyFlush(bufferedWriter)
|
defer safelyFlush(bufferedWriter)
|
||||||
|
|
||||||
@ -346,12 +351,12 @@ func printResults(matchingNodes []*yqlib.NodeContext, cmd *cobra.Command) error
|
|||||||
|
|
||||||
for index, mappedDoc := range matchingNodes {
|
for index, mappedDoc := range matchingNodes {
|
||||||
switch printMode {
|
switch printMode {
|
||||||
case "k":
|
case "p":
|
||||||
cmd.Print(lib.PathStackToString(mappedDoc.PathStack))
|
cmd.Print(lib.PathStackToString(mappedDoc.PathStack))
|
||||||
if index < len(matchingNodes)-1 {
|
if index < len(matchingNodes)-1 {
|
||||||
cmd.Print("\n")
|
cmd.Print("\n")
|
||||||
}
|
}
|
||||||
case "kv", "vk":
|
case "pv", "vp":
|
||||||
// put it into a node and print that.
|
// put it into a node and print that.
|
||||||
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
||||||
parentNode.Content = make([]*yaml.Node, 2)
|
parentNode.Content = make([]*yaml.Node, 2)
|
||||||
@ -601,9 +606,13 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string)
|
|||||||
var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
||||||
if writeScript != "" {
|
if writeScript != "" {
|
||||||
var parsedCommands = make([]updateCommandParsed, 0)
|
var parsedCommands = make([]updateCommandParsed, 0)
|
||||||
if err := readData(writeScript, 0, &parsedCommands); err != nil {
|
|
||||||
|
err := readData(writeScript, 0, &parsedCommands)
|
||||||
|
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Read write commands file '%v'", parsedCommands)
|
log.Debugf("Read write commands file '%v'", parsedCommands)
|
||||||
for index := range parsedCommands {
|
for index := range parsedCommands {
|
||||||
parsedCommand := parsedCommands[index]
|
parsedCommand := parsedCommands[index]
|
||||||
|
Loading…
Reference in New Issue
Block a user