mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
56 Commits
array-leng
...
3.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0fa0e5b86 | ||
|
|
6777d639c0 | ||
|
|
de8dcff803 | ||
|
|
765ada4dc6 | ||
|
|
1405584892 | ||
|
|
8c9c326342 | ||
|
|
e90b00957b | ||
|
|
71f5f76213 | ||
|
|
b9e304e7a4 | ||
|
|
d473c39a44 | ||
|
|
9624410add | ||
|
|
b55fe48bd8 | ||
|
|
721dd57ed4 | ||
|
|
6fc3566acd | ||
|
|
4b63d92a3c | ||
|
|
3ccd32a47e | ||
|
|
3f913afbb9 | ||
|
|
ff598e1933 | ||
|
|
23de61a8d7 | ||
|
|
64135a16e1 | ||
|
|
06d8715cbe | ||
|
|
e15633023f | ||
|
|
6f0a329331 | ||
|
|
55511de9af | ||
|
|
2db69c91c9 | ||
|
|
33e35d10dd | ||
|
|
dfdbbbb24a | ||
|
|
55c4d01a91 | ||
|
|
7dc3d62bb6 | ||
|
|
11116804c5 | ||
|
|
f68b24323e | ||
|
|
8f166a9848 | ||
|
|
3c36db9285 | ||
|
|
605d6fab9b | ||
|
|
1f9a3f5f6c | ||
|
|
a06320f13c | ||
|
|
279996533d | ||
|
|
efe942727d | ||
|
|
e4dc70cc84 | ||
|
|
8ade1275e2 | ||
|
|
e1e05d85e3 | ||
|
|
b99467432e | ||
|
|
6b07143af7 | ||
|
|
ed234e37ce | ||
|
|
c0e4917d52 | ||
|
|
2713893f87 | ||
|
|
6bb221e973 | ||
|
|
7eb01a81da | ||
|
|
5c117204fa | ||
|
|
a4fa8f1341 | ||
|
|
69caccd2d3 | ||
|
|
67fb924e0e | ||
|
|
b64187fe32 | ||
|
|
8e6ceba2ac | ||
|
|
6ef04e1e77 | ||
|
|
10029420a5 |
12
.github/workflows/go.yml
vendored
12
.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.13
|
- name: Set up Go 1.14
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.13
|
go-version: 1.14
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
@@ -25,6 +25,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Download deps
|
- name: Download deps
|
||||||
run: scripts/devtools.sh
|
run: |
|
||||||
|
export PATH=${PATH}:`go env GOPATH`/bin
|
||||||
|
scripts/devtools.sh
|
||||||
- name: Build
|
- name: Build
|
||||||
run: make local build
|
run: |
|
||||||
|
export PATH=${PATH}:`go env GOPATH`/bin
|
||||||
|
make local build
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.13 as builder
|
FROM golang:1.14 as builder
|
||||||
|
|
||||||
WORKDIR /go/src/mikefarah/yq
|
WORKDIR /go/src/mikefarah/yq
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.13
|
FROM golang:1.14
|
||||||
|
|
||||||
COPY scripts/devtools.sh /opt/devtools.sh
|
COPY scripts/devtools.sh /opt/devtools.sh
|
||||||
|
|
||||||
@@ -9,15 +9,15 @@ RUN set -e -x \
|
|||||||
RUN set -ex \
|
RUN set -ex \
|
||||||
&& buildDeps=' \
|
&& buildDeps=' \
|
||||||
build-essential \
|
build-essential \
|
||||||
python-dev \
|
python3-dev \
|
||||||
' \
|
' \
|
||||||
&& apt-get update && apt-get install -y --no-install-recommends \
|
&& apt-get update && apt-get install -y --no-install-recommends \
|
||||||
$buildDeps \
|
$buildDeps \
|
||||||
python2.7 \
|
python3 \
|
||||||
python-setuptools \
|
python3-setuptools \
|
||||||
python-wheel \
|
python3-wheel \
|
||||||
python-pip \
|
python3-pip \
|
||||||
&& pip install --upgrade \
|
&& pip3 install --upgrade \
|
||||||
pip \
|
pip \
|
||||||
'Markdown>=2.6.9' \
|
'Markdown>=2.6.9' \
|
||||||
'mkdocs>=0.16.3' \
|
'mkdocs>=0.16.3' \
|
||||||
|
|||||||
18
README.md
18
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,27 +67,29 @@ 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 "$@"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Written in portable go, so you can download a lovely dependency free binary
|
- Written in portable go, so you can download a lovely dependency free binary
|
||||||
|
- [Colorize the output](https://mikefarah.gitbook.io/yq/usage/output-format#colorize-output)
|
||||||
- [Deep read a yaml file with a given path expression](https://mikefarah.gitbook.io/yq/commands/read#basic)
|
- [Deep read a yaml file with a given path expression](https://mikefarah.gitbook.io/yq/commands/read#basic)
|
||||||
- [List matching paths of a given path expression](https://mikefarah.gitbook.io/yq/commands/read#path-only)
|
- [List matching paths of a given path expression](https://mikefarah.gitbook.io/yq/commands/read#path-only)
|
||||||
|
- [Return the lengths of arrays/object/scalars](https://mikefarah.gitbook.io/yq/commands/read#printing-length-of-the-results)
|
||||||
- Update a yaml file given a [path expression](https://mikefarah.gitbook.io/yq/commands/write-update#basic) or [script file](https://mikefarah.gitbook.io/yq/commands/write-update#basic)
|
- Update a yaml file given a [path expression](https://mikefarah.gitbook.io/yq/commands/write-update#basic) or [script file](https://mikefarah.gitbook.io/yq/commands/write-update#basic)
|
||||||
- Update creates any missing entries in the path on the fly
|
- Update creates any missing entries in the path on the fly
|
||||||
- Deeply [compare](https://mikefarah.gitbook.io/yq/commands/compare) yaml files
|
- Deeply [compare](https://mikefarah.gitbook.io/yq/commands/compare) yaml files
|
||||||
@@ -114,6 +123,7 @@ Available Commands:
|
|||||||
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
|
||||||
-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
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
name: 'YAML processor'
|
name: 'yq - portable yaml processor'
|
||||||
description: 'YAML processor for running in Github action'
|
description: 'create, read, update, delete, merge, validate and do more with yaml'
|
||||||
|
icon: command
|
||||||
|
color: gray-dark
|
||||||
inputs:
|
inputs:
|
||||||
cmd:
|
cmd:
|
||||||
description: 'The Command which should be run'
|
description: 'The Command which should be run'
|
||||||
|
|||||||
2121
cmd/commands_test.go
2121
cmd/commands_test.go
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/diff"
|
"github.com/kylelemons/godebug/diff"
|
||||||
@@ -11,6 +12,9 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// turn off for unit tests :(
|
||||||
|
var forceOsExit = true
|
||||||
|
|
||||||
func createCompareCmd() *cobra.Command {
|
func createCompareCmd() *cobra.Command {
|
||||||
var cmdCompare = &cobra.Command{
|
var cmdCompare = &cobra.Command{
|
||||||
Use: "compare [yaml_file_a] [yaml_file_b]",
|
Use: "compare [yaml_file_a] [yaml_file_b]",
|
||||||
@@ -27,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +76,14 @@ func compareDocuments(cmd *cobra.Command, args []string) error {
|
|||||||
return errorDoingThings
|
return errorDoingThings
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Print(diff.Diff(strings.TrimSuffix(dataBufferA.String(), "\n"), strings.TrimSuffix(dataBufferB.String(), "\n")))
|
diffString := diff.Diff(strings.TrimSuffix(dataBufferA.String(), "\n"), strings.TrimSuffix(dataBufferB.String(), "\n"))
|
||||||
cmd.Print("\n")
|
|
||||||
|
if len(diffString) > 1 {
|
||||||
|
cmd.Print(diffString)
|
||||||
|
cmd.Print("\n")
|
||||||
|
if forceOsExit {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
115
cmd/compare_test.go
Normal file
115
cmd/compare_test.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompareSameCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data1.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := ``
|
||||||
|
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) {
|
||||||
|
forceOsExit = false
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare ../examples/data1.yaml ../examples/data3.yaml")
|
||||||
|
|
||||||
|
expectedOutput := `-a: simple # just the best
|
||||||
|
-b: [1, 2]
|
||||||
|
+a: "simple" # just the best
|
||||||
|
+b: [1, 3]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComparePrettyCmd(t *testing.T) {
|
||||||
|
forceOsExit = false
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare -P ../examples/data1.yaml ../examples/data3.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := ` a: simple # just the best
|
||||||
|
b:
|
||||||
|
- 1
|
||||||
|
- - 2
|
||||||
|
+ - 3
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComparePathsCmd(t *testing.T) {
|
||||||
|
forceOsExit = false
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "compare -P -ppv ../examples/data1.yaml ../examples/data3.yaml **")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := ` a: simple # just the best
|
||||||
|
b.[0]: 1
|
||||||
|
-b.[1]: 2
|
||||||
|
+b.[1]: 3
|
||||||
|
c.test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
@@ -7,10 +7,18 @@ import (
|
|||||||
|
|
||||||
var customTag = ""
|
var customTag = ""
|
||||||
var printMode = "v"
|
var printMode = "v"
|
||||||
|
var printLength = false
|
||||||
|
var unwrapScalar = true
|
||||||
|
var customStyle = ""
|
||||||
|
var anchorName = ""
|
||||||
|
var makeAlias = false
|
||||||
|
var stripComments = 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
|
||||||
|
|||||||
246
cmd/delete_test.go
Normal file
246
cmd/delete_test.go
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeleteYamlCmd(t *testing.T) {
|
||||||
|
content := `a: 2
|
||||||
|
b:
|
||||||
|
c: things
|
||||||
|
d: something else
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.c", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: 2
|
||||||
|
b:
|
||||||
|
d: something else
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteDeepDoesNotExistCmd(t *testing.T) {
|
||||||
|
content := `a: 2`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.c", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: 2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteSplatYaml(t *testing.T) {
|
||||||
|
content := `a: other
|
||||||
|
b: [3, 4]
|
||||||
|
c:
|
||||||
|
toast: leave
|
||||||
|
test: 1
|
||||||
|
tell: 1
|
||||||
|
tasty.taco: cool
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s c.te*", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: other
|
||||||
|
b: [3, 4]
|
||||||
|
c:
|
||||||
|
toast: leave
|
||||||
|
tasty.taco: cool
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteSplatArrayYaml(t *testing.T) {
|
||||||
|
content := `a: 2
|
||||||
|
b:
|
||||||
|
hi:
|
||||||
|
- thing: item1
|
||||||
|
name: fred
|
||||||
|
- thing: item2
|
||||||
|
name: sam
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.hi[*].thing", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: 2
|
||||||
|
b:
|
||||||
|
hi:
|
||||||
|
- name: fred
|
||||||
|
- name: sam
|
||||||
|
`
|
||||||
|
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) {
|
||||||
|
content := `a: 2
|
||||||
|
b:
|
||||||
|
hi:
|
||||||
|
c: things
|
||||||
|
d: something else
|
||||||
|
there:
|
||||||
|
c: more things
|
||||||
|
d: more something else
|
||||||
|
there2:
|
||||||
|
c: more things also
|
||||||
|
d: more something else also
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s b.there*.c", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: 2
|
||||||
|
b:
|
||||||
|
hi:
|
||||||
|
c: things
|
||||||
|
d: something else
|
||||||
|
there:
|
||||||
|
d: more something else
|
||||||
|
there2:
|
||||||
|
d: more something else also
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteYamlArrayCmd(t *testing.T) {
|
||||||
|
content := `- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s [1]", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `- 1
|
||||||
|
- 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteYamlArrayExpressionCmd(t *testing.T) {
|
||||||
|
content := `- name: fred
|
||||||
|
- name: cat
|
||||||
|
- name: thing
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s (name==cat)", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `- name: fred
|
||||||
|
- name: thing
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteYamlMulti(t *testing.T) {
|
||||||
|
content := `apples: great
|
||||||
|
---
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete -d 1 %s [1]", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `apples: great
|
||||||
|
---
|
||||||
|
- 1
|
||||||
|
- 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteYamlMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: great
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
something: else
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("delete %s -d * apples", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
337
cmd/merge_test.go
Normal file
337
cmd/merge_test.go
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMergeCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
toast: leave
|
||||||
|
tell: 1
|
||||||
|
tasty.taco: cool
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOneFileCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge ../examples/data1.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeNoAutoCreateCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge -c=false ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge -c=false --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: other # better than the original
|
||||||
|
b: [3, 4]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeAppendCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --autocreate=false --append ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2, 3, 4]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeAppendArraysCmd(t *testing.T) {
|
||||||
|
content := `people:
|
||||||
|
- name: Barry
|
||||||
|
age: 21`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `people:
|
||||||
|
- name: Roger
|
||||||
|
age: 44`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --append -d* %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `people:
|
||||||
|
- name: Barry
|
||||||
|
age: 21
|
||||||
|
- name: Roger
|
||||||
|
age: 44
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteAndAppendCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --autocreate=false --append --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: other # better than the original
|
||||||
|
b: [1, 2, 3, 4]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeArraysCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --append ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `[1, 2, 3, 4, 5]
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCmd_Multi(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge -d1 ../examples/multiple_docs_small.yaml ../examples/data1.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: Easy! as one two three
|
||||||
|
---
|
||||||
|
another:
|
||||||
|
document: here
|
||||||
|
a: simple # just the best
|
||||||
|
b:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
---
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: green
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `apples: red
|
||||||
|
something: good`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge -d* %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
apples: green
|
||||||
|
something: good
|
||||||
|
---
|
||||||
|
something: else
|
||||||
|
apples: red
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeSpecialCharacterKeysCmd(t *testing.T) {
|
||||||
|
content := ``
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `key[bracket]: value
|
||||||
|
key.bracket: value
|
||||||
|
key"value": value
|
||||||
|
key'value': value
|
||||||
|
`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, mergeContent, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
apples: green
|
||||||
|
---
|
||||||
|
something: else`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `apples: red
|
||||||
|
something: good`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --overwrite -d* %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
apples: red
|
||||||
|
something: good
|
||||||
|
---
|
||||||
|
something: good
|
||||||
|
apples: red
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlNullMapCmd(t *testing.T) {
|
||||||
|
content := `b:`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `b:
|
||||||
|
thing: a frog
|
||||||
|
`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, mergeContent, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCmd_Error(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to missing arg")
|
||||||
|
}
|
||||||
|
expectedOutput := `Must provide at least 1 yaml file`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCmd_ErrorUnreadableFile(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge ../examples/data1.yaml fake-unknown")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to unknown file")
|
||||||
|
}
|
||||||
|
var expectedOutput string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||||
|
} else {
|
||||||
|
expectedOutput = `open fake-unknown: no such file or directory`
|
||||||
|
}
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCmd_Inplace(t *testing.T) {
|
||||||
|
filename := test.WriteTempYamlFile(test.ReadTempYamlFile("../examples/data1.yaml"))
|
||||||
|
err := os.Chmod(filename, os.FileMode(int(0666)))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge -i %s ../examples/data2.yaml", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
info, _ := os.Stat(filename)
|
||||||
|
gotOutput := test.ReadTempYamlFile(filename)
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
toast: leave
|
||||||
|
tell: 1
|
||||||
|
tasty.taco: cool
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, gotOutput)
|
||||||
|
test.AssertResult(t, os.FileMode(int(0666)), info.Mode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeAllowEmptyTargetCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge ../examples/empty.yaml ../examples/data1.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeAllowEmptyMergeCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge ../examples/data1.yaml ../examples/empty.yaml")
|
||||||
|
expectedOutput := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
11
cmd/new.go
11
cmd/new.go
@@ -2,6 +2,7 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,11 +28,19 @@ 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(&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 updateCommands, updateCommandsError = readUpdateCommands(args, 2, "Must provide <path_to_update> <value>")
|
var badArgsMessage = "Must provide <path_to_update> <value>"
|
||||||
|
if len(args) != 2 {
|
||||||
|
return errors.New(badArgsMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage)
|
||||||
if updateCommandsError != nil {
|
if updateCommandsError != nil {
|
||||||
return updateCommandsError
|
return updateCommandsError
|
||||||
}
|
}
|
||||||
|
|||||||
101
cmd/new_test.go
Normal file
101
cmd/new_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c 3")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
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) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b[0] 3")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
- 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewCmd_Error(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to missing arg")
|
||||||
|
}
|
||||||
|
expectedOutput := `Must provide <path_to_update> <value>`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewWithTaggedStyleCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c cat --tag=!!str --style=tagged")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: !!str cat
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewWithDoubleQuotedStyleCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c cat --style=double")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: "cat"
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewWithSingleQuotedStyleCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "new b.c cat --style=single")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 'cat'
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
189
cmd/prefix_test.go
Normal file
189
cmd/prefix_test.go
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPrefixCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmdArray(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s [+].d.[+]", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `- d:
|
||||||
|
- b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_MultiLayer(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s d.e.f", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
e:
|
||||||
|
f:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixMultiCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
d:
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
func TestPrefixInvalidDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -df d", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `Document index f is not a integer or *: strconv.ParseInt: parsing "f": invalid syntax`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixBadDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `asked to process document index 1 but there are only 1 document(s)`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
func TestPrefixMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix %s -d * d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
d:
|
||||||
|
apples: great`
|
||||||
|
test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_Error(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "prefix")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to missing arg")
|
||||||
|
}
|
||||||
|
expectedOutput := `Must provide <filename> <prefixed_path>`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_ErrorUnreadableFile(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "prefix fake-unknown a.b")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to unknown file")
|
||||||
|
}
|
||||||
|
var expectedOutput string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||||
|
} else {
|
||||||
|
expectedOutput = `open fake-unknown: no such file or directory`
|
||||||
|
}
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_Inplace(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("prefix -i %s d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
gotOutput := test.ReadTempYamlFile(filename)
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3`
|
||||||
|
test.AssertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
|
||||||
|
}
|
||||||
11
cmd/read.go
11
cmd/read.go
@@ -26,7 +26,12 @@ yq r -- things.yaml '--key-starting-with-dashes.blah'
|
|||||||
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), p (paths), pv (path and value pairs)")
|
cmdRead.PersistentFlags().StringVarP(&printMode, "printMode", "p", "v", "print mode (v (values, default), p (paths), pv (path and value pairs)")
|
||||||
cmdRead.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
cmdRead.PersistentFlags().StringVarP(&defaultValue, "defaultValue", "D", "", "default value printed when there are no results")
|
||||||
|
cmdRead.PersistentFlags().BoolVarP(&printLength, "length", "l", false, "print length of results")
|
||||||
|
cmdRead.PersistentFlags().BoolVarP(&collectIntoArray, "collect", "c", false, "collect results into array")
|
||||||
|
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(&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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,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 {
|
||||||
|
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()
|
||||||
|
|||||||
1337
cmd/read_test.go
Normal file
1337
cmd/read_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,7 @@ func New() *cobra.Command {
|
|||||||
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print")
|
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print")
|
||||||
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
|
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
|
||||||
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&colorsEnabled, "colorsEnabled", "C", false, "enable colors")
|
rootCmd.PersistentFlags().BoolVarP(&colorsEnabled, "colors", "C", false, "print with colors")
|
||||||
|
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
createReadCmd(),
|
createReadCmd(),
|
||||||
@@ -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 bash-completion)
|
||||||
|
|
||||||
|
To configure your bash shell to load completions for each session add to
|
||||||
|
your bashrc
|
||||||
|
|
||||||
|
# ~/.bashrc or ~/.profile
|
||||||
|
. <(yq bash-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
|
||||||
|
}
|
||||||
184
cmd/utils.go
184
cmd/utils.go
@@ -77,8 +77,35 @@ func appendDocument(originalMatchingNodes []*yqlib.NodeContext, dataBucket yaml.
|
|||||||
return append(originalMatchingNodes, matchingNodes...), nil
|
return append(originalMatchingNodes, matchingNodes...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lengthOf(node *yaml.Node) int {
|
||||||
|
kindToCheck := node.Kind
|
||||||
|
if node.Kind == yaml.DocumentNode && len(node.Content) == 1 {
|
||||||
|
log.Debugf("length of document node, calculating length of child")
|
||||||
|
kindToCheck = node.Content[0].Kind
|
||||||
|
}
|
||||||
|
switch kindToCheck {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
return len(node.Value)
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return len(node.Content) / 2
|
||||||
|
default:
|
||||||
|
return len(node.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transforms node before printing, if required
|
||||||
|
func transformNode(node *yaml.Node) *yaml.Node {
|
||||||
|
if printLength {
|
||||||
|
return &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", lengthOf(node))}
|
||||||
|
}
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
func printNode(node *yaml.Node, writer io.Writer) error {
|
func printNode(node *yaml.Node, writer io.Writer) error {
|
||||||
var encoder yqlib.Encoder
|
var encoder yqlib.Encoder
|
||||||
|
if node.Kind == yaml.ScalarNode && unwrapScalar && !outputToJSON {
|
||||||
|
return writeString(writer, node.Value+"\n")
|
||||||
|
}
|
||||||
if outputToJSON {
|
if outputToJSON {
|
||||||
encoder = yqlib.NewJsonEncoder(writer, prettyPrint, indent)
|
encoder = yqlib.NewJsonEncoder(writer, prettyPrint, indent)
|
||||||
} else {
|
} else {
|
||||||
@@ -87,6 +114,22 @@ func printNode(node *yaml.Node, writer io.Writer) error {
|
|||||||
return encoder.Encode(node)
|
return encoder.Encode(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeComments(matchingNodes []*yqlib.NodeContext) {
|
||||||
|
for _, nodeContext := range matchingNodes {
|
||||||
|
removeCommentOfNode(nodeContext.Node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeCommentOfNode(node *yaml.Node) {
|
||||||
|
node.HeadComment = ""
|
||||||
|
node.LineComment = ""
|
||||||
|
node.FootComment = ""
|
||||||
|
|
||||||
|
for _, child := range node.Content {
|
||||||
|
removeCommentOfNode(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setStyle(matchingNodes []*yqlib.NodeContext, style yaml.Style) {
|
func setStyle(matchingNodes []*yqlib.NodeContext, style yaml.Style) {
|
||||||
for _, nodeContext := range matchingNodes {
|
for _, nodeContext := range matchingNodes {
|
||||||
updateStyleOfNode(nodeContext.Node, style)
|
updateStyleOfNode(nodeContext.Node, style)
|
||||||
@@ -106,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +242,10 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error {
|
|||||||
setStyle(matchingNodes, 0)
|
setStyle(matchingNodes, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if stripComments {
|
||||||
|
removeComments(matchingNodes)
|
||||||
|
}
|
||||||
|
|
||||||
//always explode anchors when printing json
|
//always explode anchors when printing json
|
||||||
if explodeAnchors || outputToJSON {
|
if explodeAnchors || outputToJSON {
|
||||||
errorExploding := explode(matchingNodes)
|
errorExploding := explode(matchingNodes)
|
||||||
@@ -152,6 +265,9 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var errorWriting error
|
var errorWriting error
|
||||||
|
|
||||||
|
var arrayCollection = yaml.Node{Kind: yaml.SequenceNode}
|
||||||
|
|
||||||
for _, mappedDoc := range matchingNodes {
|
for _, mappedDoc := range matchingNodes {
|
||||||
switch printMode {
|
switch printMode {
|
||||||
case "p":
|
case "p":
|
||||||
@@ -164,17 +280,27 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error {
|
|||||||
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)
|
||||||
parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: lib.PathStackToString(mappedDoc.PathStack)}
|
parentNode.Content[0] = &yaml.Node{Kind: yaml.ScalarNode, Value: lib.PathStackToString(mappedDoc.PathStack)}
|
||||||
parentNode.Content[1] = mappedDoc.Node
|
parentNode.Content[1] = transformNode(mappedDoc.Node)
|
||||||
if err := printNode(&parentNode, bufferedWriter); err != nil {
|
if collectIntoArray {
|
||||||
|
arrayCollection.Content = append(arrayCollection.Content, &parentNode)
|
||||||
|
} else if err := printNode(&parentNode, bufferedWriter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if err := printNode(mappedDoc.Node, bufferedWriter); err != nil {
|
if collectIntoArray {
|
||||||
|
arrayCollection.Content = append(arrayCollection.Content, mappedDoc.Node)
|
||||||
|
} else if err := printNode(transformNode(mappedDoc.Node), bufferedWriter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if collectIntoArray {
|
||||||
|
if err := printNode(transformNode(&arrayCollection), bufferedWriter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +417,7 @@ func updateDoc(inputFile string, updateCommands []yqlib.UpdateCommand, writer io
|
|||||||
func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
||||||
var destination io.Writer
|
var destination io.Writer
|
||||||
var destinationName string
|
var destinationName string
|
||||||
|
var completedSuccessfully = false
|
||||||
if writeInplace {
|
if writeInplace {
|
||||||
info, err := os.Stat(inputFile)
|
info, err := os.Stat(inputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -308,7 +435,9 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
|
|||||||
destination = tempFile
|
destination = tempFile
|
||||||
defer func() {
|
defer func() {
|
||||||
safelyCloseFile(tempFile)
|
safelyCloseFile(tempFile)
|
||||||
safelyRenameFile(tempFile.Name(), inputFile)
|
if completedSuccessfully {
|
||||||
|
safelyRenameFile(tempFile.Name(), inputFile)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
destination = stdOut
|
destination = stdOut
|
||||||
@@ -327,7 +456,9 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
|
|||||||
encoder = yqlib.NewYamlEncoder(bufferedWriter, indent, colorsEnabled)
|
encoder = yqlib.NewYamlEncoder(bufferedWriter, indent, colorsEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
return readStream(inputFile, mapYamlDecoder(updateData, encoder))
|
var errorProcessing = readStream(inputFile, mapYamlDecoder(updateData, encoder))
|
||||||
|
completedSuccessfully = errorProcessing == nil
|
||||||
|
return errorProcessing
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateCommandParsed struct {
|
type updateCommandParsed struct {
|
||||||
@@ -365,15 +496,20 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string)
|
|||||||
log.Debug("args %v", args[expectedArgs-2])
|
log.Debug("args %v", args[expectedArgs-2])
|
||||||
updateCommands = make([]yqlib.UpdateCommand, 1)
|
updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value.Content[0], Overwrite: true}
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value.Content[0], Overwrite: true}
|
||||||
|
} else if len(args) == expectedArgs {
|
||||||
} else if len(args) < expectedArgs {
|
|
||||||
return nil, errors.New(badArgsMessage)
|
|
||||||
} else {
|
|
||||||
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])
|
||||||
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), Overwrite: true}
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias), Overwrite: true}
|
||||||
|
} else if len(args) == expectedArgs-1 {
|
||||||
|
// don't update the value
|
||||||
|
updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||||
|
log.Debug("args %v", args)
|
||||||
|
log.Debug("path %v", args[expectedArgs-2])
|
||||||
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse("", customTag, customStyle, anchorName, makeAlias), Overwrite: true, DontUpdateNodeValue: true}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(badArgsMessage)
|
||||||
}
|
}
|
||||||
return updateCommands, nil
|
return updateCommands, nil
|
||||||
}
|
}
|
||||||
|
|||||||
31
cmd/validate_test.go
Normal file
31
cmd/validate_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "validate ../examples/sample.yaml b.c")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, "", result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateBadDataCmd(t *testing.T) {
|
||||||
|
content := `[!Whatever]`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("validate %s", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail")
|
||||||
|
}
|
||||||
|
expectedOutput := `yaml: line 1: did not find expected ',' or ']'`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
@@ -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.1.2"
|
Version = "3.3.1"
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ format is list of update commands (update or delete) like so:
|
|||||||
cmdWrite.PersistentFlags().StringVarP(&sourceYamlFile, "from", "f", "", "yaml file for updating yaml (as-is)")
|
cmdWrite.PersistentFlags().StringVarP(&sourceYamlFile, "from", "f", "", "yaml file for updating yaml (as-is)")
|
||||||
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(&anchorName, "anchorName", "", "", "anchor name")
|
||||||
|
cmdWrite.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name")
|
||||||
return cmdWrite
|
return cmdWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
593
cmd/write_test.go
Normal file
593
cmd/write_test.go
Normal file
@@ -0,0 +1,593 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v3/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWriteCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
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
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --tag=!!str --style=tagged", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: !!str cat
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteWithDoubleQuotedStyleCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=double", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: "cat"
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteUpdateStyleOnlyCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
d: things
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* --style=single", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 'dog'
|
||||||
|
d: 'things'
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteUpdateTagOnlyCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: true
|
||||||
|
d: false
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* --tag=!!str", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: "true"
|
||||||
|
d: "false"
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteWithSingleQuotedStyleCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=single", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 'cat'
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteWithLiteralStyleCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=literal", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: |-
|
||||||
|
cat
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteWithFoldedStyleCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: dog
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=folded", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: >-
|
||||||
|
cat
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteEmptyMultiDocCmd(t *testing.T) {
|
||||||
|
content := `# this is empty
|
||||||
|
---
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `c: 7
|
||||||
|
|
||||||
|
# this is empty
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteSurroundingEmptyMultiDocCmd(t *testing.T) {
|
||||||
|
content := `---
|
||||||
|
# empty
|
||||||
|
---
|
||||||
|
cat: frog
|
||||||
|
---
|
||||||
|
|
||||||
|
# empty
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -d1 c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `
|
||||||
|
|
||||||
|
# empty
|
||||||
|
---
|
||||||
|
cat: frog
|
||||||
|
c: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# empty
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteFromFileCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
source := `kittens: are cute # sure are!`
|
||||||
|
fromFilename := test.WriteTempYamlFile(source)
|
||||||
|
defer test.RemoveTempYamlFile(fromFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c -f %s", filename, fromFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c:
|
||||||
|
kittens: are cute # sure are!
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteEmptyCmd(t *testing.T) {
|
||||||
|
content := ``
|
||||||
|
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
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteAutoCreateCmd(t *testing.T) {
|
||||||
|
content := `applications:
|
||||||
|
- name: app
|
||||||
|
env:`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s applications[0].env.hello world", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `applications:
|
||||||
|
- name: app
|
||||||
|
env:
|
||||||
|
hello: world
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmdScript(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
updateScript := `- command: update
|
||||||
|
path: b.c
|
||||||
|
value: 7`
|
||||||
|
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: 7
|
||||||
|
`
|
||||||
|
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) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -d 1 apples ok", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: ok
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
func TestWriteInvalidDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -df apples ok", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `Document index f is not a integer or *: strconv.ParseInt: parsing "f": invalid syntax`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteBadDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -d 1 apples ok", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `asked to process document index 1 but there are only 1 document(s)`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
func TestWriteMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -d * apples ok", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
apples: ok
|
||||||
|
---
|
||||||
|
apples: ok`
|
||||||
|
test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_EmptyArray(t *testing.T) {
|
||||||
|
content := `b: 3`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s a []", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b: 3
|
||||||
|
a: []
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_Error(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "write")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to missing arg")
|
||||||
|
}
|
||||||
|
expectedOutput := `Must provide <filename> <path_to_update> <value>`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_ErrorUnreadableFile(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "write fake-unknown a.b 3")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to unknown file")
|
||||||
|
}
|
||||||
|
var expectedOutput string
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||||
|
} else {
|
||||||
|
expectedOutput = `open fake-unknown: no such file or directory`
|
||||||
|
}
|
||||||
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_Inplace(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write -i %s b.c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
gotOutput := test.ReadTempYamlFile(filename)
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 7`
|
||||||
|
test.AssertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_InplaceError(t *testing.T) {
|
||||||
|
content := `b: cat
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write -i %s b.c 7", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected Error to occur!")
|
||||||
|
}
|
||||||
|
gotOutput := test.ReadTempYamlFile(filename)
|
||||||
|
test.AssertResult(t, content, gotOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_Append(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
- foo
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
- foo
|
||||||
|
- 7
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_AppendInline(t *testing.T) {
|
||||||
|
content := `b: [foo]`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b: [foo, 7]
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_AppendInlinePretty(t *testing.T) {
|
||||||
|
content := `b: [foo]`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -P b[+] 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
- foo
|
||||||
|
- 7
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_AppendEmptyArray(t *testing.T) {
|
||||||
|
content := `a: 2
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] v", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: 2
|
||||||
|
b:
|
||||||
|
- v
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_SplatArray(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
- c: thing
|
||||||
|
- c: another thing
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b[*].c new", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
- c: new
|
||||||
|
- c: new
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_SplatMap(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: thing
|
||||||
|
d: another thing
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* new", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: new
|
||||||
|
d: new
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteCmd_SplatMapEmpty(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: thing
|
||||||
|
d: another thing
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c.* new", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: {}
|
||||||
|
d: another thing
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
10
debian/changelog
vendored
10
debian/changelog
vendored
@@ -1,3 +1,13 @@
|
|||||||
|
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
|
||||||
15
go.mod
15
go.mod
@@ -2,15 +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.3.2
|
github.com/goccy/go-yaml v1.7.5
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/spf13/cobra v1.0.0
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // 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-20200121175148-a6ecf24a6d71
|
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.14
|
||||||
|
|||||||
131
go.sum
131
go.sum
@@ -1,22 +1,58 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
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/goccy/go-yaml v1.3.2 h1:joykVKVARE+kQNoaj0ijjPY7lhgdovyU6etuYEl3hFU=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-yaml v1.3.2/go.mod h1:PsEEJ29nIFZL07P/c8dv4P6rQkVFFXafQee85U+ERHA=
|
github.com/goccy/go-yaml v1.7.5 h1:dWvj+p3BG11S/GlUzwzt1WZz0lhBTzTIDtmXT/ZOaPY=
|
||||||
|
github.com/goccy/go-yaml v1.7.5/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
||||||
|
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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
@@ -28,44 +64,104 @@ 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.6/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=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
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-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
||||||
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/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/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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
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/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
@@ -74,8 +170,11 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
|
|||||||
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
|
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
|
||||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
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-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
|
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,11 +271,22 @@ func (n *navigator) appendArray(value *yaml.Node, head interface{}, tail []inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *navigator) recurseArray(value *yaml.Node, index int64, head interface{}, tail []interface{}, pathStack []interface{}) error {
|
func (n *navigator) recurseArray(value *yaml.Node, index int64, head interface{}, tail []interface{}, pathStack []interface{}) error {
|
||||||
for int64(len(value.Content)) <= index {
|
var contentLength = int64(len(value.Content))
|
||||||
|
for contentLength <= index {
|
||||||
value.Content = append(value.Content, &yaml.Node{Kind: guessKind(head, tail, 0)})
|
value.Content = append(value.Content, &yaml.Node{Kind: guessKind(head, tail, 0)})
|
||||||
|
contentLength = int64(len(value.Content))
|
||||||
|
}
|
||||||
|
var indexToUse = index
|
||||||
|
|
||||||
|
if indexToUse < 0 {
|
||||||
|
indexToUse = contentLength + indexToUse
|
||||||
}
|
}
|
||||||
|
|
||||||
value.Content[index] = n.getOrReplace(value.Content[index], guessKind(head, tail, value.Content[index].Kind))
|
if indexToUse < 0 {
|
||||||
|
return fmt.Errorf("Index [%v] out of range, array size is %v", index, contentLength)
|
||||||
|
}
|
||||||
|
|
||||||
return n.doTraverse(value.Content[index], head, tail, append(pathStack, index))
|
value.Content[indexToUse] = n.getOrReplace(value.Content[indexToUse], guessKind(head, tail, value.Content[indexToUse].Kind))
|
||||||
|
|
||||||
|
return n.doTraverse(value.Content[indexToUse], head, tail, append(pathStack, index))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ func DeleteNavigationStrategy(pathElementToDelete interface{}) NavigationStrateg
|
|||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
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)
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ import (
|
|||||||
var log = logging.MustGetLogger("yq")
|
var log = logging.MustGetLogger("yq")
|
||||||
|
|
||||||
type UpdateCommand struct {
|
type UpdateCommand struct {
|
||||||
Command string
|
Command string
|
||||||
Path string
|
Path string
|
||||||
Value *yaml.Node
|
Value *yaml.Node
|
||||||
Overwrite bool
|
Overwrite bool
|
||||||
|
DontUpdateNodeValue bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func KindString(kind yaml.Kind) string {
|
func KindString(kind yaml.Kind) string {
|
||||||
@@ -47,7 +48,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,19 +35,22 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
type NavigationStrategyImpl struct {
|
type NavigationStrategyImpl struct {
|
||||||
followAlias func(nodeContext NodeContext) bool
|
followAlias func(nodeContext NodeContext) bool
|
||||||
autoCreateMap func(nodeContext NodeContext) bool
|
autoCreateMap func(nodeContext NodeContext) bool
|
||||||
visit func(nodeContext NodeContext) error
|
visit func(nodeContext NodeContext) error
|
||||||
shouldVisitExtraFn func(nodeContext NodeContext) bool
|
shouldVisitExtraFn func(nodeContext NodeContext) bool
|
||||||
shouldDeeplyTraverse func(nodeContext NodeContext) bool
|
shouldDeeplyTraverse func(nodeContext NodeContext) bool
|
||||||
visitedNodes []*NodeContext
|
shouldOnlyDeeplyVisitLeaves func(nodeContext NodeContext) bool
|
||||||
pathParser PathParser
|
visitedNodes []*NodeContext
|
||||||
|
pathParser PathParser
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) GetPathParser() PathParser {
|
func (ns *NavigationStrategyImpl) GetPathParser() PathParser {
|
||||||
@@ -70,6 +73,10 @@ func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext)
|
|||||||
return ns.shouldDeeplyTraverse(nodeContext)
|
return ns.shouldDeeplyTraverse(nodeContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool {
|
||||||
|
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext)
|
||||||
|
}
|
||||||
|
|
||||||
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 :/
|
||||||
if len(nodeContext.PathStack) == 0 {
|
if len(nodeContext.PathStack) == 0 {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PathParser interface {
|
type PathParser interface {
|
||||||
@@ -45,7 +47,7 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
|
|||||||
}
|
}
|
||||||
var headString = fmt.Sprintf("%v", head)
|
var headString = fmt.Sprintf("%v", head)
|
||||||
|
|
||||||
if strings.Contains(headString, "==") {
|
if strings.Contains(headString, "==") && nodeContext.Node.Kind != yaml.ScalarNode {
|
||||||
log.Debug("ooh deep recursion time")
|
log.Debug("ooh deep recursion time")
|
||||||
result := strings.SplitN(headString, "==", 2)
|
result := strings.SplitN(headString, "==", 2)
|
||||||
path := strings.TrimSpace(result[0])
|
path := strings.TrimSpace(result[0])
|
||||||
@@ -63,6 +65,14 @@ func (p *pathParser) MatchesNextPathElement(nodeContext NodeContext, nodeKey str
|
|||||||
}
|
}
|
||||||
log.Debug("done deep recursing, found %v matches", len(navigationStrategy.GetVisitedNodes()))
|
log.Debug("done deep recursing, found %v matches", len(navigationStrategy.GetVisitedNodes()))
|
||||||
return len(navigationStrategy.GetVisitedNodes()) > 0
|
return len(navigationStrategy.GetVisitedNodes()) > 0
|
||||||
|
} else if strings.Contains(headString, "==") && nodeContext.Node.Kind == yaml.ScalarNode {
|
||||||
|
result := strings.SplitN(headString, "==", 2)
|
||||||
|
path := strings.TrimSpace(result[0])
|
||||||
|
value := strings.TrimSpace(result[1])
|
||||||
|
if path == "." {
|
||||||
|
log.Debug("need to match scalar")
|
||||||
|
return matchesString(value, nodeContext.Node.Value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if head == "+" {
|
if head == "+" {
|
||||||
|
|||||||
@@ -26,5 +26,8 @@ func ReadNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy {
|
|||||||
}
|
}
|
||||||
return deeplyTraverseArrays || !isInArray
|
return deeplyTraverseArrays || !isInArray
|
||||||
},
|
},
|
||||||
|
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
shouldOnlyDeeplyVisitLeaves: 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
|
||||||
@@ -21,11 +24,15 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
DebugNode(node)
|
DebugNode(node)
|
||||||
log.Debug("with")
|
log.Debug("with")
|
||||||
DebugNode(changesToApply)
|
DebugNode(changesToApply)
|
||||||
node.Value = changesToApply.Value
|
if !updateCommand.DontUpdateNodeValue {
|
||||||
|
node.Value = changesToApply.Value
|
||||||
|
}
|
||||||
node.Tag = changesToApply.Tag
|
node.Tag = changesToApply.Tag
|
||||||
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
|
||||||
node.HeadComment = changesToApply.HeadComment
|
node.HeadComment = changesToApply.HeadComment
|
||||||
node.LineComment = changesToApply.LineComment
|
node.LineComment = changesToApply.LineComment
|
||||||
node.FootComment = changesToApply.FootComment
|
node.FootComment = changesToApply.FootComment
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type ValueParser interface {
|
type ValueParser interface {
|
||||||
Parse(argument string, customTag string) *yaml.Node
|
Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type valueParser struct {
|
type valueParser struct {
|
||||||
@@ -15,9 +15,32 @@ func NewValueParser() ValueParser {
|
|||||||
return &valueParser{}
|
return &valueParser{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *valueParser) Parse(argument string, customTag string) *yaml.Node {
|
func (v *valueParser) Parse(argument string, customTag string, customStyle string, anchorName string, createAlias bool) *yaml.Node {
|
||||||
if argument == "[]" {
|
var style yaml.Style
|
||||||
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode}
|
if customStyle == "tagged" {
|
||||||
|
style = yaml.TaggedStyle
|
||||||
|
} else if customStyle == "double" {
|
||||||
|
style = yaml.DoubleQuotedStyle
|
||||||
|
} else if customStyle == "single" {
|
||||||
|
style = yaml.SingleQuotedStyle
|
||||||
|
} else if customStyle == "literal" {
|
||||||
|
style = yaml.LiteralStyle
|
||||||
|
} else if customStyle == "folded" {
|
||||||
|
style = yaml.FoldedStyle
|
||||||
|
} else if customStyle == "flow" {
|
||||||
|
style = yaml.FlowStyle
|
||||||
|
} else if customStyle != "" {
|
||||||
|
log.Error("Unknown style %v, ignoring", customStyle)
|
||||||
}
|
}
|
||||||
return &yaml.Node{Value: argument, Tag: customTag, Kind: yaml.ScalarNode}
|
if argument == "[]" {
|
||||||
|
return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode, Style: style}
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := yaml.ScalarNode
|
||||||
|
|
||||||
|
if createAlias {
|
||||||
|
kind = yaml.AliasNode
|
||||||
|
}
|
||||||
|
|
||||||
|
return &yaml.Node{Value: argument, Tag: customTag, Kind: kind, Style: style, Anchor: anchorName}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,26 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var parseStyleTests = []struct {
|
||||||
|
customStyle string
|
||||||
|
expectedStyle yaml.Style
|
||||||
|
}{
|
||||||
|
{"", 0},
|
||||||
|
{"tagged", yaml.TaggedStyle},
|
||||||
|
{"double", yaml.DoubleQuotedStyle},
|
||||||
|
{"single", yaml.SingleQuotedStyle},
|
||||||
|
{"folded", yaml.FoldedStyle},
|
||||||
|
{"flow", yaml.FlowStyle},
|
||||||
|
{"literal", yaml.LiteralStyle},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValueParserStyleTag(t *testing.T) {
|
||||||
|
for _, tt := range parseStyleTests {
|
||||||
|
actual := NewValueParser().Parse("cat", "", tt.customStyle, "", false)
|
||||||
|
test.AssertResultWithContext(t, tt.expectedStyle, actual.Style, tt.customStyle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var parseValueTests = []struct {
|
var parseValueTests = []struct {
|
||||||
argument string
|
argument string
|
||||||
customTag string
|
customTag string
|
||||||
@@ -20,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)
|
||||||
@@ -28,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,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -ex
|
||||||
wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.23.1
|
go get golang.org/x/tools/cmd/goimports
|
||||||
go get golang.org/x/tools/cmd/goimports
|
wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.24.0
|
||||||
|
|||||||
@@ -7,3 +7,6 @@ gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}"
|
|||||||
# include non-default linux builds too
|
# include non-default linux builds too
|
||||||
gox -ldflags "${LDFLAGS}" -os=linux -output="build/yq_{{.OS}}_{{.Arch}}"
|
gox -ldflags "${LDFLAGS}" -os=linux -output="build/yq_{{.OS}}_{{.Arch}}"
|
||||||
|
|
||||||
|
cd build
|
||||||
|
rhash -r -a . -P -o checksums
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '3.1.2'
|
version: '3.3.1'
|
||||||
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.
|
||||||
|
|
||||||
|
base: core18
|
||||||
grade: stable # devel|stable. must be 'stable' to release into candidate/stable channels
|
grade: stable # devel|stable. must be 'stable' to release into candidate/stable channels
|
||||||
confinement: strict
|
confinement: strict
|
||||||
|
|
||||||
@@ -15,8 +16,7 @@ apps:
|
|||||||
parts:
|
parts:
|
||||||
yq:
|
yq:
|
||||||
plugin: go
|
plugin: go
|
||||||
|
go-channel: 1.14/stable
|
||||||
source: .
|
source: .
|
||||||
|
source-type: git
|
||||||
go-importpath: github.com/mikefarah/yq
|
go-importpath: github.com/mikefarah/yq
|
||||||
after: [go]
|
|
||||||
go:
|
|
||||||
source-tag: go1.11
|
|
||||||
|
|||||||
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