mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c11c3df84f | ||
|
|
06bb3ac826 | ||
|
|
778f8c6916 | ||
|
|
9f43a4a265 | ||
|
|
bb6f07d147 | ||
|
|
759456e375 | ||
|
|
5e59803037 | ||
|
|
a0cb691601 | ||
|
|
086f0ec6b9 | ||
|
|
89cbe63343 | ||
|
|
07cd3d4b8b | ||
|
|
b7b6988e76 | ||
|
|
9de2039c31 | ||
|
|
767709fef5 | ||
|
|
d9ae8e1e5a | ||
|
|
b0fa0e5b86 | ||
|
|
6777d639c0 | ||
|
|
de8dcff803 | ||
|
|
765ada4dc6 | ||
|
|
1405584892 | ||
|
|
8c9c326342 | ||
|
|
e90b00957b | ||
|
|
71f5f76213 | ||
|
|
b9e304e7a4 | ||
|
|
d473c39a44 | ||
|
|
9624410add | ||
|
|
b55fe48bd8 | ||
|
|
721dd57ed4 | ||
|
|
6fc3566acd | ||
|
|
4b63d92a3c | ||
|
|
3ccd32a47e |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -10,6 +10,9 @@ assignees: ''
|
|||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
version of yq:
|
||||||
|
operating system:
|
||||||
|
|
||||||
**Input Yaml**
|
**Input Yaml**
|
||||||
Concise yaml document(s) (as simple as possible to show the bug)
|
Concise yaml document(s) (as simple as possible to show the bug)
|
||||||
data1.yml:
|
data1.yml:
|
||||||
|
|||||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -7,10 +7,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Set up Go 1.14
|
- name: Set up Go 1.15
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.14
|
go-version: 1.15
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.14 as builder
|
FROM golang:1.15 as builder
|
||||||
|
|
||||||
WORKDIR /go/src/mikefarah/yq
|
WORKDIR /go/src/mikefarah/yq
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.14
|
FROM golang:1.15
|
||||||
|
|
||||||
COPY scripts/devtools.sh /opt/devtools.sh
|
COPY scripts/devtools.sh /opt/devtools.sh
|
||||||
|
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -18,13 +18,20 @@ V3 is officially out - if you've been using v2 and want/need to upgrade, checkou
|
|||||||
```
|
```
|
||||||
brew install yq
|
brew install yq
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Windows:
|
||||||
|
```
|
||||||
|
choco install yq
|
||||||
|
```
|
||||||
|
Supported by @chillum
|
||||||
|
|
||||||
### Ubuntu and other Linux distros supporting `snap` packages:
|
### Ubuntu and other Linux distros supporting `snap` packages:
|
||||||
```
|
```
|
||||||
snap install yq
|
snap install yq
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Snap notes
|
#### Snap notes
|
||||||
`yq` installs with with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. To read root files you can:
|
`yq` installs with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. To read root files you can:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo cat /etc/myfile | yq r - a.path
|
sudo cat /etc/myfile | yq r - a.path
|
||||||
@@ -60,20 +67,20 @@ GO111MODULE=on go get github.com/mikefarah/yq/v3
|
|||||||
Oneshot use:
|
Oneshot use:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm -v ${PWD}:/workdir mikefarah/yq yq [flags] <command> FILE...
|
docker run --rm -v "${PWD}":/workdir mikefarah/yq yq [flags] <command> FILE...
|
||||||
```
|
```
|
||||||
|
|
||||||
Run commands interactively:
|
Run commands interactively:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run --rm -it -v ${PWD}:/workdir mikefarah/yq sh
|
docker run --rm -it -v "${PWD}":/workdir mikefarah/yq sh
|
||||||
```
|
```
|
||||||
|
|
||||||
It can be useful to have a bash function to avoid typing the whole docker command:
|
It can be useful to have a bash function to avoid typing the whole docker command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq() {
|
yq() {
|
||||||
docker run --rm -i -v ${PWD}:/workdir mikefarah/yq yq $@
|
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq yq "$@"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -94,6 +101,7 @@ yq() {
|
|||||||
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/commands/read#from-stdin)
|
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/commands/read#from-stdin)
|
||||||
- [Merge](https://mikefarah.gitbook.io/yq/commands/merge) multiple yaml files with various options for [overriding](https://mikefarah.gitbook.io/yq/commands/merge#overwrite-values) and [appending](https://mikefarah.gitbook.io/yq/commands/merge#append-values-with-arrays)
|
- [Merge](https://mikefarah.gitbook.io/yq/commands/merge) multiple yaml files with various options for [overriding](https://mikefarah.gitbook.io/yq/commands/merge#overwrite-values) and [appending](https://mikefarah.gitbook.io/yq/commands/merge#append-values-with-arrays)
|
||||||
- Supports multiple documents in a single yaml file for [reading](https://mikefarah.gitbook.io/yq/commands/read#multiple-documents), [writing](https://mikefarah.gitbook.io/yq/commands/write-update#multiple-documents) and [merging](https://mikefarah.gitbook.io/yq/commands/merge#multiple-documents)
|
- Supports multiple documents in a single yaml file for [reading](https://mikefarah.gitbook.io/yq/commands/read#multiple-documents), [writing](https://mikefarah.gitbook.io/yq/commands/write-update#multiple-documents) and [merging](https://mikefarah.gitbook.io/yq/commands/merge#multiple-documents)
|
||||||
|
- General shell completion scripts (bash/zsh/fish/powershell) (https://mikefarah.gitbook.io/yq/commands/shell-completion)
|
||||||
|
|
||||||
## [Usage](https://mikefarah.gitbook.io/yq/)
|
## [Usage](https://mikefarah.gitbook.io/yq/)
|
||||||
|
|
||||||
@@ -112,11 +120,12 @@ Available Commands:
|
|||||||
new yq n [--script/-s script_file] a.b.c newValue
|
new yq n [--script/-s script_file] a.b.c newValue
|
||||||
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
|
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
|
||||||
read yq r [--printMode/-p pv] sample.yaml 'b.e(name==fr*).value'
|
read yq r [--printMode/-p pv] sample.yaml 'b.e(name==fr*).value'
|
||||||
|
shell-completion Generates shell completion scripts
|
||||||
validate yq v sample.yaml
|
validate yq v sample.yaml
|
||||||
write yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue
|
write yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-C, --colors print using colors
|
-C, --colors print with colors
|
||||||
-h, --help help for yq
|
-h, --help help for yq
|
||||||
-I, --indent int sets indent level for output (default 2)
|
-I, --indent int sets indent level for output (default 2)
|
||||||
-P, --prettyPrint pretty print
|
-P, --prettyPrint pretty print
|
||||||
@@ -126,3 +135,6 @@ Flags:
|
|||||||
|
|
||||||
Use "yq [command] --help" for more information about a command.
|
Use "yq [command] --help" for more information about a command.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
- `yq` attempts to preserve comment positions and whitespace as much as possible, but it does not handle all scenarios (see https://github.com/go-yaml/yaml/tree/v3 for details)
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ yq x -d1 dataA.yaml dataB.yaml 'a.b.c'
|
|||||||
cmdCompare.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
cmdCompare.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
cmdCompare.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
cmdCompare.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||||
cmdCompare.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
cmdCompare.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
||||||
|
cmdCompare.PersistentFlags().BoolVarP(&stripComments, "stripComments", "", false, "strip comments out before comparing")
|
||||||
|
cmdCompare.PersistentFlags().BoolVarP(&explodeAnchors, "explodeAnchors", "X", false, "explode anchors")
|
||||||
return cmdCompare
|
return cmdCompare
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,55 @@ func TestCompareSameCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCompareIgnoreCommentsCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare --stripComments ../examples/data1.yaml ../examples/data1-no-comments.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := ``
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDontIgnoreCommentsCmd(t *testing.T) {
|
||||||
|
forceOsExit = false
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data1-no-comments.yaml")
|
||||||
|
|
||||||
|
expectedOutput := `-a: simple # just the best
|
||||||
|
+a: simple
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareExplodeAnchorsCommentsCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare --explodeAnchors ../examples/simple-anchor.yaml ../examples/simple-anchor-exploded.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := ``
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCompareDontExplodeAnchorsCmd(t *testing.T) {
|
||||||
|
forceOsExit = false
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare ../examples/simple-anchor.yaml ../examples/simple-anchor-exploded.yaml")
|
||||||
|
|
||||||
|
expectedOutput := `-foo: &foo
|
||||||
|
+foo:
|
||||||
|
a: 1
|
||||||
|
foobar:
|
||||||
|
- !!merge <<: *foo
|
||||||
|
+ a: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompareDifferentCmd(t *testing.T) {
|
func TestCompareDifferentCmd(t *testing.T) {
|
||||||
forceOsExit = false
|
forceOsExit = false
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ var printMode = "v"
|
|||||||
var printLength = false
|
var printLength = false
|
||||||
var unwrapScalar = true
|
var unwrapScalar = true
|
||||||
var customStyle = ""
|
var customStyle = ""
|
||||||
|
var anchorName = ""
|
||||||
|
var makeAlias = false
|
||||||
var stripComments = false
|
var stripComments = false
|
||||||
var collectIntoArray = false
|
var collectIntoArray = false
|
||||||
var writeInplace = false
|
var writeInplace = false
|
||||||
var writeScript = ""
|
var writeScript = ""
|
||||||
var sourceYamlFile = ""
|
var sourceYamlFile = ""
|
||||||
var outputToJSON = false
|
var outputToJSON = false
|
||||||
|
var exitStatus = false
|
||||||
var prettyPrint = false
|
var prettyPrint = false
|
||||||
var explodeAnchors = false
|
var explodeAnchors = false
|
||||||
var colorsEnabled = false
|
var colorsEnabled = false
|
||||||
|
|||||||
@@ -100,6 +100,29 @@ b:
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteDeepSplatArrayYaml(t *testing.T) {
|
||||||
|
content := `thing: 123
|
||||||
|
b:
|
||||||
|
hi:
|
||||||
|
- thing: item1
|
||||||
|
name: fred
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s **.thing", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `b:
|
||||||
|
hi:
|
||||||
|
- name: fred
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDeleteSplatPrefixYaml(t *testing.T) {
|
func TestDeleteSplatPrefixYaml(t *testing.T) {
|
||||||
content := `a: 2
|
content := `a: 2
|
||||||
b:
|
b:
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||||
errors "github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,16 +28,14 @@ Note that you can give a create script to perform more sophisticated yaml. This
|
|||||||
cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for creating 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)")
|
||||||
cmdNew.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
|
cmdNew.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
|
||||||
|
cmdNew.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name")
|
||||||
|
cmdNew.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name")
|
||||||
return cmdNew
|
return cmdNew
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProperty(cmd *cobra.Command, args []string) error {
|
func newProperty(cmd *cobra.Command, args []string) error {
|
||||||
var badArgsMessage = "Must provide <path_to_update> <value>"
|
var badArgsMessage = "Must provide <path_to_update> <value>"
|
||||||
if len(args) != 2 {
|
var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage, false)
|
||||||
return errors.New(badArgsMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage)
|
|
||||||
if updateCommandsError != nil {
|
if updateCommandsError != nil {
|
||||||
return updateCommandsError
|
return updateCommandsError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mikefarah/yq/v3/test"
|
"github.com/mikefarah/yq/v3/test"
|
||||||
@@ -18,6 +19,48 @@ func TestNewCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewCmdScript(t *testing.T) {
|
||||||
|
updateScript := `- command: update
|
||||||
|
path: b.c
|
||||||
|
value: 7`
|
||||||
|
scriptFilename := test.WriteTempYamlFile(updateScript)
|
||||||
|
defer test.RemoveTempYamlFile(scriptFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("new --script %s", scriptFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 7
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAnchorCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c 3 --anchorName=fred")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: &fred 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAliasCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c foo --makeAlias")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: *foo
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewArrayCmd(t *testing.T) {
|
func TestNewArrayCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "new b[0] 3")
|
result := test.RunCmd(cmd, "new b[0] 3")
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ yq r -- things.yaml '--key-starting-with-dashes.blah'
|
|||||||
cmdRead.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
cmdRead.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
||||||
cmdRead.PersistentFlags().BoolVarP(&stripComments, "stripComments", "", false, "print yaml without any comments")
|
cmdRead.PersistentFlags().BoolVarP(&stripComments, "stripComments", "", false, "print yaml without any comments")
|
||||||
cmdRead.PersistentFlags().BoolVarP(&explodeAnchors, "explodeAnchors", "X", false, "explode anchors")
|
cmdRead.PersistentFlags().BoolVarP(&explodeAnchors, "explodeAnchors", "X", false, "explode anchors")
|
||||||
|
cmdRead.PersistentFlags().BoolVarP(&exitStatus, "exitStatus", "e", false, "set exit status if no matches are found")
|
||||||
return cmdRead
|
return cmdRead
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +51,13 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
matchingNodes, errorReadingStream := readYamlFile(args[0], path, updateAll, docIndexInt)
|
matchingNodes, errorReadingStream := readYamlFile(args[0], path, updateAll, docIndexInt)
|
||||||
|
|
||||||
|
if exitStatus && len(matchingNodes) == 0 {
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
return errors.New("No matches found")
|
||||||
|
}
|
||||||
|
|
||||||
if errorReadingStream != nil {
|
if errorReadingStream != nil {
|
||||||
|
cmd.SilenceUsage = true
|
||||||
return errorReadingStream
|
return errorReadingStream
|
||||||
}
|
}
|
||||||
out := cmd.OutOrStdout()
|
out := cmd.OutOrStdout()
|
||||||
|
|||||||
@@ -17,6 +17,30 @@ func TestReadCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, "2\n", result.Output)
|
test.AssertResult(t, "2\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadCmdWithExitStatus(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml b.c -e")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "2\n", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCmdWithExitStatusNotExist(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml caterpillar -e")
|
||||||
|
test.AssertResult(t, "No matches found", result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadCmdNotExist(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml caterpillar")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadUnwrapCmd(t *testing.T) {
|
func TestReadUnwrapCmd(t *testing.T) {
|
||||||
|
|
||||||
content := `b: 'frog' # my favourite`
|
content := `b: 'frog' # my favourite`
|
||||||
@@ -882,6 +906,24 @@ b:
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadNotFoundWithExitStatus(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml adsf -e")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail")
|
||||||
|
}
|
||||||
|
expectedOutput := `No matches found`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadNotFoundWithoutExitStatus(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml adsf")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error("Expected command to succeed!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadPrettyPrintWithIndentCmd(t *testing.T) {
|
func TestReadPrettyPrintWithIndentCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read -P -I4 ../examples/sample.json")
|
result := test.RunCmd(cmd, "read -P -I4 ../examples/sample.json")
|
||||||
@@ -1165,6 +1207,26 @@ func TestReadBadDataCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadDeepFromRootCmd(t *testing.T) {
|
||||||
|
content := `state:
|
||||||
|
country:
|
||||||
|
city: foo
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read %s (**.city==foo)", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `country:
|
||||||
|
city: foo
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadSplatPrefixCmd(t *testing.T) {
|
func TestReadSplatPrefixCmd(t *testing.T) {
|
||||||
content := `a: 2
|
content := `a: 2
|
||||||
b:
|
b:
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ func New() *cobra.Command {
|
|||||||
createDeleteCmd(),
|
createDeleteCmd(),
|
||||||
createNewCmd(),
|
createNewCmd(),
|
||||||
createMergeCmd(),
|
createMergeCmd(),
|
||||||
|
createBashCompletionCmd(rootCmd),
|
||||||
)
|
)
|
||||||
rootCmd.SetOutput(os.Stdout)
|
|
||||||
|
|
||||||
return rootCmd
|
return rootCmd
|
||||||
}
|
}
|
||||||
|
|||||||
57
cmd/shell_completion.go
Normal file
57
cmd/shell_completion.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var shellVariant = "bash"
|
||||||
|
|
||||||
|
func createBashCompletionCmd(rootCmd *cobra.Command) *cobra.Command {
|
||||||
|
var completionCmd = &cobra.Command{
|
||||||
|
Use: "shell-completion",
|
||||||
|
Short: "Generates shell completion scripts",
|
||||||
|
Long: `To load completion for:
|
||||||
|
bash:
|
||||||
|
Run
|
||||||
|
. <(yq shell-completion)
|
||||||
|
|
||||||
|
To configure your bash shell to load completions for each session add to
|
||||||
|
your bashrc
|
||||||
|
|
||||||
|
# ~/.bashrc or ~/.profile
|
||||||
|
. <(yq shell-completion)
|
||||||
|
|
||||||
|
zsh:
|
||||||
|
The generated completion script should be put somewhere in your $fpath named _yq
|
||||||
|
|
||||||
|
powershell:
|
||||||
|
Users need PowerShell version 5.0 or above, which comes with Windows 10 and
|
||||||
|
can be downloaded separately for Windows 7 or 8.1. They can then write the
|
||||||
|
completions to a file and source this file from their PowerShell profile,
|
||||||
|
which is referenced by the $Profile environment variable.
|
||||||
|
|
||||||
|
fish:
|
||||||
|
Save the output to a fish file and add it to your completions directory.
|
||||||
|
|
||||||
|
`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
switch shellVariant {
|
||||||
|
case "bash", "":
|
||||||
|
return rootCmd.GenBashCompletion(os.Stdout)
|
||||||
|
case "zsh":
|
||||||
|
return rootCmd.GenZshCompletion(os.Stdout)
|
||||||
|
case "fish":
|
||||||
|
return rootCmd.GenFishCompletion(os.Stdout, true)
|
||||||
|
case "powershell":
|
||||||
|
return rootCmd.GenPowerShellCompletion(os.Stdout)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Unknown variant %v", shellVariant)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
completionCmd.PersistentFlags().StringVarP(&shellVariant, "variation", "V", "", "shell variation: bash (default), zsh, fish, powershell")
|
||||||
|
return completionCmd
|
||||||
|
}
|
||||||
113
cmd/utils.go
113
cmd/utils.go
@@ -149,25 +149,91 @@ func writeString(writer io.Writer, txt string) error {
|
|||||||
return errorWriting
|
return errorWriting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setIfNotThere(node *yaml.Node, key string, value *yaml.Node) {
|
||||||
|
for index := 0; index < len(node.Content); index = index + 2 {
|
||||||
|
keyNode := node.Content[index]
|
||||||
|
if keyNode.Value == key {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// need to add it to the map
|
||||||
|
mapEntryKey := yaml.Node{Value: key, Kind: yaml.ScalarNode}
|
||||||
|
node.Content = append(node.Content, &mapEntryKey)
|
||||||
|
node.Content = append(node.Content, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyAlias(node *yaml.Node, alias *yaml.Node) {
|
||||||
|
for index := 0; index < len(alias.Content); index = index + 2 {
|
||||||
|
keyNode := alias.Content[index]
|
||||||
|
log.Debugf("applying alias key %v", keyNode.Value)
|
||||||
|
valueNode := alias.Content[index+1]
|
||||||
|
setIfNotThere(node, keyNode.Value, valueNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func explodeNode(node *yaml.Node) error {
|
||||||
|
node.Anchor = ""
|
||||||
|
switch node.Kind {
|
||||||
|
case yaml.SequenceNode, yaml.DocumentNode:
|
||||||
|
for index, contentNode := range node.Content {
|
||||||
|
log.Debugf("exploding index %v", index)
|
||||||
|
errorInContent := explodeNode(contentNode)
|
||||||
|
if errorInContent != nil {
|
||||||
|
return errorInContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case yaml.AliasNode:
|
||||||
|
log.Debugf("its an alias!")
|
||||||
|
node.Kind = node.Alias.Kind
|
||||||
|
node.Style = node.Alias.Style
|
||||||
|
node.Tag = node.Alias.Tag
|
||||||
|
node.Content = node.Alias.Content
|
||||||
|
node.Value = node.Alias.Value
|
||||||
|
node.Alias = nil
|
||||||
|
return nil
|
||||||
|
case yaml.MappingNode:
|
||||||
|
for index := 0; index < len(node.Content); index = index + 2 {
|
||||||
|
keyNode := node.Content[index]
|
||||||
|
valueNode := node.Content[index+1]
|
||||||
|
log.Debugf("traversing %v", keyNode.Value)
|
||||||
|
if keyNode.Value != "<<" {
|
||||||
|
errorInContent := explodeNode(valueNode)
|
||||||
|
if errorInContent != nil {
|
||||||
|
return errorInContent
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if valueNode.Kind == yaml.SequenceNode {
|
||||||
|
log.Debugf("an alias merge list!")
|
||||||
|
for index := len(valueNode.Content) - 1; index >= 0; index = index - 1 {
|
||||||
|
aliasNode := valueNode.Content[index]
|
||||||
|
applyAlias(node, aliasNode.Alias)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Debugf("an alias merge!")
|
||||||
|
applyAlias(node, valueNode.Alias)
|
||||||
|
}
|
||||||
|
node.Content = append(node.Content[:index], node.Content[index+2:]...)
|
||||||
|
//replay that index, since the array is shorter now.
|
||||||
|
index = index - 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func explode(matchingNodes []*yqlib.NodeContext) error {
|
func explode(matchingNodes []*yqlib.NodeContext) error {
|
||||||
log.Debug("exploding nodes")
|
log.Debug("exploding nodes")
|
||||||
for _, nodeContext := range matchingNodes {
|
for _, nodeContext := range matchingNodes {
|
||||||
var targetNode = yaml.Node{Kind: nodeContext.Node.Kind}
|
log.Debugf("exploding %v", nodeContext.Head)
|
||||||
explodedNodes, errorRetrieving := lib.Get(nodeContext.Node, "**", true)
|
errorExplodingNode := explodeNode(nodeContext.Node)
|
||||||
if errorRetrieving != nil {
|
if errorExplodingNode != nil {
|
||||||
return errorRetrieving
|
return errorExplodingNode
|
||||||
}
|
|
||||||
for _, matchingNode := range explodedNodes {
|
|
||||||
mergePath := lib.MergePathStackToString(matchingNode.PathStack, appendFlag)
|
|
||||||
updateCommand := yqlib.UpdateCommand{Command: "update", Path: mergePath, Value: matchingNode.Node, Overwrite: overwriteFlag}
|
|
||||||
errorUpdating := lib.Update(&targetNode, updateCommand, true)
|
|
||||||
if errorUpdating != nil {
|
|
||||||
return errorUpdating
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodeContext.Node = &targetNode
|
|
||||||
}
|
|
||||||
log.Debug("done exploding nodes")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,6 +423,16 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// mkdir temp dir as some docker images does not have temp dir
|
||||||
|
_, err = os.Stat(os.TempDir())
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
err = os.Mkdir(os.TempDir(), 0700)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
tempFile, err := ioutil.TempFile("", "temp")
|
tempFile, err := ioutil.TempFile("", "temp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -401,7 +477,7 @@ type updateCommandParsed struct {
|
|||||||
Value yaml.Node
|
Value yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string) ([]yqlib.UpdateCommand, error) {
|
func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string, allowNoValue bool) ([]yqlib.UpdateCommand, error) {
|
||||||
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)
|
||||||
@@ -435,13 +511,14 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string)
|
|||||||
log.Debug("args %v", args)
|
log.Debug("args %v", args)
|
||||||
log.Debug("path %v", args[expectedArgs-2])
|
log.Debug("path %v", args[expectedArgs-2])
|
||||||
log.Debug("Value %v", args[expectedArgs-1])
|
log.Debug("Value %v", args[expectedArgs-1])
|
||||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag, customStyle), Overwrite: true}
|
value := valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias)
|
||||||
} else if len(args) == expectedArgs-1 {
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value, Overwrite: true, DontUpdateComments: true}
|
||||||
|
} else if len(args) == expectedArgs-1 && allowNoValue {
|
||||||
// don't update the value
|
// don't update the value
|
||||||
updateCommands = make([]yqlib.UpdateCommand, 1)
|
updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||||
log.Debug("args %v", args)
|
log.Debug("args %v", args)
|
||||||
log.Debug("path %v", args[expectedArgs-2])
|
log.Debug("path %v", args[expectedArgs-2])
|
||||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle), Overwrite: true, DontUpdateNodeValue: true}
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle, anchorName, makeAlias), Overwrite: true, DontUpdateNodeValue: true}
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(badArgsMessage)
|
return nil, errors.New(badArgsMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ var (
|
|||||||
GitDescribe string
|
GitDescribe string
|
||||||
|
|
||||||
// Version is main version number that is being run at the moment.
|
// Version is main version number that is being run at the moment.
|
||||||
Version = "3.3.0"
|
Version = "3.3.3"
|
||||||
|
|
||||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
||||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ format is list of update commands (update or delete) like so:
|
|||||||
cmdWrite.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
|
cmdWrite.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
|
||||||
cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
cmdWrite.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
|
cmdWrite.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
|
||||||
|
cmdWrite.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name")
|
||||||
|
cmdWrite.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name")
|
||||||
return cmdWrite
|
return cmdWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeProperty(cmd *cobra.Command, args []string) error {
|
func writeProperty(cmd *cobra.Command, args []string) error {
|
||||||
var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>")
|
var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>", true)
|
||||||
if updateCommandsError != nil {
|
if updateCommandsError != nil {
|
||||||
return updateCommandsError
|
return updateCommandsError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,24 @@ func TestWriteCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteKeepCommentsCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3 # comment
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 7 # comment
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: dog
|
c: dog
|
||||||
|
|||||||
17
debian/changelog
vendored
17
debian/changelog
vendored
@@ -1,3 +1,20 @@
|
|||||||
|
yq (3.3.2) focal; urgency=medium
|
||||||
|
|
||||||
|
* Bug fix: existStatus bug (#459)
|
||||||
|
* Automatically makes a os temp directory if it does not exist (#461)
|
||||||
|
|
||||||
|
-- Roberto Mier Escandon <rmescandon@gmail.com> Fri, 07 Aug 2020 18:53:01 +0200
|
||||||
|
|
||||||
|
yq (3.3-0) focal; urgency=medium
|
||||||
|
|
||||||
|
* You can control string styles (quotes) using the new --style flag
|
||||||
|
* String values now always have quotes when outputting to json
|
||||||
|
* Negative array indices now traverse the array backwards
|
||||||
|
* Added a --stripComments flag to print yaml without any comments
|
||||||
|
* Bumped go to version 1.14
|
||||||
|
|
||||||
|
-- Roberto Mier Escandon <rmescandon@gmail.com> Thu, 30 Apr 2020 20:45:44 +0200
|
||||||
|
|
||||||
yq (3.1-2) eoan; urgency=medium
|
yq (3.1-2) eoan; urgency=medium
|
||||||
|
|
||||||
* Bug fix: yq 3 was removing empty inline-style objects and arrays (#355)
|
* Bug fix: yq 3 was removing empty inline-style objects and arrays (#355)
|
||||||
|
|||||||
1
debian/files
vendored
1
debian/files
vendored
@@ -1 +0,0 @@
|
|||||||
yq_3.1-2_source.buildinfo devel optional
|
|
||||||
4
examples/data1-no-comments.yaml
Normal file
4
examples/data1-no-comments.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
a: simple
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
b:
|
|
||||||
c: things
|
|
||||||
5
examples/simple-anchor-exploded.yaml
Normal file
5
examples/simple-anchor-exploded.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
foo:
|
||||||
|
a: 1
|
||||||
|
|
||||||
|
foobar:
|
||||||
|
a: 1
|
||||||
12
go.mod
12
go.mod
@@ -2,16 +2,16 @@ module github.com/mikefarah/yq/v3
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/goccy/go-yaml v1.4.3
|
github.com/goccy/go-yaml v1.8.1
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.0.0
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.14
|
go 1.15
|
||||||
|
|||||||
22
go.sum
22
go.sum
@@ -29,8 +29,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-yaml v1.4.3 h1:+1jK1ost1TBEfWjciIMU8rciBq0poxurgS7XvLgQInM=
|
github.com/goccy/go-yaml v1.8.1 h1:JuZRFlqLM5cWF6A+waL8AKVuCcqvKOuhJtUQI+L3ez0=
|
||||||
github.com/goccy/go-yaml v1.4.3/go.mod h1:PsEEJ29nIFZL07P/c8dv4P6rQkVFFXafQee85U+ERHA=
|
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@@ -64,8 +64,8 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
|
|||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||||
@@ -144,19 +144,20 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193
|
|||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc=
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@@ -175,7 +176,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ func NewDataNavigator(NavigationStrategy NavigationStrategy) DataNavigator {
|
|||||||
func (n *navigator) Traverse(value *yaml.Node, path []interface{}) error {
|
func (n *navigator) Traverse(value *yaml.Node, path []interface{}) error {
|
||||||
realValue := value
|
realValue := value
|
||||||
emptyArray := make([]interface{}, 0)
|
emptyArray := make([]interface{}, 0)
|
||||||
|
log.Debugf("Traversing path %v", pathStackToString(path))
|
||||||
if realValue.Kind == yaml.DocumentNode {
|
if realValue.Kind == yaml.DocumentNode {
|
||||||
log.Debugf("its a document! returning the first child")
|
log.Debugf("its a document! returning the first child")
|
||||||
return n.doTraverse(value.Content[0], "", path, emptyArray)
|
return n.doTraverse(value.Content[0], "", path, emptyArray)
|
||||||
@@ -68,6 +69,16 @@ func (n *navigator) getOrReplace(original *yaml.Node, expectedKind yaml.Kind) *y
|
|||||||
|
|
||||||
func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface{}, pathStack []interface{}) error {
|
func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface{}, pathStack []interface{}) error {
|
||||||
log.Debug("recursing, processing %v, pathStack %v", head, pathStackToString(pathStack))
|
log.Debug("recursing, processing %v, pathStack %v", head, pathStackToString(pathStack))
|
||||||
|
|
||||||
|
nodeContext := NewNodeContext(value, head, tail, pathStack)
|
||||||
|
|
||||||
|
if head == "**" && !n.navigationStrategy.ShouldOnlyDeeplyVisitLeaves(nodeContext) {
|
||||||
|
errorVisitingDeeply := n.navigationStrategy.Visit(nodeContext)
|
||||||
|
if errorVisitingDeeply != nil {
|
||||||
|
return errorVisitingDeeply
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch value.Kind {
|
switch value.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
log.Debug("its a map with %v entries", len(value.Content)/2)
|
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||||
@@ -85,20 +96,20 @@ func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface
|
|||||||
if head == "+" {
|
if head == "+" {
|
||||||
return n.appendArray(value, head, tail, pathStack)
|
return n.appendArray(value, head, tail, pathStack)
|
||||||
} else if len(value.Content) == 0 && head == "**" {
|
} else if len(value.Content) == 0 && head == "**" {
|
||||||
return n.navigationStrategy.Visit(NewNodeContext(value, head, tail, pathStack))
|
return n.navigationStrategy.Visit(nodeContext)
|
||||||
}
|
}
|
||||||
return n.splatArray(value, head, tail, pathStack)
|
return n.splatArray(value, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
case yaml.AliasNode:
|
case yaml.AliasNode:
|
||||||
log.Debug("its an alias!")
|
log.Debug("its an alias!")
|
||||||
DebugNode(value.Alias)
|
DebugNode(value.Alias)
|
||||||
if n.navigationStrategy.FollowAlias(NewNodeContext(value, head, tail, pathStack)) {
|
if n.navigationStrategy.FollowAlias(nodeContext) {
|
||||||
log.Debug("following the alias")
|
log.Debug("following the alias")
|
||||||
return n.recurse(value.Alias, head, tail, pathStack)
|
return n.recurse(value.Alias, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return n.navigationStrategy.Visit(NewNodeContext(value, head, tail, pathStack))
|
return n.navigationStrategy.Visit(nodeContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,12 @@ func DeleteNavigationStrategy(pathElementToDelete interface{}) NavigationStrateg
|
|||||||
followAlias: func(nodeContext NodeContext) bool {
|
followAlias: func(nodeContext NodeContext) bool {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
node := nodeContext.Node
|
node := nodeContext.Node
|
||||||
log.Debug("need to find and delete %v in here", pathElementToDelete)
|
log.Debug("need to find and delete %v in here (%v)", pathElementToDelete, pathStackToString(nodeContext.PathStack))
|
||||||
DebugNode(node)
|
DebugNode(node)
|
||||||
if node.Kind == yaml.SequenceNode {
|
if node.Kind == yaml.SequenceNode {
|
||||||
newContent := deleteFromArray(parser, node.Content, nodeContext.PathStack, pathElementToDelete)
|
newContent := deleteFromArray(parser, node.Content, nodeContext.PathStack, pathElementToDelete)
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy {
|
|||||||
return &NavigationStrategyImpl{
|
return &NavigationStrategyImpl{
|
||||||
visitedNodes: []*NodeContext{},
|
visitedNodes: []*NodeContext{},
|
||||||
pathParser: NewPathParser(),
|
pathParser: NewPathParser(),
|
||||||
followAlias: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type UpdateCommand struct {
|
|||||||
Value *yaml.Node
|
Value *yaml.Node
|
||||||
Overwrite bool
|
Overwrite bool
|
||||||
DontUpdateNodeValue bool
|
DontUpdateNodeValue bool
|
||||||
|
DontUpdateComments bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func KindString(kind yaml.Kind) string {
|
func KindString(kind yaml.Kind) string {
|
||||||
@@ -48,7 +49,7 @@ func DebugNode(value *yaml.Node) {
|
|||||||
log.Error("Error debugging node, %v", errorEncoding.Error())
|
log.Error("Error debugging node, %v", errorEncoding.Error())
|
||||||
}
|
}
|
||||||
encoder.Close()
|
encoder.Close()
|
||||||
log.Debug("Tag: %v, Kind: %v", value.Tag, KindString(value.Kind))
|
log.Debug("Tag: %v, Kind: %v, Anchor: %v", value.Tag, KindString(value.Kind), value.Anchor)
|
||||||
log.Debug("%v", buf.String())
|
log.Debug("%v", buf.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ type NavigationStrategy interface {
|
|||||||
// we use it to match against the pathExpression in head.
|
// we use it to match against the pathExpression in head.
|
||||||
ShouldTraverse(nodeContext NodeContext, nodeKey string) bool
|
ShouldTraverse(nodeContext NodeContext, nodeKey string) bool
|
||||||
ShouldDeeplyTraverse(nodeContext NodeContext) bool
|
ShouldDeeplyTraverse(nodeContext NodeContext) bool
|
||||||
|
// when deeply traversing, should we visit all matching nodes, or just leaves?
|
||||||
|
ShouldOnlyDeeplyVisitLeaves(NodeContext) bool
|
||||||
GetVisitedNodes() []*NodeContext
|
GetVisitedNodes() []*NodeContext
|
||||||
DebugVisitedNodes()
|
DebugVisitedNodes()
|
||||||
GetPathParser() PathParser
|
GetPathParser() PathParser
|
||||||
@@ -46,6 +48,7 @@ type NavigationStrategyImpl struct {
|
|||||||
visit func(nodeContext NodeContext) error
|
visit func(nodeContext NodeContext) error
|
||||||
shouldVisitExtraFn func(nodeContext NodeContext) bool
|
shouldVisitExtraFn func(nodeContext NodeContext) bool
|
||||||
shouldDeeplyTraverse func(nodeContext NodeContext) bool
|
shouldDeeplyTraverse func(nodeContext NodeContext) bool
|
||||||
|
shouldOnlyDeeplyVisitLeaves func(nodeContext NodeContext) bool
|
||||||
visitedNodes []*NodeContext
|
visitedNodes []*NodeContext
|
||||||
pathParser PathParser
|
pathParser PathParser
|
||||||
}
|
}
|
||||||
@@ -59,16 +62,33 @@ func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool {
|
||||||
|
if ns.followAlias != nil {
|
||||||
return ns.followAlias(nodeContext)
|
return ns.followAlias(nodeContext)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool {
|
||||||
|
if ns.autoCreateMap != nil {
|
||||||
return ns.autoCreateMap(nodeContext)
|
return ns.autoCreateMap(nodeContext)
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool {
|
||||||
|
if ns.shouldDeeplyTraverse != nil {
|
||||||
return ns.shouldDeeplyTraverse(nodeContext)
|
return ns.shouldDeeplyTraverse(nodeContext)
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool {
|
||||||
|
if ns.shouldOnlyDeeplyVisitLeaves != nil {
|
||||||
|
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool {
|
func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool {
|
||||||
// we should traverse aliases (if enabled), but not visit them :/
|
// we should traverse aliases (if enabled), but not visit them :/
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ func ReadNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy {
|
|||||||
return &NavigationStrategyImpl{
|
return &NavigationStrategyImpl{
|
||||||
visitedNodes: []*NodeContext{},
|
visitedNodes: []*NodeContext{},
|
||||||
pathParser: NewPathParser(),
|
pathParser: NewPathParser(),
|
||||||
followAlias: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
autoCreateMap: func(nodeContext NodeContext) bool {
|
||||||
return autoCreate
|
return autoCreate
|
||||||
},
|
},
|
||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
node := nodeContext.Node
|
node := nodeContext.Node
|
||||||
changesToApply := updateCommand.Value
|
changesToApply := updateCommand.Value
|
||||||
@@ -28,9 +25,13 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
node.Kind = changesToApply.Kind
|
node.Kind = changesToApply.Kind
|
||||||
node.Style = changesToApply.Style
|
node.Style = changesToApply.Style
|
||||||
node.Content = changesToApply.Content
|
node.Content = changesToApply.Content
|
||||||
|
node.Anchor = changesToApply.Anchor
|
||||||
|
node.Alias = changesToApply.Alias
|
||||||
|
if !updateCommand.DontUpdateComments {
|
||||||
node.HeadComment = changesToApply.HeadComment
|
node.HeadComment = changesToApply.HeadComment
|
||||||
node.LineComment = changesToApply.LineComment
|
node.LineComment = changesToApply.LineComment
|
||||||
node.FootComment = changesToApply.FootComment
|
node.FootComment = changesToApply.FootComment
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Debug("skipping update as node already has value %v and overwriteFlag is ", node.Value, updateCommand.Overwrite)
|
log.Debug("skipping update as node already has value %v and overwriteFlag is ", node.Value, updateCommand.Overwrite)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ValueParser interface {
|
type ValueParser interface {
|
||||||
Parse(argument string, customTag string, customStyle string) *yaml.Node
|
Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type valueParser struct {
|
type valueParser struct {
|
||||||
@@ -15,7 +15,7 @@ func NewValueParser() ValueParser {
|
|||||||
return &valueParser{}
|
return &valueParser{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *valueParser) Parse(argument string, customTag string, customStyle string) *yaml.Node {
|
func (v *valueParser) Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node {
|
||||||
var style yaml.Style
|
var style yaml.Style
|
||||||
if customStyle == "tagged" {
|
if customStyle == "tagged" {
|
||||||
style = yaml.TaggedStyle
|
style = yaml.TaggedStyle
|
||||||
@@ -27,12 +27,20 @@ func (v *valueParser) Parse(argument string, customTag string, customStyle strin
|
|||||||
style = yaml.LiteralStyle
|
style = yaml.LiteralStyle
|
||||||
} else if customStyle == "folded" {
|
} else if customStyle == "folded" {
|
||||||
style = yaml.FoldedStyle
|
style = yaml.FoldedStyle
|
||||||
|
} else if customStyle == "flow" {
|
||||||
|
style = yaml.FlowStyle
|
||||||
} else if customStyle != "" {
|
} else if customStyle != "" {
|
||||||
log.Error("Unknown style %v, ignoring", customStyle)
|
log.Error("Unknown style %v, ignoring", customStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
if argument == "[]" {
|
if argument == "[]" {
|
||||||
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode, Style: style}
|
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode, Style: style}
|
||||||
}
|
}
|
||||||
return &yaml.Node{Value: argument, Tag: customTag, Kind: yaml.ScalarNode, Style: style}
|
|
||||||
|
kind := yaml.ScalarNode
|
||||||
|
|
||||||
|
if createAlias {
|
||||||
|
kind = yaml.AliasNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return &yaml.Node{Value: argument, Tag: customTag, Kind: kind, Style: style, Anchor: anchorName}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ var parseStyleTests = []struct {
|
|||||||
{"double", yaml.DoubleQuotedStyle},
|
{"double", yaml.DoubleQuotedStyle},
|
||||||
{"single", yaml.SingleQuotedStyle},
|
{"single", yaml.SingleQuotedStyle},
|
||||||
{"folded", yaml.FoldedStyle},
|
{"folded", yaml.FoldedStyle},
|
||||||
|
{"flow", yaml.FlowStyle},
|
||||||
{"literal", yaml.LiteralStyle},
|
{"literal", yaml.LiteralStyle},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValueParserStyleTag(t *testing.T) {
|
func TestValueParserStyleTag(t *testing.T) {
|
||||||
for _, tt := range parseStyleTests {
|
for _, tt := range parseStyleTests {
|
||||||
actual := NewValueParser().Parse("cat", "", tt.customStyle)
|
actual := NewValueParser().Parse("cat", "", tt.customStyle, "", false)
|
||||||
test.AssertResultWithContext(t, tt.expectedStyle, actual.Style, tt.customStyle)
|
test.AssertResultWithContext(t, tt.expectedStyle, actual.Style, tt.customStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +40,7 @@ var parseValueTests = []struct {
|
|||||||
|
|
||||||
func TestValueParserParse(t *testing.T) {
|
func TestValueParserParse(t *testing.T) {
|
||||||
for _, tt := range parseValueTests {
|
for _, tt := range parseValueTests {
|
||||||
actual := NewValueParser().Parse(tt.argument, tt.customTag, "")
|
actual := NewValueParser().Parse(tt.argument, tt.customTag, "", "", false)
|
||||||
test.AssertResultWithContext(t, tt.argument, actual.Value, tt.testDescription)
|
test.AssertResultWithContext(t, tt.argument, actual.Value, tt.testDescription)
|
||||||
test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, tt.testDescription)
|
test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, tt.testDescription)
|
||||||
test.AssertResult(t, yaml.ScalarNode, actual.Kind)
|
test.AssertResult(t, yaml.ScalarNode, actual.Kind)
|
||||||
@@ -47,7 +48,18 @@ func TestValueParserParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValueParserParseEmptyArray(t *testing.T) {
|
func TestValueParserParseEmptyArray(t *testing.T) {
|
||||||
actual := NewValueParser().Parse("[]", "", "")
|
actual := NewValueParser().Parse("[]", "", "", "", false)
|
||||||
test.AssertResult(t, "!!seq", actual.Tag)
|
test.AssertResult(t, "!!seq", actual.Tag)
|
||||||
test.AssertResult(t, yaml.SequenceNode, actual.Kind)
|
test.AssertResult(t, yaml.SequenceNode, actual.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValueParserParseAlias(t *testing.T) {
|
||||||
|
actual := NewValueParser().Parse("bob", "", "", "", true)
|
||||||
|
test.AssertResult(t, "bob", actual.Value)
|
||||||
|
test.AssertResult(t, yaml.AliasNode, actual.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValueParserAnchorname(t *testing.T) {
|
||||||
|
actual := NewValueParser().Parse("caterpillar", "", "", "foo", false)
|
||||||
|
test.AssertResult(t, "foo", actual.Anchor)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
brew install mkdocs libyaml
|
|
||||||
pip3 install markdown-include
|
|
||||||
pip3 install mkdocs-material
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '3.3.0'
|
version: '3.3.3'
|
||||||
summary: A lightweight and portable command-line YAML processor
|
summary: A lightweight and portable command-line YAML processor
|
||||||
description: |
|
description: |
|
||||||
The aim of the project is to be the jq or sed of yaml files.
|
The aim of the project is to be the jq or sed of yaml files.
|
||||||
@@ -16,7 +16,7 @@ apps:
|
|||||||
parts:
|
parts:
|
||||||
yq:
|
yq:
|
||||||
plugin: go
|
plugin: go
|
||||||
go-channel: 1.14/stable
|
go-channel: 1.15/stable
|
||||||
source: .
|
source: .
|
||||||
source-type: git
|
source-type: git
|
||||||
go-importpath: github.com/mikefarah/yq
|
go-importpath: github.com/mikefarah/yq
|
||||||
|
|||||||
3
yq.go
3
yq.go
@@ -4,14 +4,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
command "github.com/mikefarah/yq/v3/cmd"
|
command "github.com/mikefarah/yq/v3/cmd"
|
||||||
logging "gopkg.in/op/go-logging.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd := command.New()
|
cmd := command.New()
|
||||||
log := logging.MustGetLogger("yq")
|
|
||||||
if err := cmd.Execute(); err != nil {
|
if err := cmd.Execute(); err != nil {
|
||||||
log.Error(err.Error())
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user