mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
160 Commits
4.0.0-alph
...
v4.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c15936bf3 | ||
|
|
b0735d8152 | ||
|
|
f17cbfd007 | ||
|
|
7b7ab70286 | ||
|
|
43165fa340 | ||
|
|
feda9f044d | ||
|
|
85629af59c | ||
|
|
5fc26e9453 | ||
|
|
07a6fa4df5 | ||
|
|
ec29ee7c14 | ||
|
|
24538c0cc7 | ||
|
|
61398bfd3a | ||
|
|
f7d95021c1 | ||
|
|
6bb8b1fb77 | ||
|
|
5e2c19cc86 | ||
|
|
30c269a66c | ||
|
|
70a1c60d7b | ||
|
|
e4d48bbc0d | ||
|
|
369ff94ad0 | ||
|
|
1c7fb14631 | ||
|
|
f4de5c4300 | ||
|
|
a72c14f06b | ||
|
|
5ed52aca66 | ||
|
|
5a5ac0dfef | ||
|
|
5a55869745 | ||
|
|
15e18bb98b | ||
|
|
644063646e | ||
|
|
aabed1a237 | ||
|
|
c12764dba8 | ||
|
|
1d5ecb244d | ||
|
|
7798a141cf | ||
|
|
b7583a538d | ||
|
|
529e88b630 | ||
|
|
658006eb93 | ||
|
|
2743a7e058 | ||
|
|
f95862fba3 | ||
|
|
3f58c4bc38 | ||
|
|
a7975df7cd | ||
|
|
3d5a5e0360 | ||
|
|
155755ae2f | ||
|
|
601c13531c | ||
|
|
69d00c89df | ||
|
|
2faff7b05f | ||
|
|
165949041d | ||
|
|
dbd7ab0f13 | ||
|
|
6d512ad718 | ||
|
|
4fef4a7ab1 | ||
|
|
dcb17b51a9 | ||
|
|
385417556d | ||
|
|
edb5f213d7 | ||
|
|
5cfd9b05ee | ||
|
|
0e764c59ce | ||
|
|
1b887e23b3 | ||
|
|
a76b72e691 | ||
|
|
9509831cff | ||
|
|
e92180e89d | ||
|
|
a6ae33c3f1 | ||
|
|
94a563dfd8 | ||
|
|
0328cfd619 | ||
|
|
88663a6ce3 | ||
|
|
b10a9ccfc6 | ||
|
|
9e9e15df73 | ||
|
|
6cc6fdf322 | ||
|
|
a88c2dc5d3 | ||
|
|
ea231006ed | ||
|
|
80f187f1a4 | ||
|
|
98e8b3479f | ||
|
|
eb539ff326 | ||
|
|
c09f7aa707 | ||
|
|
7f5c380d16 | ||
|
|
6a05e517f1 | ||
|
|
8ee6f7dc1a | ||
|
|
8bd54cd603 | ||
|
|
f2f7b6db0f | ||
|
|
e082fee5d4 | ||
|
|
412911561f | ||
|
|
52ae633cb7 | ||
|
|
9356ca59bb | ||
|
|
6dec167f74 | ||
|
|
00f6981314 | ||
|
|
4c60a2a967 | ||
|
|
f4529614c4 | ||
|
|
f059e13f94 | ||
|
|
4dbf158505 | ||
|
|
39a93a2836 | ||
|
|
7c158fce26 | ||
|
|
0bf43d2a55 | ||
|
|
1b0bce5da6 | ||
|
|
f112bde5fe | ||
|
|
e5aa4a87a4 | ||
|
|
f305e8fa12 | ||
|
|
d2d0c2c111 | ||
|
|
2aab79431c | ||
|
|
540d4953f5 | ||
|
|
7849232255 | ||
|
|
57cd67f055 | ||
|
|
6b17fd4fc1 | ||
|
|
ca8cd78616 | ||
|
|
9876b0ce8f | ||
|
|
a23272727d | ||
|
|
1fb37785d6 | ||
|
|
efb9027540 | ||
|
|
2577fe5425 | ||
|
|
f39c57fed9 | ||
|
|
1e8f755e7c | ||
|
|
bb088f6aa2 | ||
|
|
a96b74e779 | ||
|
|
09a9e1e7f0 | ||
|
|
db60746e4e | ||
|
|
8846255d1c | ||
|
|
a3e422ff76 | ||
|
|
2c3357702d | ||
|
|
c9dbf04da3 | ||
|
|
fbe53885ae | ||
|
|
da027f69d7 | ||
|
|
8cd290c00b | ||
|
|
363fe5d283 | ||
|
|
773b1a3517 | ||
|
|
cf4915d786 | ||
|
|
08f579f4e3 | ||
|
|
c9229439f7 | ||
|
|
9bc66c80b6 | ||
|
|
8de10e550d | ||
|
|
1258fa199e | ||
|
|
3a030651a3 | ||
|
|
3f48201a19 | ||
|
|
3cecb4e383 | ||
|
|
13679e51e2 | ||
|
|
f42728eef7 | ||
|
|
93136ba840 | ||
|
|
5665dc7b71 | ||
|
|
9302279dd2 | ||
|
|
5205f01248 | ||
|
|
0a66bb797d | ||
|
|
5972bb2f23 | ||
|
|
ec43f5e7c3 | ||
|
|
1ce30b25dc | ||
|
|
3d6a231722 | ||
|
|
3f04a1b52e | ||
|
|
aed598c736 | ||
|
|
e9fa873af8 | ||
|
|
064cff1341 | ||
|
|
fc3af441e5 | ||
|
|
e451119014 | ||
|
|
d38caf6bc2 | ||
|
|
4e385a1b93 | ||
|
|
356aac5a1f | ||
|
|
663413cd7a | ||
|
|
f03005f86d | ||
|
|
bc87aca8d7 | ||
|
|
62f262147c | ||
|
|
0259bb44c1 | ||
|
|
c08980e70f | ||
|
|
e07a5b6065 | ||
|
|
f69a81b79b | ||
|
|
9674acf684 | ||
|
|
ccb718cd0f | ||
|
|
815edef86a | ||
|
|
cd83d94b6a | ||
|
|
6afc2e9189 |
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
name: Bug report
|
name: Bug report - V3
|
||||||
about: Create a report to help us improve
|
about: Create a report to help us improve
|
||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels: bug, v3
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -10,11 +10,14 @@ assignees: ''
|
|||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
version of yq:
|
Note that any how to questions should be posted in the discussion board and not raised as an issue.
|
||||||
operating system:
|
|
||||||
|
Version of yq: 3.X.X
|
||||||
|
Operating system: mac/linux/windows/....
|
||||||
|
Installed via: docker/binary release/homebrew/snap/...
|
||||||
|
|
||||||
**Input Yaml**
|
**Input Yaml**
|
||||||
Concise yaml document(s) (as simple as possible to show the bug)
|
Concise yaml document(s) (as simple as possible to show the bug, please keep it to 10 lines or less)
|
||||||
data1.yml:
|
data1.yml:
|
||||||
```yaml
|
```yaml
|
||||||
this: should really work
|
this: should really work
|
||||||
51
.github/ISSUE_TEMPLATE/bug_report_v4.md
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug_report_v4.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
name: Bug report - V4
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: bug, v4
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
Note that any how to questions should be posted in the discussion board and not raised as an issue.
|
||||||
|
|
||||||
|
Version of yq: 4.X.X
|
||||||
|
Operating system: mac/linux/windows/....
|
||||||
|
Installed via: docker/binary release/homebrew/snap/...
|
||||||
|
|
||||||
|
**Input Yaml**
|
||||||
|
Concise yaml document(s) (as simple as possible to show the bug, please keep it to 10 lines or less)
|
||||||
|
data1.yml:
|
||||||
|
```yaml
|
||||||
|
this: should really work
|
||||||
|
```
|
||||||
|
|
||||||
|
data2.yml:
|
||||||
|
```yaml
|
||||||
|
but: it strangely didn't
|
||||||
|
```
|
||||||
|
|
||||||
|
**Command**
|
||||||
|
The command you ran:
|
||||||
|
```
|
||||||
|
yq eval-all 'select(fileIndex==0) | .a.b.c' data1.yml data2.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Actual behavior**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
cat: meow
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
this: should really work
|
||||||
|
but: it strangely didn't
|
||||||
|
```
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
16
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,17 +1,23 @@
|
|||||||
---
|
---
|
||||||
name: Feature request
|
name: Feature request - V4
|
||||||
about: Suggest an idea for this project
|
about: Suggest an idea for this project
|
||||||
title: ''
|
title: ''
|
||||||
labels: enhancement
|
labels: enhancement, v4
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Please describe your feature request.**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
A clear and concise description of what the request is and what it would solve.
|
||||||
|
Eg. I wish I could use yq to [...]
|
||||||
|
|
||||||
|
Note:
|
||||||
|
- how to questions should be posted in the discussion board and not raised as an issue.
|
||||||
|
- V3 will no longer have any enhancements.
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
If we have data1.yml like:
|
If we have data1.yml like:
|
||||||
|
(please keep to around 10 lines )
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
country: Australia
|
country: Australia
|
||||||
@@ -20,7 +26,7 @@ country: Australia
|
|||||||
And we run a command:
|
And we run a command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq predictWeather data1.yml
|
yq eval 'predictWeatherOf(.country)'
|
||||||
```
|
```
|
||||||
|
|
||||||
it could output
|
it could output
|
||||||
|
|||||||
3
.github/workflows/go.yml
vendored
3
.github/workflows/go.yml
vendored
@@ -28,7 +28,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
export PATH=${PATH}:`go env GOPATH`/bin
|
export PATH=${PATH}:`go env GOPATH`/bin
|
||||||
scripts/devtools.sh
|
scripts/devtools.sh
|
||||||
- name: Build
|
|
||||||
run: |
|
|
||||||
export PATH=${PATH}:`go env GOPATH`/bin
|
|
||||||
make local build
|
make local build
|
||||||
80
.github/workflows/release.yml
vendored
Normal file
80
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: Release YQ
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publishGitRelease:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: '^1.15'
|
||||||
|
- name: Cross compile
|
||||||
|
run: |
|
||||||
|
sudo apt-get install rhash -y
|
||||||
|
go get github.com/mitchellh/gox
|
||||||
|
./scripts/xcompile.sh
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1.0.0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: ${{ github.ref }}
|
||||||
|
draft: true
|
||||||
|
prerelease: false
|
||||||
|
|
||||||
|
- uses: shogo82148/actions-upload-release-asset@v1
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: build/*
|
||||||
|
|
||||||
|
publishDocker:
|
||||||
|
environment: dockerhub
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: mikefarah/yq
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Get latest release tag
|
||||||
|
uses: oprypin/find-latest-tag@v1
|
||||||
|
with:
|
||||||
|
repository: mikefarah/yq # The repository to scan.
|
||||||
|
releases-only: true # We know that all relevant tags have a GitHub release for them.
|
||||||
|
id: yq
|
||||||
|
|
||||||
|
- name: Clone source code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
ref: ${{ steps.yq.outputs.tag }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v1
|
||||||
|
with:
|
||||||
|
platforms: all
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
id: buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Available platforms
|
||||||
|
run: echo ${{ steps.buildx.outputs.platforms }} && docker version
|
||||||
|
|
||||||
|
- name: Build and push image
|
||||||
|
run: |
|
||||||
|
IMAGE_V_VERSION="$(git describe --tags --abbrev=0)"
|
||||||
|
IMAGE_VERSION=${IMAGE_V_VERSION:1}
|
||||||
|
|
||||||
|
SHORT_SHA1=$(git rev-parse --short HEAD)
|
||||||
|
PLATFORMS="linux/amd64,linux/ppc64le,linux/arm64"
|
||||||
|
echo "Building and pushing version ${IMAGE_VERSION} of image ${IMAGE_NAME}"
|
||||||
|
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
|
||||||
|
docker buildx build --platform "${PLATFORMS}" -t "${IMAGE_NAME}:${IMAGE_VERSION}" -t "${IMAGE_NAME}:latest" -t "${IMAGE_NAME}:4" \
|
||||||
|
--push .
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ RUN CGO_ENABLED=0 make local build
|
|||||||
|
|
||||||
# Choose alpine as a base image to make this useful for CI, as many
|
# Choose alpine as a base image to make this useful for CI, as many
|
||||||
# CI tools expect an interactive shell inside the container
|
# CI tools expect an interactive shell inside the container
|
||||||
FROM alpine:3.12 as production
|
FROM alpine:3.12.3 as production
|
||||||
|
|
||||||
COPY --from=builder /go/src/mikefarah/yq/yq /usr/bin/yq
|
COPY --from=builder /go/src/mikefarah/yq/yq /usr/bin/yq
|
||||||
RUN chmod +x /usr/bin/yq
|
RUN chmod +x /usr/bin/yq
|
||||||
@@ -22,4 +22,4 @@ LABEL version=${VERSION}
|
|||||||
|
|
||||||
WORKDIR /workdir
|
WORKDIR /workdir
|
||||||
|
|
||||||
ENTRYPOINT [/usr/bin/yq]
|
ENTRYPOINT ["/usr/bin/yq"]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ COPY scripts/devtools.sh /opt/devtools.sh
|
|||||||
|
|
||||||
RUN set -e -x \
|
RUN set -e -x \
|
||||||
&& /opt/devtools.sh
|
&& /opt/devtools.sh
|
||||||
|
ENV PATH=/go/bin:$PATH
|
||||||
|
|
||||||
# install mkdocs
|
# install mkdocs
|
||||||
RUN set -ex \
|
RUN set -ex \
|
||||||
|
|||||||
147
README.md
147
README.md
@@ -3,60 +3,88 @@
|
|||||||
   
|
   
|
||||||
|
|
||||||
|
|
||||||
a lightweight and portable command-line YAML processor
|
a lightweight and portable command-line YAML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
|
||||||
|
|
||||||
The aim of the project is to be the [jq](https://github.com/stedolan/jq) or sed of yaml files.
|
yq is written in go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as docker, all listed below.
|
||||||
|
|
||||||
|
## V4 released!
|
||||||
|
V4 is now officially released, it's quite different from V3 (sorry for the migration), however it is much more similar to ```jq```, using a similar expression syntax and therefore support much more complex functionality!
|
||||||
|
|
||||||
|
If you've been using v3 and want/need to upgrade, checkout the [upgrade guide](https://mikefarah.gitbook.io/yq/v/v4.x/upgrading-from-v3).
|
||||||
|
|
||||||
|
Support for v3 will cease August 2021, until then, critical bug and security fixes will still get applied if required.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
### [Download the latest binary](https://github.com/mikefarah/yq/releases/latest)
|
### [Download the latest binary](https://github.com/mikefarah/yq/releases/latest)
|
||||||
|
|
||||||
### MacOS:
|
### wget
|
||||||
|
Use wget to download the pre-compiled binaries:
|
||||||
|
|
||||||
|
#### Compressed via tar.gz
|
||||||
|
```bash
|
||||||
|
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\
|
||||||
|
tar xz && mv ${BINARY} /usr/bin/yq
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Plain binary
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq &&\
|
||||||
|
chmod +x /usr/bin/yq
|
||||||
|
```
|
||||||
|
|
||||||
|
For instance, VERSION=v4.2.0 and BINARY=yq_linux_amd64
|
||||||
|
|
||||||
|
### MacOS / Linux via Homebrew:
|
||||||
|
Using [Homebrew](https://brew.sh/)
|
||||||
```
|
```
|
||||||
brew install yq
|
brew install yq
|
||||||
```
|
```
|
||||||
|
|
||||||
### Ubuntu and other Linux distros supporting `snap` packages:
|
or, for the (deprecated) v3 version:
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install yq@3
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that for v3, as it is a versioned brew it will not add the `yq` command to your path automatically. Please follow the instructions given by brew upon installation.
|
||||||
|
|
||||||
|
### Linux via snap:
|
||||||
```
|
```
|
||||||
snap install yq
|
snap install yq
|
||||||
```
|
```
|
||||||
|
|
||||||
|
or, for the (deprecated) v3 version:
|
||||||
|
|
||||||
|
```
|
||||||
|
snap install yq --channel=v3/stable
|
||||||
|
```
|
||||||
|
|
||||||
#### Snap notes
|
#### Snap notes
|
||||||
`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:
|
`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 e '.a.path' -
|
||||||
```
|
```
|
||||||
|
|
||||||
And to write to a root file you can either use [sponge](https://linux.die.net/man/1/sponge):
|
And to write to a root file you can either use [sponge](https://linux.die.net/man/1/sponge):
|
||||||
```
|
```
|
||||||
sudo cat /etc/myfile | yq w - a.path value | sudo sponge /etc/myfile
|
sudo cat /etc/myfile | yq e '.a.path = "value"' - | sudo sponge /etc/myfile
|
||||||
```
|
```
|
||||||
or write to a temporary file:
|
or write to a temporary file:
|
||||||
```
|
```
|
||||||
sudo cat /etc/myfile | yq w - a.path value | sudo tee /etc/myfile.tmp
|
sudo cat /etc/myfile | yq e '.a.path = "value"' | sudo tee /etc/myfile.tmp
|
||||||
sudo mv /etc/myfile.tmp /etc/myfile
|
sudo mv /etc/myfile.tmp /etc/myfile
|
||||||
rm /etc/myfile.tmp
|
rm /etc/myfile.tmp
|
||||||
```
|
```
|
||||||
|
|
||||||
### wget
|
|
||||||
|
|
||||||
Use wget to download the pre-compiled binaries:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
wget https://github.com/mikefarah/yq/releases/download/{VERSION}/{BINARY} -O /usr/bin/yq &&\
|
|
||||||
chmod +x /usr/bin/yq
|
|
||||||
```
|
|
||||||
|
|
||||||
For instance, VERSION=3.4.0 and BINARY=yq_linux_amd64
|
|
||||||
|
|
||||||
|
|
||||||
### Run with Docker
|
### Run with Docker
|
||||||
|
|
||||||
#### 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 <command> [flags] [expression ]FILE...
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Run commands interactively:
|
#### Run commands interactively:
|
||||||
@@ -69,18 +97,26 @@ It can be useful to have a bash function to avoid typing the whole docker comman
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
yq() {
|
yq() {
|
||||||
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq yq "$@"
|
docker run --rm -i -v "${PWD}":/workdir mikefarah/yq "$@"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go Get:
|
### Go Get:
|
||||||
```
|
```
|
||||||
GO111MODULE=on go get github.com/mikefarah/yq/v3
|
GO111MODULE=on go get github.com/mikefarah/yq
|
||||||
```
|
```
|
||||||
|
|
||||||
## Community Supported Installation methods
|
## Community Supported Installation methods
|
||||||
As these are supported by the community :heart: - however, they may be out of date with the officially supported releases.
|
As these are supported by the community :heart: - however, they may be out of date with the officially supported releases.
|
||||||
|
|
||||||
|
# Webi
|
||||||
|
|
||||||
|
```
|
||||||
|
webi yq
|
||||||
|
```
|
||||||
|
|
||||||
|
See [webi](https://webinstall.dev/)
|
||||||
|
Supported by @adithyasunil26 (https://github.com/webinstall/webi-installers/tree/master/yq)
|
||||||
|
|
||||||
### Windows:
|
### Windows:
|
||||||
```
|
```
|
||||||
@@ -88,6 +124,14 @@ choco install yq
|
|||||||
```
|
```
|
||||||
Supported by @chillum (https://chocolatey.org/packages/yq)
|
Supported by @chillum (https://chocolatey.org/packages/yq)
|
||||||
|
|
||||||
|
### Mac:
|
||||||
|
Using [MacPorts](https://www.macports.org/)
|
||||||
|
```
|
||||||
|
sudo port selfupdate
|
||||||
|
sudo port install yq
|
||||||
|
```
|
||||||
|
Supported by @herbygillot (https://ports.macports.org/maintainer/github/herbygillot)
|
||||||
|
|
||||||
### Alpine Linux
|
### Alpine Linux
|
||||||
- Enable edge/community repo by adding ```$MIRROR/alpine/edge/community``` to ```/etc/apk/repositories```
|
- Enable edge/community repo by adding ```$MIRROR/alpine/edge/community``` to ```/etc/apk/repositories```
|
||||||
- Update database index with ```apk update```
|
- Update database index with ```apk update```
|
||||||
@@ -108,22 +152,18 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/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)
|
- Uses similar syntax as `jq` but works with YAML and JSON files
|
||||||
- [Deep read a yaml file with a given path expression](https://mikefarah.gitbook.io/yq/commands/read#basic)
|
- Fully supports multi document yaml files
|
||||||
- [List matching paths of a given path expression](https://mikefarah.gitbook.io/yq/commands/read#path-only)
|
- Colorized yaml output
|
||||||
- [Return the lengths of arrays/object/scalars](https://mikefarah.gitbook.io/yq/commands/read#printing-length-of-the-results)
|
- [Deeply traverse yaml](https://mikefarah.gitbook.io/yq/v/v4.x/traverse)
|
||||||
- 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)
|
- [Sort yaml by keys](https://mikefarah.gitbook.io/yq/v/v4.x/sort-keys)
|
||||||
- Update creates any missing entries in the path on the fly
|
- Manipulate yaml [comments](https://mikefarah.gitbook.io/yq/comment-operators), [styling](https://mikefarah.gitbook.io/yq/style), [tags](https://mikefarah.gitbook.io/yq/tag) and [anchors and aliases](https://mikefarah.gitbook.io/yq/anchor-and-alias-operators).
|
||||||
- Deeply [compare](https://mikefarah.gitbook.io/yq/commands/compare) yaml files
|
- [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
|
||||||
- Keeps yaml formatting and comments when updating
|
- [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/v/v4.x/select#select-and-update-matching-values-in-map)
|
||||||
- [Validate a yaml file](https://mikefarah.gitbook.io/yq/commands/validate)
|
- Keeps yaml formatting and comments when updating (though there are issues with whitespace)
|
||||||
- Create a yaml file given a [deep path and value](https://mikefarah.gitbook.io/yq/commands/create#creating-a-simple-yaml-file) or a [script file](https://mikefarah.gitbook.io/yq/commands/create#creating-using-a-create-script)
|
- [Convert to/from json to yaml](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert)
|
||||||
- [Prefix a path to a yaml file](https://mikefarah.gitbook.io/yq/commands/prefix)
|
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate)
|
||||||
- [Convert to/from json to yaml](https://mikefarah.gitbook.io/yq/usage/convert)
|
- [General shell completion scripts (bash/zsh/fish/powershell)](https://mikefarah.gitbook.io/yq/v/v4.x/commands/shell-completion)
|
||||||
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/commands/read#from-stdin)
|
|
||||||
- [Merge](https://mikefarah.gitbook.io/yq/commands/merge) multiple yaml files with various options for [overriding](https://mikefarah.gitbook.io/yq/commands/merge#overwrite-values) and [appending](https://mikefarah.gitbook.io/yq/commands/merge#append-values-with-arrays)
|
|
||||||
- Supports multiple documents in a single yaml file for [reading](https://mikefarah.gitbook.io/yq/commands/read#multiple-documents), [writing](https://mikefarah.gitbook.io/yq/commands/write-update#multiple-documents) and [merging](https://mikefarah.gitbook.io/yq/commands/merge#multiple-documents)
|
|
||||||
- General shell completion scripts (bash/zsh/fish/powershell) (https://mikefarah.gitbook.io/yq/commands/shell-completion)
|
|
||||||
|
|
||||||
## [Usage](https://mikefarah.gitbook.io/yq/)
|
## [Usage](https://mikefarah.gitbook.io/yq/)
|
||||||
|
|
||||||
@@ -135,32 +175,33 @@ Usage:
|
|||||||
yq [command]
|
yq [command]
|
||||||
|
|
||||||
Available Commands:
|
Available Commands:
|
||||||
compare yq x [--prettyPrint/-P] dataA.yaml dataB.yaml 'b.e(name==fr*).value'
|
eval Apply expression to each document in each yaml file given in sequence
|
||||||
delete yq d [--inplace/-i] [--doc/-d index] sample.yaml 'b.e(name==fred)'
|
eval-all Loads _all_ yaml documents of _all_ yaml files and runs expression once
|
||||||
help Help about any command
|
help Help about any command
|
||||||
merge yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--append/-a] sample.yaml sample2.yaml
|
shell-completion Generate completion script
|
||||||
new yq n [--script/-s script_file] a.b.c newValue
|
|
||||||
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
|
|
||||||
read yq r [--printMode/-p pv] sample.yaml 'b.e(name==fr*).value'
|
|
||||||
shell-completion Generates shell completion scripts
|
|
||||||
validate yq v sample.yaml
|
|
||||||
write yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue
|
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-C, --colors print with colors
|
-C, --colors force print with colors
|
||||||
|
-e, --exit-status set exit status if there are no matches or null or false is returned
|
||||||
-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
|
-i, --inplace update the yaml file inplace of first yaml file given.
|
||||||
-j, --tojson output as json. By default it prints a json document in one line, use the prettyPrint flag to print a formatted doc.
|
-M, --no-colors force print with no colors
|
||||||
|
-N, --no-doc Don't print document separators (---)
|
||||||
|
-n, --null-input Don't read input, simply evaluate the expression given. Useful for creating yaml docs from scratch.
|
||||||
|
-P, --prettyPrint pretty print, shorthand for '... style = ""'
|
||||||
|
-j, --tojson output as json. Set indent to 0 to print json in one line.
|
||||||
-v, --verbose verbose mode
|
-v, --verbose verbose mode
|
||||||
-V, --version Print version information and quit
|
-V, --version Print version information and quit
|
||||||
|
|
||||||
Use "yq [command] --help" for more information about a command.
|
Use "yq [command] --help" for more information about a command.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Upgrade from V2
|
Simple Example:
|
||||||
If you've been using v2 and want/need to upgrade, checkout the [upgrade guide](https://mikefarah.gitbook.io/yq/upgrading-from-v2).
|
|
||||||
|
```bash
|
||||||
|
yq e '.a.b | length' f1.yml f2.yml
|
||||||
|
```
|
||||||
|
|
||||||
## Known Issues / Missing Features
|
## Known Issues / Missing Features
|
||||||
- `yq` attempts to preserve comment positions and whitespace as much as possible, but it does not handle all scenarios (see https://github.com/go-yaml/yaml/tree/v3 for details)
|
- `yq` attempts to preserve comment positions and whitespace as much as possible, but it does not handle all scenarios (see https://github.com/go-yaml/yaml/tree/v3 for details)
|
||||||
- You cannot (yet) select multiple paths/keys from the yaml to be printed out (https://github.com/mikefarah/yq/issues/287)
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package cmd
|
|||||||
|
|
||||||
var unwrapScalar = true
|
var unwrapScalar = true
|
||||||
|
|
||||||
// var writeInplace = false
|
var writeInplace = false
|
||||||
var outputToJSON = false
|
var outputToJSON = false
|
||||||
|
|
||||||
// var exitStatus = false
|
var exitStatus = false
|
||||||
var forceColor = false
|
var forceColor = false
|
||||||
var forceNoColor = false
|
var forceNoColor = false
|
||||||
var colorsEnabled = false
|
var colorsEnabled = false
|
||||||
@@ -14,5 +14,6 @@ var noDocSeparators = false
|
|||||||
var nullInput = false
|
var nullInput = false
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var version = false
|
var version = false
|
||||||
|
var prettyPrint = false
|
||||||
|
|
||||||
// var log = logging.MustGetLogger("yq")
|
var completedSuccessfully = false
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||||
@@ -13,9 +15,8 @@ func createEvaluateAllCommand() *cobra.Command {
|
|||||||
Aliases: []string{"ea"},
|
Aliases: []string{"ea"},
|
||||||
Short: "Loads _all_ yaml documents of _all_ yaml files and runs expression once",
|
Short: "Loads _all_ yaml documents of _all_ yaml files and runs expression once",
|
||||||
Example: `
|
Example: `
|
||||||
yq es '.a.b | length' file1.yml file2.yml
|
# merges f2.yml into f1.yml (inplace)
|
||||||
yq es < sample.yaml
|
yq eval-all --inplace 'select(fileIndex == 0) * select(fileIndex == 1)' f1.yml f2.yml
|
||||||
yq es -n '{"a": "b"}'
|
|
||||||
`,
|
`,
|
||||||
Long: "Evaluate All:\nUseful when you need to run an expression across several yaml documents or files. Consumes more memory than eval",
|
Long: "Evaluate All:\nUseful when you need to run an expression across several yaml documents or files. Consumes more memory than eval",
|
||||||
RunE: evaluateAll,
|
RunE: evaluateAll,
|
||||||
@@ -23,6 +24,7 @@ yq es -n '{"a": "b"}'
|
|||||||
return cmdEvalAll
|
return cmdEvalAll
|
||||||
}
|
}
|
||||||
func evaluateAll(cmd *cobra.Command, args []string) error {
|
func evaluateAll(cmd *cobra.Command, args []string) error {
|
||||||
|
cmd.SilenceUsage = true
|
||||||
// 0 args, read std in
|
// 0 args, read std in
|
||||||
// 1 arg, null input, process expression
|
// 1 arg, null input, process expression
|
||||||
// 1 arg, read file in sequence
|
// 1 arg, read file in sequence
|
||||||
@@ -39,26 +41,54 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
|
|||||||
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
||||||
colorsEnabled = true
|
colorsEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if writeInplace && len(args) < 2 {
|
||||||
|
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeInplace {
|
||||||
|
// only use colors if its forced
|
||||||
|
colorsEnabled = forceColor
|
||||||
|
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[1])
|
||||||
|
out, err = writeInPlaceHandler.CreateTempFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// need to indirectly call the function so that completedSuccessfully is
|
||||||
|
// passed when we finish execution as opposed to now
|
||||||
|
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
|
||||||
|
}
|
||||||
|
|
||||||
|
if nullInput && len(args) > 1 {
|
||||||
|
return errors.New("Cannot pass files in when using null-input flag")
|
||||||
|
}
|
||||||
|
|
||||||
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||||
|
|
||||||
|
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = yqlib.EvaluateAllFileStreams("", []string{"-"}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], []string{}, printer)
|
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer)
|
||||||
} else {
|
} else {
|
||||||
err = yqlib.EvaluateAllFileStreams("", []string{args[0]}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], args[1:], printer)
|
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer)
|
||||||
|
}
|
||||||
|
|
||||||
|
completedSuccessfully = err == nil
|
||||||
|
|
||||||
|
if err == nil && exitStatus && !printer.PrintedAnything() {
|
||||||
|
return errors.New("no matches found")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
||||||
@@ -13,16 +15,36 @@ func createEvaluateSequenceCommand() *cobra.Command {
|
|||||||
Aliases: []string{"e"},
|
Aliases: []string{"e"},
|
||||||
Short: "Apply expression to each document in each yaml file given in sequence",
|
Short: "Apply expression to each document in each yaml file given in sequence",
|
||||||
Example: `
|
Example: `
|
||||||
yq es '.a.b | length' file1.yml file2.yml
|
# runs the expression against each file, in series
|
||||||
yq es < sample.yaml
|
yq e '.a.b | length' f1.yml f2.yml
|
||||||
yq es -n '{"a": "b"}'
|
|
||||||
|
# prints out the file
|
||||||
|
yq e sample.yaml
|
||||||
|
|
||||||
|
# prints a new yaml document
|
||||||
|
yq e -n '.a.b.c = "cat"'
|
||||||
|
|
||||||
|
|
||||||
|
# updates file.yaml directly
|
||||||
|
yq e '.a.b = "cool"' -i file.yaml
|
||||||
`,
|
`,
|
||||||
Long: "Evaluate Sequence:\nIterate over each yaml document, apply the expression and print the results, in sequence.",
|
Long: "Evaluate Sequence:\nIterate over each yaml document, apply the expression and print the results, in sequence.",
|
||||||
RunE: evaluateSequence,
|
RunE: evaluateSequence,
|
||||||
}
|
}
|
||||||
return cmdEvalSequence
|
return cmdEvalSequence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processExpression(expression string) string {
|
||||||
|
if prettyPrint && expression == "" {
|
||||||
|
return `... style=""`
|
||||||
|
} else if prettyPrint {
|
||||||
|
return fmt.Sprintf("%v | ... style= \"\"", expression)
|
||||||
|
}
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
func evaluateSequence(cmd *cobra.Command, args []string) error {
|
func evaluateSequence(cmd *cobra.Command, args []string) error {
|
||||||
|
cmd.SilenceUsage = true
|
||||||
// 0 args, read std in
|
// 0 args, read std in
|
||||||
// 1 arg, null input, process expression
|
// 1 arg, null input, process expression
|
||||||
// 1 arg, read file in sequence
|
// 1 arg, read file in sequence
|
||||||
@@ -39,26 +61,54 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
|||||||
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
|
||||||
colorsEnabled = true
|
colorsEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if writeInplace && len(args) < 2 {
|
||||||
|
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
|
||||||
|
}
|
||||||
|
|
||||||
|
if writeInplace {
|
||||||
|
// only use colors if its forced
|
||||||
|
colorsEnabled = forceColor
|
||||||
|
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[1])
|
||||||
|
out, err = writeInPlaceHandler.CreateTempFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// need to indirectly call the function so that completedSuccessfully is
|
||||||
|
// passed when we finish execution as opposed to now
|
||||||
|
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
|
||||||
|
}
|
||||||
|
|
||||||
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
|
||||||
|
|
||||||
|
streamEvaluator := yqlib.NewStreamEvaluator()
|
||||||
|
|
||||||
|
if nullInput && len(args) > 1 {
|
||||||
|
return errors.New("Cannot pass files in when using null-input flag")
|
||||||
|
}
|
||||||
|
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = yqlib.EvaluateFileStreamsSequence("", []string{"-"}, printer)
|
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer)
|
||||||
} else {
|
} else {
|
||||||
cmd.Println(cmd.UsageString())
|
cmd.Println(cmd.UsageString())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if nullInput {
|
if nullInput {
|
||||||
err = yqlib.EvaluateAllFileStreams(args[0], []string{}, printer)
|
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer)
|
||||||
} else {
|
} else {
|
||||||
err = yqlib.EvaluateFileStreamsSequence("", []string{args[0]}, printer)
|
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = yqlib.EvaluateFileStreamsSequence(args[0], args[1:], printer)
|
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
|
}
|
||||||
|
completedSuccessfully = err == nil
|
||||||
|
|
||||||
|
if err == nil && exitStatus && !printer.PrintedAnything() {
|
||||||
|
return errors.New("no matches found")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ func New() *cobra.Command {
|
|||||||
|
|
||||||
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(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
|
||||||
|
|
||||||
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
|
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
|
||||||
|
|||||||
@@ -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 = "4.0.0-alpha1"
|
Version = "4.3.2"
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
61
cmd/write.go
61
cmd/write.go
@@ -1,61 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "github.com/spf13/cobra"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func createWriteCmd() *cobra.Command {
|
|
||||||
// var cmdWrite = &cobra.Command{
|
|
||||||
// Use: "write [yaml_file] [path_expression] [value]",
|
|
||||||
// Aliases: []string{"w"},
|
|
||||||
// Short: "yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue",
|
|
||||||
// Example: `
|
|
||||||
// yq write things.yaml 'a.b.c' true
|
|
||||||
// yq write things.yaml 'a.*.c' true
|
|
||||||
// yq write things.yaml 'a.**' true
|
|
||||||
// yq write things.yaml 'a.(child.subchild==co*).c' true
|
|
||||||
// yq write things.yaml 'a.b.c' --tag '!!str' true # force 'true' to be interpreted as a string instead of bool
|
|
||||||
// yq write things.yaml 'a.b.c' --tag '!!float' 3
|
|
||||||
// yq write --inplace -- things.yaml 'a.b.c' '--cat' # need to use '--' to stop processing arguments as flags
|
|
||||||
// yq w -i things.yaml 'a.b.c' cat
|
|
||||||
// yq w -i -s update_script.yaml things.yaml
|
|
||||||
// yq w things.yaml 'a.b.d[+]' foo # appends a new node to the 'd' array
|
|
||||||
// yq w --doc 2 things.yaml 'a.b.d[+]' foo # updates the 3rd document of the yaml file
|
|
||||||
// `,
|
|
||||||
// Long: `Updates the yaml file w.r.t the given path and value.
|
|
||||||
// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
|
|
||||||
|
|
||||||
// Append value to array adds the value to the end of array.
|
|
||||||
|
|
||||||
// Update Scripts:
|
|
||||||
// Note that you can give an update script to perform more sophisticated update. Update script
|
|
||||||
// format is list of update commands (update or delete) like so:
|
|
||||||
// ---
|
|
||||||
// - command: update
|
|
||||||
// path: b.c
|
|
||||||
// value:
|
|
||||||
// #great
|
|
||||||
// things: frog # wow!
|
|
||||||
// - command: delete
|
|
||||||
// path: b.d
|
|
||||||
// `,
|
|
||||||
// RunE: writeProperty,
|
|
||||||
// }
|
|
||||||
// cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
|
||||||
// cmdWrite.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml")
|
|
||||||
// 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(&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
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func writeProperty(cmd *cobra.Command, args []string) error {
|
|
||||||
// var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>", true)
|
|
||||||
// if updateCommandsError != nil {
|
|
||||||
// return updateCommandsError
|
|
||||||
// }
|
|
||||||
// return updateDoc(args[0], updateCommands, cmd.OutOrStdout())
|
|
||||||
// }
|
|
||||||
@@ -1,610 +0,0 @@
|
|||||||
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 TestWriteKeepCommentsCmd(t *testing.T) {
|
|
||||||
// content := `b:
|
|
||||||
// c: 3 # comment
|
|
||||||
// `
|
|
||||||
// filename := test.WriteTempYamlFile(content)
|
|
||||||
// defer test.RemoveTempYamlFile(filename)
|
|
||||||
|
|
||||||
// cmd := getRootCommand()
|
|
||||||
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
|
|
||||||
// if result.Error != nil {
|
|
||||||
// t.Error(result.Error)
|
|
||||||
// }
|
|
||||||
// expectedOutput := `b:
|
|
||||||
// c: 7 # comment
|
|
||||||
// `
|
|
||||||
// test.AssertResult(t, expectedOutput, result.Output)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mikefarah/yq:3
|
FROM mikefarah/yq:4.3.2
|
||||||
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
|||||||
15
go.mod
15
go.mod
@@ -2,18 +2,15 @@ module github.com/mikefarah/yq/v4
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/elliotchance/orderedmap v1.3.0
|
github.com/elliotchance/orderedmap v1.3.0
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.10.0
|
||||||
github.com/goccy/go-yaml v1.8.1
|
github.com/goccy/go-yaml v1.8.4
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
github.com/jinzhu/copier v0.1.0
|
||||||
github.com/mattn/go-colorable v0.1.7 // indirect
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/spf13/cobra v1.0.0
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
|
||||||
github.com/timtadh/data-structures v0.5.3 // indirect
|
github.com/timtadh/data-structures v0.5.3 // indirect
|
||||||
github.com/timtadh/lexmachine v0.2.2
|
github.com/timtadh/lexmachine v0.2.2
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
|
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.15
|
go 1.15
|
||||||
|
|||||||
223
go.sum
223
go.sum
@@ -1,16 +1,33 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||||
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
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/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/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/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
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/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
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/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.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
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/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/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
@@ -22,37 +39,74 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
|
|||||||
github.com/elliotchance/orderedmap v1.3.0 h1:k6m77/d0zCXTjsk12nX40TkEBkSICq8T4s6R6bpCqU0=
|
github.com/elliotchance/orderedmap v1.3.0 h1:k6m77/d0zCXTjsk12nX40TkEBkSICq8T4s6R6bpCqU0=
|
||||||
github.com/elliotchance/orderedmap v1.3.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw=
|
github.com/elliotchance/orderedmap v1.3.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw=
|
||||||
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.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
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.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-yaml v1.8.1 h1:JuZRFlqLM5cWF6A+waL8AKVuCcqvKOuhJtUQI+L3ez0=
|
github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M=
|
||||||
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
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/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
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/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
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/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/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||||
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
|
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
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/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
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/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88=
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
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/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
@@ -64,26 +118,34 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
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.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.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
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/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
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/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
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_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-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
@@ -94,88 +156,164 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
|||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
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/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/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
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/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
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/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 v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
|
||||||
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.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
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/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/timtadh/data-structures v0.5.3 h1:F2tEjoG9qWIyUjbvXVgJqEOGJPMIiYn7U5W5mE+i/vQ=
|
github.com/timtadh/data-structures v0.5.3 h1:F2tEjoG9qWIyUjbvXVgJqEOGJPMIiYn7U5W5mE+i/vQ=
|
||||||
github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU=
|
github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU=
|
||||||
github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4PHmY=
|
github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4PHmY=
|
||||||
github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI=
|
github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
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/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=
|
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/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-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-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-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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/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.1-0.20180807135948-17ff2d5776d2/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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
|
||||||
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
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=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
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/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
@@ -183,6 +321,13 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
|||||||
66
pkg/yqlib/all_at_once_evaluator.go
Normal file
66
pkg/yqlib/all_at_once_evaluator.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A yaml expression evaluator that runs the expression once against all files/nodes in memory.
|
||||||
|
type Evaluator interface {
|
||||||
|
EvaluateFiles(expression string, filenames []string, printer Printer) error
|
||||||
|
|
||||||
|
// EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes
|
||||||
|
EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error)
|
||||||
|
|
||||||
|
// EvaluateCandidateNodes takes an expression and list of candidate nodes, returning a list of matching candidate nodes
|
||||||
|
EvaluateCandidateNodes(expression string, inputCandidateNodes *list.List) (*list.List, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type allAtOnceEvaluator struct {
|
||||||
|
treeNavigator DataTreeNavigator
|
||||||
|
treeCreator ExpressionParser
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAllAtOnceEvaluator() Evaluator {
|
||||||
|
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewExpressionParser()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
|
||||||
|
inputCandidates := list.New()
|
||||||
|
for _, node := range nodes {
|
||||||
|
inputCandidates.PushBack(&CandidateNode{Node: node})
|
||||||
|
}
|
||||||
|
return e.EvaluateCandidateNodes(expression, inputCandidates)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error) {
|
||||||
|
node, err := e.treeCreator.ParseExpression(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.treeNavigator.GetMatchingNodes(inputCandidates, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer) error {
|
||||||
|
fileIndex := 0
|
||||||
|
|
||||||
|
var allDocuments *list.List = list.New()
|
||||||
|
for _, filename := range filenames {
|
||||||
|
reader, err := readStream(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileDocuments, err := readDocuments(reader, filename, fileIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
allDocuments.PushBackList(fileDocuments)
|
||||||
|
fileIndex = fileIndex + 1
|
||||||
|
}
|
||||||
|
matches, err := e.EvaluateCandidateNodes(expression, allDocuments)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return printer.PrintResults(matches)
|
||||||
|
}
|
||||||
40
pkg/yqlib/all_at_once_evaluator_test.go
Normal file
40
pkg/yqlib/all_at_once_evaluator_test.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v4/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
var evaluateNodesScenario = []expressionScenario{
|
||||||
|
{
|
||||||
|
document: `a: hello`,
|
||||||
|
expression: `.a`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!str)::hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
document: `a: hello`,
|
||||||
|
expression: `.`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
document: `- a: "yes"`,
|
||||||
|
expression: `.[] | has("a")`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllAtOnceEvaluateNodes(t *testing.T) {
|
||||||
|
var evaluator = NewAllAtOnceEvaluator()
|
||||||
|
for _, tt := range evaluateNodesScenario {
|
||||||
|
node := test.ParseData(tt.document)
|
||||||
|
list, _ := evaluator.EvaluateNodes(tt.expression, &node)
|
||||||
|
test.AssertResultComplex(t, tt.expected, resultsToString(list))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,20 +6,45 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jinzhu/copier"
|
"github.com/jinzhu/copier"
|
||||||
"gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CandidateNode struct {
|
type CandidateNode struct {
|
||||||
Node *yaml.Node // the actual node
|
Node *yaml.Node // the actual node
|
||||||
Path []interface{} /// the path we took to get to this node
|
Path []interface{} /// the path we took to get to this node
|
||||||
Document uint // the document index of this node
|
Document uint // the document index of this node
|
||||||
Filename string
|
Filename string
|
||||||
|
FileIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *CandidateNode) GetKey() string {
|
func (n *CandidateNode) GetKey() string {
|
||||||
return fmt.Sprintf("%v - %v", n.Document, n.Path)
|
return fmt.Sprintf("%v - %v", n.Document, n.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *CandidateNode) CreateChild(path interface{}, node *yaml.Node) *CandidateNode {
|
||||||
|
return &CandidateNode{
|
||||||
|
Node: node,
|
||||||
|
Path: n.createChildPath(path),
|
||||||
|
Document: n.Document,
|
||||||
|
Filename: n.Filename,
|
||||||
|
FileIndex: n.FileIndex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
|
||||||
|
if path == nil {
|
||||||
|
newPath := make([]interface{}, len(n.Path))
|
||||||
|
copy(newPath, n.Path)
|
||||||
|
return newPath
|
||||||
|
}
|
||||||
|
|
||||||
|
//don't use append as they may actually modify the path of the orignal node!
|
||||||
|
newPath := make([]interface{}, len(n.Path)+1)
|
||||||
|
copy(newPath, n.Path)
|
||||||
|
newPath[len(n.Path)] = path
|
||||||
|
return newPath
|
||||||
|
}
|
||||||
|
|
||||||
func (n *CandidateNode) Copy() (*CandidateNode, error) {
|
func (n *CandidateNode) Copy() (*CandidateNode, error) {
|
||||||
clone := &CandidateNode{}
|
clone := &CandidateNode{}
|
||||||
err := copier.Copy(clone, n)
|
err := copier.Copy(clone, n)
|
||||||
@@ -31,10 +56,12 @@ func (n *CandidateNode) Copy() (*CandidateNode, error) {
|
|||||||
|
|
||||||
// updates this candidate from the given candidate node
|
// updates this candidate from the given candidate node
|
||||||
func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
|
func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
|
||||||
|
|
||||||
n.UpdateAttributesFrom(other)
|
n.UpdateAttributesFrom(other)
|
||||||
n.Node.Content = other.Node.Content
|
n.Node.Content = other.Node.Content
|
||||||
n.Node.Value = other.Node.Value
|
n.Node.Value = other.Node.Value
|
||||||
n.Node.Alias = other.Node.Alias
|
n.Node.Alias = other.Node.Alias
|
||||||
|
n.Node.Anchor = other.Node.Anchor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ func format(attr color.Attribute) string {
|
|||||||
return fmt.Sprintf("%s[%dm", escape, attr)
|
return fmt.Sprintf("%s[%dm", escape, attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ColorizeAndPrint(bytes []byte, writer io.Writer) error {
|
func colorizeAndPrint(yamlBytes []byte, writer io.Writer) error {
|
||||||
tokens := lexer.Tokenize(string(bytes))
|
tokens := lexer.Tokenize(string(yamlBytes))
|
||||||
var p printer.Printer
|
var p printer.Printer
|
||||||
p.Bool = func() *printer.Property {
|
p.Bool = func() *printer.Property {
|
||||||
return &printer.Property{
|
return &printer.Property{
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package yqlib
|
|
||||||
|
|
||||||
import "gopkg.in/op/go-logging.v1"
|
|
||||||
|
|
||||||
var log = logging.MustGetLogger("yq-lib")
|
|
||||||
@@ -5,44 +5,39 @@ import (
|
|||||||
|
|
||||||
"container/list"
|
"container/list"
|
||||||
|
|
||||||
"gopkg.in/op/go-logging.v1"
|
logging "gopkg.in/op/go-logging.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dataTreeNavigator struct {
|
|
||||||
navigationPrefs NavigationPrefs
|
|
||||||
}
|
|
||||||
|
|
||||||
type NavigationPrefs struct {
|
|
||||||
FollowAlias bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type DataTreeNavigator interface {
|
type DataTreeNavigator interface {
|
||||||
// given a list of CandidateEntities and a pathNode,
|
// given a list of CandidateEntities and a expressionNode,
|
||||||
// this will process the list against the given pathNode and return
|
// this will process the list against the given expressionNode and return
|
||||||
// a new list of matching candidates
|
// a new list of matching candidates
|
||||||
GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error)
|
GetMatchingNodes(matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDataTreeNavigator(navigationPrefs NavigationPrefs) DataTreeNavigator {
|
type dataTreeNavigator struct {
|
||||||
return &dataTreeNavigator{navigationPrefs}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func NewDataTreeNavigator() DataTreeNavigator {
|
||||||
if pathNode == nil {
|
return &dataTreeNavigator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dataTreeNavigator) GetMatchingNodes(matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
|
||||||
|
if expressionNode == nil {
|
||||||
log.Debugf("getMatchingNodes - nothing to do")
|
log.Debugf("getMatchingNodes - nothing to do")
|
||||||
return matchingNodes, nil
|
return matchingNodes, nil
|
||||||
}
|
}
|
||||||
log.Debugf("Processing Op: %v", pathNode.Operation.toString())
|
log.Debugf("Processing Op: %v", expressionNode.Operation.toString())
|
||||||
if log.IsEnabledFor(logging.DEBUG) {
|
if log.IsEnabledFor(logging.DEBUG) {
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
log.Debug(NodeToString(el.Value.(*CandidateNode)))
|
log.Debug(NodeToString(el.Value.(*CandidateNode)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Debug(">>")
|
log.Debug(">>")
|
||||||
handler := pathNode.Operation.OperationType.Handler
|
handler := expressionNode.Operation.OperationType.Handler
|
||||||
if handler != nil {
|
if handler != nil {
|
||||||
return handler(d, matchingNodes, pathNode)
|
return handler(d, matchingNodes, expressionNode)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("Unknown operator %v", pathNode.Operation.OperationType)
|
return nil, fmt.Errorf("Unknown operator %v", expressionNode.Operation.OperationType)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
1
pkg/yqlib/doc/.gitignore
vendored
Normal file
1
pkg/yqlib/doc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.zip
|
||||||
211
pkg/yqlib/doc/Add.md
Normal file
211
pkg/yqlib/doc/Add.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
Add behaves differently according to the type of the LHS:
|
||||||
|
- arrays: concatenate
|
||||||
|
- number scalars: arithmetic addition
|
||||||
|
- string scalars: concatenate
|
||||||
|
|
||||||
|
Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||||
|
|
||||||
|
## Concatenate and assign arrays
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
val: thing
|
||||||
|
b:
|
||||||
|
- cat
|
||||||
|
- dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.b += ["cow"]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
val: thing
|
||||||
|
b:
|
||||||
|
- cat
|
||||||
|
- dog
|
||||||
|
- cow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Concatenate arrays
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
b:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a + .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Concatenate null to array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a + null' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add new object to array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- dog: woof
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a + {"cat": "meow"}' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- dog: woof
|
||||||
|
- cat: meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add string to array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a + "hello"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- hello
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update array (append)
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
b:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a = .a + .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
b:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## String concatenation
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: meow
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a = .a + .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: catmeow
|
||||||
|
b: meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Relative string concatenation
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: meow
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a += .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: catmeow
|
||||||
|
b: meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Number addition - float
|
||||||
|
If the lhs or rhs are floats then the expression will be calculated with floats.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 3
|
||||||
|
b: 4.9
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a = .a + .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 7.9
|
||||||
|
b: 4.9
|
||||||
|
```
|
||||||
|
|
||||||
|
## Number addition - int
|
||||||
|
If both the lhs and rhs are ints then the expression will be calculated with ints.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 3
|
||||||
|
b: 4
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a = .a + .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 7
|
||||||
|
b: 4
|
||||||
|
```
|
||||||
|
|
||||||
|
## Increment number
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: 3
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a += 1' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 4
|
||||||
|
```
|
||||||
|
|
||||||
73
pkg/yqlib/doc/Alternative (Default value).md
Normal file
73
pkg/yqlib/doc/Alternative (Default value).md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
This operator is used to provide alternative (or default) values when a particular expression is either null or false.
|
||||||
|
|
||||||
|
## LHS is defined
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: bridge
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a // "hello"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
bridge
|
||||||
|
```
|
||||||
|
|
||||||
|
## LHS is not defined
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a // "hello"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
|
||||||
|
## LHS is null
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: ~
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a // "hello"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
|
||||||
|
## LHS is false
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: false
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a // "hello"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
hello
|
||||||
|
```
|
||||||
|
|
||||||
|
## RHS is an expression
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: false
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a // .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
cat
|
||||||
|
```
|
||||||
|
|
||||||
194
pkg/yqlib/doc/Anchor and Alias Operators.md
Normal file
194
pkg/yqlib/doc/Anchor and Alias Operators.md
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
Use the `alias` and `anchor` operators to read and write yaml aliases and anchors. The `explode` operator normalises a yaml file (dereference aliases and remove anchor names).
|
||||||
|
|
||||||
|
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
|
||||||
|
|
||||||
|
|
||||||
|
## Get anchor
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: &billyBob cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | anchor' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
billyBob
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set anchor
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a anchor = "foobar"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: &foobar cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set anchor relatively using assign-update
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a anchor |= .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: &cat
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get alias
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: &billyBob meow
|
||||||
|
a: *billyBob
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | alias' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
billyBob
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set alias
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: &meow purr
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a alias = "meow"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
b: &meow purr
|
||||||
|
a: *meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set alias relatively using assign-update
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: &meow purr
|
||||||
|
a:
|
||||||
|
f: meow
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a alias |= .f' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
b: &meow purr
|
||||||
|
a: *meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explode alias and anchor
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
f:
|
||||||
|
a: &a cat
|
||||||
|
b: *a
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'explode(.f)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
f:
|
||||||
|
a: cat
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explode with no aliases or anchors
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: mike
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'explode(.a)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: mike
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explode with alias keys
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
f:
|
||||||
|
a: &a cat
|
||||||
|
*a: b
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'explode(.f)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
f:
|
||||||
|
a: cat
|
||||||
|
cat: b
|
||||||
|
```
|
||||||
|
|
||||||
|
## Explode with merge anchors
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
foo: &foo
|
||||||
|
a: foo_a
|
||||||
|
thing: foo_thing
|
||||||
|
c: foo_c
|
||||||
|
bar: &bar
|
||||||
|
b: bar_b
|
||||||
|
thing: bar_thing
|
||||||
|
c: bar_c
|
||||||
|
foobarList:
|
||||||
|
b: foobarList_b
|
||||||
|
!!merge <<:
|
||||||
|
- *foo
|
||||||
|
- *bar
|
||||||
|
c: foobarList_c
|
||||||
|
foobar:
|
||||||
|
c: foobar_c
|
||||||
|
!!merge <<: *foo
|
||||||
|
thing: foobar_thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'explode(.)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
foo:
|
||||||
|
a: foo_a
|
||||||
|
thing: foo_thing
|
||||||
|
c: foo_c
|
||||||
|
bar:
|
||||||
|
b: bar_b
|
||||||
|
thing: bar_thing
|
||||||
|
c: bar_c
|
||||||
|
foobarList:
|
||||||
|
b: bar_b
|
||||||
|
a: foo_a
|
||||||
|
thing: bar_thing
|
||||||
|
c: foobarList_c
|
||||||
|
foobar:
|
||||||
|
c: foo_c
|
||||||
|
a: foo_a
|
||||||
|
thing: foobar_thing
|
||||||
|
```
|
||||||
|
|
||||||
@@ -5,8 +5,19 @@ Which will assign the LHS node values to the RHS node values. The RHS expression
|
|||||||
|
|
||||||
### relative form: `|=`
|
### relative form: `|=`
|
||||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
||||||
## Examples
|
## Create yaml file
|
||||||
### Update parent to be the child value
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '.a.b = "cat" | .x = "frog"'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: cat
|
||||||
|
x: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update node to be the child value
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -23,7 +34,28 @@ a:
|
|||||||
g: foof
|
g: foof
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update to be the sibling value
|
## Update node from another file
|
||||||
|
Note this will also work when the second file is a scalar (string/number)
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: apples
|
||||||
|
```
|
||||||
|
And another sample another.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: bob
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval-all 'select(fileIndex==0).a = select(fileIndex==1) | select(fileIndex==0)' sample.yml another.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: bob
|
||||||
|
```
|
||||||
|
|
||||||
|
## Update node to be the sibling value
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -40,7 +72,7 @@ a: sibling
|
|||||||
b: sibling
|
b: sibling
|
||||||
```
|
```
|
||||||
|
|
||||||
### Updated multiple paths
|
## Updated multiple paths
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: fieldA
|
a: fieldA
|
||||||
@@ -58,7 +90,7 @@ b: fieldB
|
|||||||
c: potatoe
|
c: potatoe
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update string value
|
## Update string value
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -74,7 +106,7 @@ a:
|
|||||||
b: frog
|
b: frog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update string value via |=
|
## Update string value via |=
|
||||||
Note there is no difference between `=` and `|=` when the RHS is a scalar
|
Note there is no difference between `=` and `|=` when the RHS is a scalar
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
@@ -92,7 +124,7 @@ a:
|
|||||||
b: frog
|
b: frog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update selected results
|
## Update selected results
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -101,7 +133,7 @@ a:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.a[] | select(. == "apple") |= "frog"' sample.yml
|
yq eval '(.a[] | select(. == "apple")) = "frog"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -110,7 +142,7 @@ a:
|
|||||||
c: cactus
|
c: cactus
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update array values
|
## Update array values
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
- candy
|
- candy
|
||||||
@@ -119,7 +151,7 @@ Given a sample.yml file of:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.[] | select(. == "*andy") |= "bogs"' sample.yml
|
yq eval '(.[] | select(. == "*andy")) = "bogs"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -128,10 +160,10 @@ will output
|
|||||||
- bogs
|
- bogs
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update empty object
|
## Update empty object
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
'': null
|
{}
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
@@ -139,25 +171,20 @@ yq eval '.a.b |= "bogs"' sample.yml
|
|||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
'': null
|
{a: {b: bogs}}
|
||||||
a:
|
|
||||||
b: bogs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update empty object and array
|
## Update empty object and array
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
'': null
|
{}
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.a.b[0] |= "bogs"' sample.yml
|
yq eval '.a.b.[0] |= "bogs"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
'': null
|
{a: {b: [bogs]}}
|
||||||
a:
|
|
||||||
b:
|
|
||||||
- bogs
|
|
||||||
```
|
```
|
||||||
|
|
||||||
113
pkg/yqlib/doc/Boolean Operators.md
Normal file
113
pkg/yqlib/doc/Boolean Operators.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
The `or` and `and` operators take two parameters and return a boolean result. `not` flips a boolean from true to false, or vice versa. These are most commonly used with the `select` operator to filter particular nodes.
|
||||||
|
## OR example
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input 'true or false'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## AND example
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input 'true and false'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Matching nodes with select, equals and or
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a: bird
|
||||||
|
b: dog
|
||||||
|
- a: frog
|
||||||
|
b: bird
|
||||||
|
- a: cat
|
||||||
|
b: fly
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a: bird
|
||||||
|
b: dog
|
||||||
|
- a: cat
|
||||||
|
b: fly
|
||||||
|
```
|
||||||
|
|
||||||
|
## Not true is false
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input 'true | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Not false is true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input 'false | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
|
## String values considered to be true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '"cat" | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Empty string value considered to be true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '"" | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Numbers are considered to be true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '1 | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zero is considered to be true
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '0 | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Null is considered to be false
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
yq eval --null-input '~ | not'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
@@ -3,17 +3,17 @@
|
|||||||
This creates an array using the expression between the square brackets.
|
This creates an array using the expression between the square brackets.
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Collect empty
|
||||||
### Collect empty
|
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '[]'
|
yq eval --null-input '[]'
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
[]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Collect single
|
## Collect single
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '["cat"]'
|
yq eval --null-input '["cat"]'
|
||||||
@@ -23,7 +23,7 @@ will output
|
|||||||
- cat
|
- cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Collect many
|
## Collect many
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
Use these comment operators to set or retrieve comments.
|
Use these comment operators to set or retrieve comments.
|
||||||
## Examples
|
## Set line comment
|
||||||
### Set line comment
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -14,7 +13,23 @@ will output
|
|||||||
a: cat # single
|
a: cat # single
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set head comment
|
## Use update assign to perform relative updates
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.. lineComment |= .' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat # cat
|
||||||
|
b: dog # dog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set head comment
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -30,7 +45,7 @@ will output
|
|||||||
a: cat
|
a: cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set foot comment, using an expression
|
## Set foot comment, using an expression
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -46,7 +61,7 @@ a: cat
|
|||||||
# cat
|
# cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Remove comment
|
## Remove comment
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat # comment
|
a: cat # comment
|
||||||
@@ -62,7 +77,7 @@ a: cat
|
|||||||
b: dog # leave this
|
b: dog # leave this
|
||||||
```
|
```
|
||||||
|
|
||||||
### Remove all comments
|
## Remove all comments
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat # comment
|
a: cat # comment
|
||||||
@@ -76,7 +91,7 @@ will output
|
|||||||
a: cat
|
a: cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get line comment
|
## Get line comment
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat # meow
|
a: cat # meow
|
||||||
@@ -90,7 +105,7 @@ will output
|
|||||||
meow
|
meow
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get head comment
|
## Get head comment
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat # meow
|
a: cat # meow
|
||||||
@@ -104,7 +119,7 @@ will output
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get foot comment
|
## Get foot comment
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat # meow
|
a: cat # meow
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents.
|
This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents.
|
||||||
## Examples
|
## Collect empty object
|
||||||
### Collect empty object
|
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '{}'
|
yq eval --null-input '{}'
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
{}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wrap (prefix) existing object
|
## Wrap (prefix) existing object
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
name: Mike
|
name: Mike
|
||||||
@@ -24,7 +24,7 @@ wrap:
|
|||||||
name: Mike
|
name: Mike
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using splat to create multiple objects
|
## Using splat to create multiple objects
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
name: Mike
|
name: Mike
|
||||||
@@ -34,7 +34,7 @@ pets:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '{.name: .pets[]}' sample.yml
|
yq eval '{.name: .pets.[]}' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -42,7 +42,7 @@ Mike: cat
|
|||||||
Mike: dog
|
Mike: dog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working with multiple documents
|
## Working with multiple documents
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
name: Mike
|
name: Mike
|
||||||
@@ -57,7 +57,7 @@ pets:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '{.name: .pets[]}' sample.yml
|
yq eval '{.name: .pets.[]}' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -67,7 +67,7 @@ Rosey: monkey
|
|||||||
Rosey: sheep
|
Rosey: sheep
|
||||||
```
|
```
|
||||||
|
|
||||||
### Creating yaml from scratch
|
## Creating yaml from scratch
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '{"wrap": "frog"}'
|
yq eval --null-input '{"wrap": "frog"}'
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
Deletes matching entries in maps or arrays.
|
|
||||||
## Examples
|
|
||||||
### Delete entry in map
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'del(.b)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
```
|
|
||||||
|
|
||||||
### Delete entry in array
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'del(.[1])' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- 1
|
|
||||||
- 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Delete no matches
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'del(.c)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
|
|
||||||
### Delete matching entries
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
b: dog
|
|
||||||
c: bat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'del( .[] | select(. == "*at") )' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
b: dog
|
|
||||||
```
|
|
||||||
|
|
||||||
117
pkg/yqlib/doc/Delete.md
Normal file
117
pkg/yqlib/doc/Delete.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
Deletes matching entries in maps or arrays.
|
||||||
|
## Delete entry in map
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.b)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete nested entry in map
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
a1: fred
|
||||||
|
a2: frood
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.a.a1)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
a2: frood
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete entry in array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.[1])' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- 1
|
||||||
|
- 3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete nested entry in array
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a: cat
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.[0].a)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- b: dog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete no matches
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.c)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete matching entries
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
c: bat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del( .[] | select(. == "*at") )' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
b: dog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recursively delete matching keys
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
name: frog
|
||||||
|
b:
|
||||||
|
name: blog
|
||||||
|
age: 12
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'del(.. | select(has("name")).name)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
age: 12
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
## Examples
|
|
||||||
### Retrieve a document index
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.a | documentIndex' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
0
|
|
||||||
---
|
|
||||||
1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Filter by document index
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'select(. | documentIndex == 1)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
|
|
||||||
### Print Document Index with matches
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: cat
|
|
||||||
---
|
|
||||||
a: frog
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.a | ({"match": ., "doc": (. | documentIndex)})' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
match: cat
|
|
||||||
doc: 0
|
|
||||||
match: frog
|
|
||||||
doc: 1
|
|
||||||
```
|
|
||||||
|
|
||||||
88
pkg/yqlib/doc/Document Index.md
Normal file
88
pkg/yqlib/doc/Document Index.md
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
Use the `documentIndex` operator (or the `di` shorthand) to select nodes of a particular document.
|
||||||
|
## Retrieve a document index
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
---
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | documentIndex' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
0
|
||||||
|
---
|
||||||
|
1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Retrieve a document index, shorthand
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
---
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | di' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
0
|
||||||
|
---
|
||||||
|
1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filter by document index
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
---
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'select(documentIndex == 1)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Filter by document index shorthand
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
---
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'select(di == 1)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Print Document Index with matches
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
---
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | ({"match": ., "doc": documentIndex})' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
match: cat
|
||||||
|
doc: 0
|
||||||
|
match: frog
|
||||||
|
doc: 1
|
||||||
|
```
|
||||||
|
|
||||||
78
pkg/yqlib/doc/Env Variable Operators.md
Normal file
78
pkg/yqlib/doc/Env Variable Operators.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
This operator is used to handle environment variables usage in path expressions. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read. Note that there are two forms, `env` which will parse the environment variable as a yaml (be it a map, array, string, number of boolean) and `strenv` which will always parse the argument as a string.
|
||||||
|
|
||||||
|
|
||||||
|
## Read string environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="cat meow" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat meow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read boolean environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="true" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read numeric environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="12" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read yaml environment variable
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="{b: fish}" yq eval --null-input '.a = env(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: {b: fish}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read boolean environment variable as a string
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="true" yq eval --null-input '.a = strenv(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read numeric environment variable as a string
|
||||||
|
Running
|
||||||
|
```bash
|
||||||
|
myenv="12" yq eval --null-input '.a = strenv(myenv)'
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: "12"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic key lookup with environment variable
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
cat: meow
|
||||||
|
dog: woof
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
myenv="cat" yq eval '.[env(myenv)]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
meow
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
## Equals Operator
|
|
||||||
|
|
||||||
This is a boolean operator that will return ```true``` if the LHS is equal to the RHS and ``false`` otherwise.
|
This is a boolean operator that will return ```true``` if the LHS is equal to the RHS and ``false`` otherwise.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -13,8 +11,7 @@ select(.a == .b)
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Match string
|
||||||
### Match string
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
- cat
|
- cat
|
||||||
@@ -32,7 +29,7 @@ true
|
|||||||
false
|
false
|
||||||
```
|
```
|
||||||
|
|
||||||
### Match number
|
## Match number
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
- 3
|
- 3
|
||||||
@@ -50,7 +47,7 @@ true
|
|||||||
false
|
false
|
||||||
```
|
```
|
||||||
|
|
||||||
### Match nulls
|
## Match nulls
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input 'null == ~'
|
yq eval --null-input 'null == ~'
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
Explodes (or dereferences) aliases and anchors.
|
|
||||||
## Examples
|
|
||||||
### Explode alias and anchor
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
f:
|
|
||||||
a: &a cat
|
|
||||||
b: *a
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'explode(.f)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
f:
|
|
||||||
a: cat
|
|
||||||
b: cat
|
|
||||||
```
|
|
||||||
|
|
||||||
### Explode with no aliases or anchors
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: mike
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'explode(.a)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: mike
|
|
||||||
```
|
|
||||||
|
|
||||||
### Explode with alias keys
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
f:
|
|
||||||
a: &a cat
|
|
||||||
*a: b
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'explode(.f)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
f:
|
|
||||||
a: cat
|
|
||||||
cat: b
|
|
||||||
```
|
|
||||||
|
|
||||||
### Explode with merge anchors
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
foo: &foo
|
|
||||||
a: foo_a
|
|
||||||
thing: foo_thing
|
|
||||||
c: foo_c
|
|
||||||
bar: &bar
|
|
||||||
b: bar_b
|
|
||||||
thing: bar_thing
|
|
||||||
c: bar_c
|
|
||||||
foobarList:
|
|
||||||
b: foobarList_b
|
|
||||||
!!merge <<:
|
|
||||||
- *foo
|
|
||||||
- *bar
|
|
||||||
c: foobarList_c
|
|
||||||
foobar:
|
|
||||||
c: foobar_c
|
|
||||||
!!merge <<: *foo
|
|
||||||
thing: foobar_thing
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval 'explode(.)' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
foo:
|
|
||||||
a: foo_a
|
|
||||||
thing: foo_thing
|
|
||||||
c: foo_c
|
|
||||||
bar:
|
|
||||||
b: bar_b
|
|
||||||
thing: bar_thing
|
|
||||||
c: bar_c
|
|
||||||
foobarList:
|
|
||||||
b: bar_b
|
|
||||||
a: foo_a
|
|
||||||
thing: bar_thing
|
|
||||||
c: foobarList_c
|
|
||||||
foobar:
|
|
||||||
c: foo_c
|
|
||||||
a: foo_a
|
|
||||||
thing: foobar_thing
|
|
||||||
```
|
|
||||||
|
|
||||||
51
pkg/yqlib/doc/File Operators.md
Normal file
51
pkg/yqlib/doc/File Operators.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
File operators are most often used with merge when needing to merge specific files together. Note that when doing this, you will need to use `eval-all` to ensure all yaml documents are loaded into memory before performing the merge (as opposed to `eval` which runs the expression once per document).
|
||||||
|
|
||||||
|
Note that the `fileIndex` operator has a short alias of `fi`.
|
||||||
|
|
||||||
|
## Merging files
|
||||||
|
Note the use of eval-all to ensure all documents are loaded into memory.
|
||||||
|
```bash
|
||||||
|
yq eval-all 'select(fi == 0) * select(filename == "file2.yaml")' file1.yaml file2.yaml
|
||||||
|
```
|
||||||
|
## Get filename
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'filename' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
sample.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get file index
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'fileIndex' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get file index alias
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'fi' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
0
|
||||||
|
```
|
||||||
|
|
||||||
44
pkg/yqlib/doc/Has.md
Normal file
44
pkg/yqlib/doc/Has.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
|
||||||
|
## Has map key
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- a: yes
|
||||||
|
- a: ~
|
||||||
|
- a:
|
||||||
|
- b: nope
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.[] | has("a")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Has array index
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- []
|
||||||
|
- [1]
|
||||||
|
- [1, 2]
|
||||||
|
- [1, null]
|
||||||
|
- [1, 2, 3]
|
||||||
|
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.[] | has(1)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
|
```
|
||||||
|
|
||||||
54
pkg/yqlib/doc/Length.md
Normal file
54
pkg/yqlib/doc/Length.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Returns the lengths of the nodes. Length is defined according to the type of the node.
|
||||||
|
|
||||||
|
## String length
|
||||||
|
returns length of string
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | length' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Map length
|
||||||
|
returns number of entries
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
c: dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'length' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Array length
|
||||||
|
returns number of elements
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
- 2
|
||||||
|
- 4
|
||||||
|
- 6
|
||||||
|
- 8
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'length' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
4
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
# Mulitply Operator
|
|
||||||
## Examples
|
|
||||||
### Merge objects together
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
{a: {also: me}, b: {also: {g: wizz}}}
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '. * {"a":.b}' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
{a: {also: {g: wizz}}, b: {also: {g: wizz}}}
|
|
||||||
```
|
|
||||||
### Merge keeps style of LHS
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
a: {things: great}
|
|
||||||
b:
|
|
||||||
also: "me"
|
|
||||||
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '. * {"a":.b}' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
a: {things: great, also: "me"}
|
|
||||||
b:
|
|
||||||
also: "me"
|
|
||||||
```
|
|
||||||
### Merge arrays
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
{a: [1,2,3], b: [3,4,5]}
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '. * {"a":.b}' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
{a: [3, 4, 5], b: [3, 4, 5]}
|
|
||||||
```
|
|
||||||
### Merge to prefix an element
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
{a: cat, b: dog}
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '. * {"a": {"c": .a}}' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
{a: {c: cat}, b: dog}
|
|
||||||
```
|
|
||||||
### Merge with simple aliases
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
{a: &cat {c: frog}, b: {f: *cat}, c: {g: thongs}}
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.c * .b' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
{g: thongs, f: *cat}
|
|
||||||
```
|
|
||||||
### Merge does not copy anchor names
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
{a: {c: &cat frog}, b: {f: *cat}, c: {g: thongs}}
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.c * .a' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
{g: thongs, c: frog}
|
|
||||||
```
|
|
||||||
### Merge with merge anchors
|
|
||||||
sample.yml:
|
|
||||||
```yaml
|
|
||||||
|
|
||||||
foo: &foo
|
|
||||||
a: foo_a
|
|
||||||
thing: foo_thing
|
|
||||||
c: foo_c
|
|
||||||
|
|
||||||
bar: &bar
|
|
||||||
b: bar_b
|
|
||||||
thing: bar_thing
|
|
||||||
c: bar_c
|
|
||||||
|
|
||||||
foobarList:
|
|
||||||
b: foobarList_b
|
|
||||||
<<: [*foo,*bar]
|
|
||||||
c: foobarList_c
|
|
||||||
|
|
||||||
foobar:
|
|
||||||
c: foobar_c
|
|
||||||
<<: *foo
|
|
||||||
thing: foobar_thing
|
|
||||||
|
|
||||||
```
|
|
||||||
Expression
|
|
||||||
```bash
|
|
||||||
yq '.foobar * .foobarList' < sample.yml
|
|
||||||
```
|
|
||||||
Result
|
|
||||||
```yaml
|
|
||||||
c: foobarList_c
|
|
||||||
<<: [*foo, *bar]
|
|
||||||
thing: foobar_thing
|
|
||||||
b: foobarList_b
|
|
||||||
```
|
|
||||||
@@ -2,9 +2,18 @@ Like the multiple operator in `jq`, depending on the operands, this multiply ope
|
|||||||
|
|
||||||
Upcoming versions of `yq` will add support for other types of multiplication (numbers, strings).
|
Upcoming versions of `yq` will add support for other types of multiplication (numbers, strings).
|
||||||
|
|
||||||
|
To concatenate when merging objects, use the `*+` form (see examples below). This will recursively merge objects, appending arrays when it encounters them.
|
||||||
|
|
||||||
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
||||||
## Examples
|
|
||||||
### Merge objects together, returning merged result only
|
## Merging files
|
||||||
|
Note the use of eval-all to ensure all documents are loaded into memory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Merge objects together, returning merged result only
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -27,7 +36,7 @@ fieldA: cat
|
|||||||
fieldB: dog
|
fieldB: dog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge objects together, returning parent object
|
## Merge objects together, returning parent object
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -55,12 +64,13 @@ b:
|
|||||||
fieldB: dog
|
fieldB: dog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge keeps style of LHS
|
## Merge keeps style of LHS
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: {things: great}
|
a: {things: great}
|
||||||
b:
|
b:
|
||||||
also: "me"
|
also: "me"
|
||||||
|
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
@@ -73,7 +83,7 @@ b:
|
|||||||
also: "me"
|
also: "me"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge arrays
|
## Merge arrays
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -101,7 +111,39 @@ b:
|
|||||||
- 5
|
- 5
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge to prefix an element
|
## Merge, appending arrays
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
array:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- animal: dog
|
||||||
|
value: coconut
|
||||||
|
b:
|
||||||
|
array:
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- animal: cat
|
||||||
|
value: banana
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a *+ .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
array:
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- animal: dog
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- animal: cat
|
||||||
|
value: banana
|
||||||
|
```
|
||||||
|
|
||||||
|
## Merge to prefix an element
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -118,7 +160,7 @@ a:
|
|||||||
b: dog
|
b: dog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge with simple aliases
|
## Merge with simple aliases
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: &cat
|
a: &cat
|
||||||
@@ -138,7 +180,7 @@ g: thongs
|
|||||||
f: *cat
|
f: *cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge does not copy anchor names
|
## Merge copies anchor names
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -155,10 +197,10 @@ yq eval '.c * .a' sample.yml
|
|||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
g: thongs
|
g: thongs
|
||||||
c: frog
|
c: &cat frog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Merge with merge anchors
|
## Merge with merge anchors
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
This is a boolean operator and will return `true` when given a `false` value (including null), and `false` otherwise.
|
|
||||||
## Examples
|
|
||||||
### Not true is false
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input 'true | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Not false is true
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input 'false | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
### String values considered to be true
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '"cat" | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Empty string value considered to be true
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '"" | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Numbers are considered to be true
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '1 | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Zero is considered to be true
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '0 | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
false
|
|
||||||
```
|
|
||||||
|
|
||||||
### Null is considered to be false
|
|
||||||
Running
|
|
||||||
```bash
|
|
||||||
yq eval --null-input '~ | not'
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
92
pkg/yqlib/doc/Path.md
Normal file
92
pkg/yqlib/doc/Path.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
The path operator can be used to get the traversal paths of matching nodes in an expression. The path is returned as an array, which if traversed in order will lead to the matching node.
|
||||||
|
|
||||||
|
You can get the key/index of matching nodes by using the `path` operator to return the path array then piping that through `.[-1]` to get the last element of that array, the key.
|
||||||
|
|
||||||
|
## Map path
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.b | path' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get map key
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.b | path | .[-1]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
b
|
||||||
|
```
|
||||||
|
|
||||||
|
## Array path
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- cat
|
||||||
|
- dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.[] | select(. == "dog") | path' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a
|
||||||
|
- 1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get array index
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- cat
|
||||||
|
- dog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
1
|
||||||
|
```
|
||||||
|
|
||||||
|
## Print path and value
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- cat
|
||||||
|
- dog
|
||||||
|
- frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- path:
|
||||||
|
- a
|
||||||
|
- 1
|
||||||
|
value: dog
|
||||||
|
- path:
|
||||||
|
- a
|
||||||
|
- 2
|
||||||
|
value: frog
|
||||||
|
```
|
||||||
|
|
||||||
35
pkg/yqlib/doc/Pipe.md
Normal file
35
pkg/yqlib/doc/Pipe.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Pipe the results of an expression into another. Like the bash operator.
|
||||||
|
|
||||||
|
## Simple Pipe
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a | .b' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multiple updates
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cow
|
||||||
|
b: sheep
|
||||||
|
c: same
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a = "cat" | .b = "dog"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: dog
|
||||||
|
c: same
|
||||||
|
```
|
||||||
|
|
||||||
154
pkg/yqlib/doc/Recursive Descent (Glob).md
Normal file
154
pkg/yqlib/doc/Recursive Descent (Glob).md
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
This operator recursively matches (or globs) all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
|
||||||
|
|
||||||
|
## match values form `..`
|
||||||
|
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
|
||||||
|
|
||||||
|
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '.. style= "flow"' file.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## match values and map keys form `...`
|
||||||
|
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
|
||||||
|
|
||||||
|
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '... style= "flow"' file.yaml
|
||||||
|
```
|
||||||
|
## Recurse map (values only)
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '..' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recursively find nodes with keys
|
||||||
|
Note that this example has wrapped the expression in `[]` to show that there are two matches returned. You do not have to wrap in `[]` in your path expression.
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
name: frog
|
||||||
|
b:
|
||||||
|
name: blog
|
||||||
|
age: 12
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '[.. | select(has("name"))]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- name: frog
|
||||||
|
b:
|
||||||
|
name: blog
|
||||||
|
age: 12
|
||||||
|
- name: blog
|
||||||
|
age: 12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recursively find nodes with values
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
nameA: frog
|
||||||
|
b:
|
||||||
|
nameB: frog
|
||||||
|
age: 12
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.. | select(. == "frog")' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
frog
|
||||||
|
frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Recurse map (values and keys)
|
||||||
|
Note that the map key appears in the results
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '...' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: frog
|
||||||
|
a
|
||||||
|
frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Aliases are not traversed
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: &cat
|
||||||
|
c: frog
|
||||||
|
b: *cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '[..]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- a: &cat
|
||||||
|
c: frog
|
||||||
|
b: *cat
|
||||||
|
- &cat
|
||||||
|
c: frog
|
||||||
|
- frog
|
||||||
|
- *cat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Merge docs are not traversed
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
foo: &foo
|
||||||
|
a: foo_a
|
||||||
|
thing: foo_thing
|
||||||
|
c: foo_c
|
||||||
|
bar: &bar
|
||||||
|
b: bar_b
|
||||||
|
thing: bar_thing
|
||||||
|
c: bar_c
|
||||||
|
foobarList:
|
||||||
|
b: foobarList_b
|
||||||
|
!!merge <<:
|
||||||
|
- *foo
|
||||||
|
- *bar
|
||||||
|
c: foobarList_c
|
||||||
|
foobar:
|
||||||
|
c: foobar_c
|
||||||
|
!!merge <<: *foo
|
||||||
|
thing: foobar_thing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.foobar | [..]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
- c: foobar_c
|
||||||
|
!!merge <<: *foo
|
||||||
|
thing: foobar_thing
|
||||||
|
- foobar_c
|
||||||
|
- *foo
|
||||||
|
- foobar_thing
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches, for instance to set the `style` of all nodes in a yaml doc:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yq eval '.. style= "flow"' file.yaml
|
|
||||||
```
|
|
||||||
## Examples
|
|
||||||
### Map
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a:
|
|
||||||
b: apple
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a:
|
|
||||||
b: apple
|
|
||||||
b: apple
|
|
||||||
apple
|
|
||||||
```
|
|
||||||
|
|
||||||
### Array
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
1
|
|
||||||
2
|
|
||||||
3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Array of maps
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
- a: cat
|
|
||||||
- 2
|
|
||||||
- true
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
- a: cat
|
|
||||||
- 2
|
|
||||||
- true
|
|
||||||
a: cat
|
|
||||||
cat
|
|
||||||
2
|
|
||||||
true
|
|
||||||
```
|
|
||||||
|
|
||||||
### Aliases are not traversed
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
a: &cat
|
|
||||||
c: frog
|
|
||||||
b: *cat
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
a: &cat
|
|
||||||
c: frog
|
|
||||||
b: *cat
|
|
||||||
&cat
|
|
||||||
c: frog
|
|
||||||
frog
|
|
||||||
*cat
|
|
||||||
```
|
|
||||||
|
|
||||||
### Merge docs are not traversed
|
|
||||||
Given a sample.yml file of:
|
|
||||||
```yaml
|
|
||||||
foo: &foo
|
|
||||||
a: foo_a
|
|
||||||
thing: foo_thing
|
|
||||||
c: foo_c
|
|
||||||
bar: &bar
|
|
||||||
b: bar_b
|
|
||||||
thing: bar_thing
|
|
||||||
c: bar_c
|
|
||||||
foobarList:
|
|
||||||
b: foobarList_b
|
|
||||||
!!merge <<:
|
|
||||||
- *foo
|
|
||||||
- *bar
|
|
||||||
c: foobarList_c
|
|
||||||
foobar:
|
|
||||||
c: foobar_c
|
|
||||||
!!merge <<: *foo
|
|
||||||
thing: foobar_thing
|
|
||||||
```
|
|
||||||
then
|
|
||||||
```bash
|
|
||||||
yq eval '.foobar | ..' sample.yml
|
|
||||||
```
|
|
||||||
will output
|
|
||||||
```yaml
|
|
||||||
c: foobar_c
|
|
||||||
!!merge <<: *foo
|
|
||||||
thing: foobar_thing
|
|
||||||
foobar_c
|
|
||||||
*foo
|
|
||||||
foobar_thing
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
Select is used to filter arrays and maps by a boolean expression.
|
Select is used to filter arrays and maps by a boolean expression.
|
||||||
## Examples
|
## Select elements from array
|
||||||
### Select elements from array
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
- cat
|
- cat
|
||||||
@@ -17,7 +16,7 @@ cat
|
|||||||
goat
|
goat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Select and update matching values in map
|
## Select and update matching values in map
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -27,7 +26,7 @@ a:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '(.a[] | select(. == "*at")) |= "rabbit"' sample.yml
|
yq eval '(.a.[] | select(. == "*at")) |= "rabbit"' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
68
pkg/yqlib/doc/Sort Keys.md
Normal file
68
pkg/yqlib/doc/Sort Keys.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
The Sort Keys operator sorts maps by their keys (based on their string value). This operator does not do anything to arrays or scalars (so you can easily recursively apply it to all maps).
|
||||||
|
|
||||||
|
Sort is particularly useful for diffing two different yaml documents:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval -i 'sortKeys(..)' file1.yml
|
||||||
|
yq eval -i 'sortKeys(..)' file2.yml
|
||||||
|
diff file1.yml file2.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sort keys of map
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
c: frog
|
||||||
|
a: blah
|
||||||
|
b: bing
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'sortKeys(.)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: blah
|
||||||
|
b: bing
|
||||||
|
c: frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sort keys recursively
|
||||||
|
Note the array elements are left unsorted, but maps inside arrays are sorted
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
bParent:
|
||||||
|
c: dog
|
||||||
|
array:
|
||||||
|
- 3
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
aParent:
|
||||||
|
z: donkey
|
||||||
|
x:
|
||||||
|
- c: yum
|
||||||
|
b: delish
|
||||||
|
- b: ew
|
||||||
|
a: apple
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval 'sortKeys(..)' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
aParent:
|
||||||
|
x:
|
||||||
|
- b: delish
|
||||||
|
c: yum
|
||||||
|
- a: apple
|
||||||
|
b: ew
|
||||||
|
z: donkey
|
||||||
|
bParent:
|
||||||
|
array:
|
||||||
|
- 3
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
c: dog
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style)
|
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style)
|
||||||
## Examples
|
## Set tagged style
|
||||||
### Set tagged style
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -21,7 +20,7 @@ c: !!float 3.2
|
|||||||
e: !!bool true
|
e: !!bool true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set double quote style
|
## Set double quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -41,7 +40,27 @@ c: "3.2"
|
|||||||
e: "true"
|
e: "true"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set single quote style
|
## Set double quote style on map keys too
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: cat
|
||||||
|
b: 5
|
||||||
|
c: 3.2
|
||||||
|
e: true
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '... style="double"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
"a": "cat"
|
||||||
|
"b": "5"
|
||||||
|
"c": "3.2"
|
||||||
|
"e": "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set single quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -61,7 +80,7 @@ c: '3.2'
|
|||||||
e: 'true'
|
e: 'true'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set literal quote style
|
## Set literal quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -85,7 +104,7 @@ e: |-
|
|||||||
true
|
true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set folded quote style
|
## Set folded quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -109,7 +128,7 @@ e: >-
|
|||||||
true
|
true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set flow quote style
|
## Set flow quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -126,17 +145,19 @@ will output
|
|||||||
{a: cat, b: 5, c: 3.2, e: true}
|
{a: cat, b: 5, c: 3.2, e: true}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set empty (default) quote style
|
## Reset style - or pretty print
|
||||||
|
Set empty (default) quote style, note the usage of `...` to match keys too. Note that there is a `--prettyPrint/-P` short flag for this.
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
b: 5
|
"b": 5
|
||||||
c: 3.2
|
'c': 3.2
|
||||||
e: true
|
"e": true
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.. style=""' sample.yml
|
yq eval '... style=""' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -146,11 +167,26 @@ c: 3.2
|
|||||||
e: true
|
e: true
|
||||||
```
|
```
|
||||||
|
|
||||||
### Read style
|
## Set style relatively with assign-update
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: single
|
||||||
b: thing
|
b: double
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.[] style |= .' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: 'single'
|
||||||
|
b: "double"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read style
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
{a: "cat", b: 'thing'}
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
@@ -158,8 +194,8 @@ yq eval '.. | style' sample.yml
|
|||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
flow
|
||||||
|
double
|
||||||
|
single
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
The tag operator can be used to get or set the tag of ndoes (e.g. `!!str`, `!!int`, `!!bool`).
|
The tag operator can be used to get or set the tag of nodes (e.g. `!!str`, `!!int`, `!!bool`).
|
||||||
## Examples
|
## Get tag
|
||||||
### Get tag
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -23,7 +22,21 @@ will output
|
|||||||
!!seq
|
!!seq
|
||||||
```
|
```
|
||||||
|
|
||||||
### Convert numbers to strings
|
## Set custom tag
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a: str
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a tag = "!!mikefarah"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a: !!mikefarah str
|
||||||
|
```
|
||||||
|
|
||||||
|
## Find numbers and convert them to strings
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: cat
|
a: cat
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
This is the simples (and perhaps most used) operator, it is used to navigate deeply into yaml structurse.
|
This is the simplest (and perhaps most used) operator, it is used to navigate deeply into yaml structurse.
|
||||||
## Examples
|
## Simple map navigation
|
||||||
### Simple map navigation
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -15,7 +14,7 @@ will output
|
|||||||
b: apple
|
b: apple
|
||||||
```
|
```
|
||||||
|
|
||||||
### Splat
|
## Splat
|
||||||
Often used to pipe children into other operators
|
Often used to pipe children into other operators
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
@@ -33,7 +32,41 @@ b: apple
|
|||||||
c: banana
|
c: banana
|
||||||
```
|
```
|
||||||
|
|
||||||
### Children don't exist
|
## Special characters
|
||||||
|
Use quotes around path elements with special characters
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
"{}": frog
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '."{}"' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
frog
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic keys
|
||||||
|
Expressions within [] can be used to dynamically lookup / calculate keys
|
||||||
|
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
b: apple
|
||||||
|
apple: crispy yum
|
||||||
|
banana: soft yum
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.[.b]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
crispy yum
|
||||||
|
```
|
||||||
|
|
||||||
|
## Children don't exist
|
||||||
Nodes are added dynamically while traversing
|
Nodes are added dynamically while traversing
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
@@ -49,7 +82,7 @@ will output
|
|||||||
null
|
null
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wildcard matching
|
## Wildcard matching
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a:
|
a:
|
||||||
@@ -66,7 +99,7 @@ apple
|
|||||||
things
|
things
|
||||||
```
|
```
|
||||||
|
|
||||||
### Aliases
|
## Aliases
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: &cat
|
a: &cat
|
||||||
@@ -82,7 +115,7 @@ will output
|
|||||||
*cat
|
*cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing aliases with splat
|
## Traversing aliases with splat
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: &cat
|
a: &cat
|
||||||
@@ -91,14 +124,14 @@ b: *cat
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.b.[]' sample.yml
|
yq eval '.b[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
frog
|
frog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing aliases explicitly
|
## Traversing aliases explicitly
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: &cat
|
a: &cat
|
||||||
@@ -114,7 +147,7 @@ will output
|
|||||||
frog
|
frog
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing arrays by index
|
## Traversing arrays by index
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
- 1
|
- 1
|
||||||
@@ -123,42 +156,42 @@ Given a sample.yml file of:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '[0]' sample.yml
|
yq eval '.[0]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
1
|
1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Maps with numeric keys
|
## Maps with numeric keys
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
2: cat
|
2: cat
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '[2]' sample.yml
|
yq eval '.[2]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
cat
|
cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Maps with non existing numeric keys
|
## Maps with non existing numeric keys
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: b
|
a: b
|
||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '[0]' sample.yml
|
yq eval '.[0]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
null
|
null
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing merge anchors
|
## Traversing merge anchors
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -189,7 +222,7 @@ will output
|
|||||||
foo_a
|
foo_a
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing merge anchors with override
|
## Traversing merge anchors with override
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -220,7 +253,7 @@ will output
|
|||||||
foo_c
|
foo_c
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing merge anchors with local override
|
## Traversing merge anchors with local override
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -251,7 +284,7 @@ will output
|
|||||||
foobar_thing
|
foobar_thing
|
||||||
```
|
```
|
||||||
|
|
||||||
### Splatting merge anchors
|
## Splatting merge anchors
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -275,7 +308,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobar.[]' sample.yml
|
yq eval '.foobar[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -284,7 +317,7 @@ foo_a
|
|||||||
foobar_thing
|
foobar_thing
|
||||||
```
|
```
|
||||||
|
|
||||||
### Traversing merge anchor lists
|
## Traversing merge anchor lists
|
||||||
Note that the later merge anchors override previous
|
Note that the later merge anchors override previous
|
||||||
|
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
@@ -317,7 +350,7 @@ will output
|
|||||||
bar_thing
|
bar_thing
|
||||||
```
|
```
|
||||||
|
|
||||||
### Splatting merge anchor lists
|
## Splatting merge anchor lists
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
foo: &foo
|
foo: &foo
|
||||||
@@ -341,7 +374,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobarList.[]' sample.yml
|
yq eval '.foobarList[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -351,3 +384,21 @@ bar_thing
|
|||||||
foobarList_c
|
foobarList_c
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Select multiple indices
|
||||||
|
Given a sample.yml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq eval '.a[0, 2]' sample.yml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
a
|
||||||
|
c
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
This operator is used to combine different results together.
|
This operator is used to combine different results together.
|
||||||
## Examples
|
## Combine scalars
|
||||||
### Combine scalars
|
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '1, true, "cat"'
|
yq eval --null-input '1, true, "cat"'
|
||||||
@@ -12,7 +11,7 @@ true
|
|||||||
cat
|
cat
|
||||||
```
|
```
|
||||||
|
|
||||||
### Combine selected paths
|
## Combine selected paths
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
a: fieldA
|
a: fieldA
|
||||||
0
pkg/yqlib/doc/aa.md
Normal file
0
pkg/yqlib/doc/aa.md
Normal file
6
pkg/yqlib/doc/headers/Add.md
Normal file
6
pkg/yqlib/doc/headers/Add.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Add behaves differently according to the type of the LHS:
|
||||||
|
- arrays: concatenate
|
||||||
|
- number scalars: arithmetic addition
|
||||||
|
- string scalars: concatenate
|
||||||
|
|
||||||
|
Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
|
||||||
1
pkg/yqlib/doc/headers/Alternative (Default value).md
Normal file
1
pkg/yqlib/doc/headers/Alternative (Default value).md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This operator is used to provide alternative (or default) values when a particular expression is either null or false.
|
||||||
4
pkg/yqlib/doc/headers/Anchor and Alias Operators.md
Normal file
4
pkg/yqlib/doc/headers/Anchor and Alias Operators.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Use the `alias` and `anchor` operators to read and write yaml aliases and anchors. The `explode` operator normalises a yaml file (dereference aliases and remove anchor names).
|
||||||
|
|
||||||
|
`yq` supports merge aliases (like `<<: *blah`) however this is no longer in the standard yaml spec (1.2) and so `yq` will automatically add the `!!merge` tag to these nodes as it is effectively a custom tag.
|
||||||
|
|
||||||
1
pkg/yqlib/doc/headers/Boolean Operators.md
Normal file
1
pkg/yqlib/doc/headers/Boolean Operators.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
The `or` and `and` operators take two parameters and return a boolean result. `not` flips a boolean from true to false, or vice versa. These are most commonly used with the `select` operator to filter particular nodes.
|
||||||
1
pkg/yqlib/doc/headers/Document Index.md
Normal file
1
pkg/yqlib/doc/headers/Document Index.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Use the `documentIndex` operator (or the `di` shorthand) to select nodes of a particular document.
|
||||||
2
pkg/yqlib/doc/headers/Env Variable Operators.md
Normal file
2
pkg/yqlib/doc/headers/Env Variable Operators.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
This operator is used to handle environment variables usage in path expressions. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read. Note that there are two forms, `env` which will parse the environment variable as a yaml (be it a map, array, string, number of boolean) and `strenv` which will always parse the argument as a string.
|
||||||
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
## Equals Operator
|
|
||||||
|
|
||||||
This is a boolean operator that will return ```true``` if the LHS is equal to the RHS and ``false`` otherwise.
|
This is a boolean operator that will return ```true``` if the LHS is equal to the RHS and ``false`` otherwise.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1 +0,0 @@
|
|||||||
Explodes (or dereferences) aliases and anchors.
|
|
||||||
9
pkg/yqlib/doc/headers/File Operators.md
Normal file
9
pkg/yqlib/doc/headers/File Operators.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
File operators are most often used with merge when needing to merge specific files together. Note that when doing this, you will need to use `eval-all` to ensure all yaml documents are loaded into memory before performing the merge (as opposed to `eval` which runs the expression once per document).
|
||||||
|
|
||||||
|
Note that the `fileIndex` operator has a short alias of `fi`.
|
||||||
|
|
||||||
|
## Merging files
|
||||||
|
Note the use of eval-all to ensure all documents are loaded into memory.
|
||||||
|
```bash
|
||||||
|
yq eval-all 'select(fi == 0) * select(filename == "file2.yaml")' file1.yaml file2.yaml
|
||||||
|
```
|
||||||
1
pkg/yqlib/doc/headers/Has.md
Normal file
1
pkg/yqlib/doc/headers/Has.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
|
||||||
1
pkg/yqlib/doc/headers/Length.md
Normal file
1
pkg/yqlib/doc/headers/Length.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Returns the lengths of the nodes. Length is defined according to the type of the node.
|
||||||
@@ -2,4 +2,13 @@ Like the multiple operator in `jq`, depending on the operands, this multiply ope
|
|||||||
|
|
||||||
Upcoming versions of `yq` will add support for other types of multiplication (numbers, strings).
|
Upcoming versions of `yq` will add support for other types of multiplication (numbers, strings).
|
||||||
|
|
||||||
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
To concatenate when merging objects, use the `*+` form (see examples below). This will recursively merge objects, appending arrays when it encounters them.
|
||||||
|
|
||||||
|
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
|
||||||
|
|
||||||
|
## Merging files
|
||||||
|
Note the use of eval-all to ensure all documents are loaded into memory.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
|
||||||
|
```
|
||||||
@@ -1 +0,0 @@
|
|||||||
This is a boolean operator and will return `true` when given a `false` value (including null), and `false` otherwise.
|
|
||||||
3
pkg/yqlib/doc/headers/Path.md
Normal file
3
pkg/yqlib/doc/headers/Path.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
The path operator can be used to get the traversal paths of matching nodes in an expression. The path is returned as an array, which if traversed in order will lead to the matching node.
|
||||||
|
|
||||||
|
You can get the key/index of matching nodes by using the `path` operator to return the path array then piping that through `.[-1]` to get the last element of that array, the key.
|
||||||
1
pkg/yqlib/doc/headers/Pipe.md
Normal file
1
pkg/yqlib/doc/headers/Pipe.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Pipe the results of an expression into another. Like the bash operator.
|
||||||
19
pkg/yqlib/doc/headers/Recursive Descent (Glob).md
Normal file
19
pkg/yqlib/doc/headers/Recursive Descent (Glob).md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
This operator recursively matches (or globs) all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
|
||||||
|
|
||||||
|
## match values form `..`
|
||||||
|
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
|
||||||
|
|
||||||
|
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '.. style= "flow"' file.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## match values and map keys form `...`
|
||||||
|
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
|
||||||
|
|
||||||
|
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval '... style= "flow"' file.yaml
|
||||||
|
```
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
This operator recursively matches all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches, for instance to set the `style` of all nodes in a yaml doc:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
yq eval '.. style= "flow"' file.yaml
|
|
||||||
```
|
|
||||||
9
pkg/yqlib/doc/headers/Sort Keys.md
Normal file
9
pkg/yqlib/doc/headers/Sort Keys.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
The Sort Keys operator sorts maps by their keys (based on their string value). This operator does not do anything to arrays or scalars (so you can easily recursively apply it to all maps).
|
||||||
|
|
||||||
|
Sort is particularly useful for diffing two different yaml documents:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yq eval -i 'sortKeys(..)' file1.yml
|
||||||
|
yq eval -i 'sortKeys(..)' file2.yml
|
||||||
|
diff file1.yml file2.yml
|
||||||
|
```
|
||||||
@@ -1 +0,0 @@
|
|||||||
The tag operator can be used to get or set the tag of ndoes (e.g. `!!str`, `!!int`, `!!bool`).
|
|
||||||
1
pkg/yqlib/doc/headers/Tag.md
Normal file
1
pkg/yqlib/doc/headers/Tag.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
The tag operator can be used to get or set the tag of nodes (e.g. `!!str`, `!!int`, `!!bool`).
|
||||||
@@ -1 +0,0 @@
|
|||||||
This is the simples (and perhaps most used) operator, it is used to navigate deeply into yaml structurse.
|
|
||||||
1
pkg/yqlib/doc/headers/Traverse.md
Normal file
1
pkg/yqlib/doc/headers/Traverse.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is the simplest (and perhaps most used) operator, it is used to navigate deeply into yaml structurse.
|
||||||
@@ -50,7 +50,7 @@ func (ye *yamlEncoder) Encode(node *yaml.Node) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ye.colorise {
|
if ye.colorise {
|
||||||
return ColorizeAndPrint(tempBuffer.Bytes(), ye.destination)
|
return colorizeAndPrint(tempBuffer.Bytes(), ye.destination)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestJsonEncoderPreservesObjectOrder(t *testing.T) {
|
|||||||
writer := bufio.NewWriter(&output)
|
writer := bufio.NewWriter(&output)
|
||||||
|
|
||||||
var jsonEncoder = NewJsonEncoder(writer, 2)
|
var jsonEncoder = NewJsonEncoder(writer, 2)
|
||||||
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml")
|
inputs, err := readDocuments(strings.NewReader(sampleYaml), "sample.yml", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
76
pkg/yqlib/expression_parser.go
Normal file
76
pkg/yqlib/expression_parser.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var myPathTokeniser = newExpressionTokeniser()
|
||||||
|
var myPathPostfixer = newExpressionPostFixer()
|
||||||
|
|
||||||
|
type ExpressionNode struct {
|
||||||
|
Operation *Operation
|
||||||
|
Lhs *ExpressionNode
|
||||||
|
Rhs *ExpressionNode
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExpressionParser interface {
|
||||||
|
ParseExpression(expression string) (*ExpressionNode, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type expressionParserImpl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExpressionParser() ExpressionParser {
|
||||||
|
return &expressionParserImpl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *expressionParserImpl) ParseExpression(expression string) (*ExpressionNode, error) {
|
||||||
|
tokens, err := myPathTokeniser.Tokenise(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var Operations []*Operation
|
||||||
|
Operations, err = myPathPostfixer.ConvertToPostfix(tokens)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return p.createExpressionTree(Operations)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *expressionParserImpl) createExpressionTree(postFixPath []*Operation) (*ExpressionNode, error) {
|
||||||
|
var stack = make([]*ExpressionNode, 0)
|
||||||
|
|
||||||
|
if len(postFixPath) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, Operation := range postFixPath {
|
||||||
|
var newNode = ExpressionNode{Operation: Operation}
|
||||||
|
log.Debugf("pathTree %v ", Operation.toString())
|
||||||
|
if Operation.OperationType.NumArgs > 0 {
|
||||||
|
numArgs := Operation.OperationType.NumArgs
|
||||||
|
if numArgs == 1 {
|
||||||
|
if len(stack) < 1 {
|
||||||
|
return nil, fmt.Errorf("'%v' expects 1 arg but received none", strings.TrimSpace(Operation.StringValue))
|
||||||
|
}
|
||||||
|
remaining, rhs := stack[:len(stack)-1], stack[len(stack)-1]
|
||||||
|
newNode.Rhs = rhs
|
||||||
|
stack = remaining
|
||||||
|
} else if numArgs == 2 {
|
||||||
|
if len(stack) < 2 {
|
||||||
|
return nil, fmt.Errorf("'%v' expects 2 args but there is %v", strings.TrimSpace(Operation.StringValue), len(stack))
|
||||||
|
}
|
||||||
|
remaining, lhs, rhs := stack[:len(stack)-2], stack[len(stack)-2], stack[len(stack)-1]
|
||||||
|
newNode.Lhs = lhs
|
||||||
|
newNode.Rhs = rhs
|
||||||
|
stack = remaining
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack = append(stack, &newNode)
|
||||||
|
}
|
||||||
|
if len(stack) != 1 {
|
||||||
|
return nil, fmt.Errorf("expected end of expression but found '%v', please check expression syntax", strings.TrimSpace(stack[1].Operation.StringValue))
|
||||||
|
}
|
||||||
|
return stack[0], nil
|
||||||
|
}
|
||||||
42
pkg/yqlib/expression_parser_test.go
Normal file
42
pkg/yqlib/expression_parser_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v4/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPathTreeNoArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression("=")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 0", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneLhsArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression(".a =")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneRhsArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression("= .a")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeTwoArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression(".a = .b")
|
||||||
|
test.AssertResultComplex(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeNoArgsForOneArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression("explode")
|
||||||
|
test.AssertResultComplex(t, "'explode' expects 1 arg but received none", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneArgForOneArgOp(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression("explode(.)")
|
||||||
|
test.AssertResultComplex(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeExtraArgs(t *testing.T) {
|
||||||
|
_, err := NewExpressionParser().ParseExpression("sortKeys(.) explode(.)")
|
||||||
|
test.AssertResultComplex(t, "expected end of expression but found 'explode', please check expression syntax", err.Error())
|
||||||
|
}
|
||||||
@@ -3,43 +3,43 @@ package yqlib
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"gopkg.in/op/go-logging.v1"
|
logging "gopkg.in/op/go-logging.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PathPostFixer interface {
|
type expressionPostFixer interface {
|
||||||
ConvertToPostfix([]*Token) ([]*Operation, error)
|
ConvertToPostfix([]*token) ([]*Operation, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type pathPostFixer struct {
|
type expressionPostFixerImpl struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPathPostFixer() PathPostFixer {
|
func newExpressionPostFixer() expressionPostFixer {
|
||||||
return &pathPostFixer{}
|
return &expressionPostFixerImpl{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func popOpToResult(opStack []*Token, result []*Operation) ([]*Token, []*Operation) {
|
func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {
|
||||||
var newOp *Token
|
var newOp *token
|
||||||
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
|
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
|
||||||
return opStack, append(result, newOp.Operation)
|
return opStack, append(result, newOp.Operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*Operation, error) {
|
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
|
||||||
var result []*Operation
|
var result []*Operation
|
||||||
// surround the whole thing with quotes
|
// surround the whole thing with quotes
|
||||||
var opStack = []*Token{&Token{TokenType: OpenBracket}}
|
var opStack = []*token{&token{TokenType: openBracket}}
|
||||||
var tokens = append(infixTokens, &Token{TokenType: CloseBracket})
|
var tokens = append(infixTokens, &token{TokenType: closeBracket})
|
||||||
|
|
||||||
for _, token := range tokens {
|
for _, currentToken := range tokens {
|
||||||
log.Debugf("postfix processing token %v, %v", token.toString(), token.Operation)
|
log.Debugf("postfix processing currentToken %v, %v", currentToken.toString(), currentToken.Operation)
|
||||||
switch token.TokenType {
|
switch currentToken.TokenType {
|
||||||
case OpenBracket, OpenCollect, OpenCollectObject:
|
case openBracket, openCollect, openCollectObject:
|
||||||
opStack = append(opStack, token)
|
opStack = append(opStack, currentToken)
|
||||||
case CloseCollect, CloseCollectObject:
|
case closeCollect, closeCollectObject:
|
||||||
var opener TokenType = OpenCollect
|
var opener tokenType = openCollect
|
||||||
var collectOperator *OperationType = Collect
|
var collectOperator *operationType = collectOpType
|
||||||
if token.TokenType == CloseCollectObject {
|
if currentToken.TokenType == closeCollectObject {
|
||||||
opener = OpenCollectObject
|
opener = openCollectObject
|
||||||
collectOperator = CollectObject
|
collectOperator = collectObjectOpType
|
||||||
}
|
}
|
||||||
itemsInMiddle := false
|
itemsInMiddle := false
|
||||||
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener {
|
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener {
|
||||||
@@ -48,7 +48,7 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*Operation, er
|
|||||||
}
|
}
|
||||||
if !itemsInMiddle {
|
if !itemsInMiddle {
|
||||||
// must be an empty collection, add the empty object as a LHS parameter
|
// must be an empty collection, add the empty object as a LHS parameter
|
||||||
result = append(result, &Operation{OperationType: Empty})
|
result = append(result, &Operation{OperationType: emptyOpType})
|
||||||
}
|
}
|
||||||
if len(opStack) == 0 {
|
if len(opStack) == 0 {
|
||||||
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
|
return nil, errors.New("Bad path expression, got close collect brackets without matching opening bracket")
|
||||||
@@ -56,10 +56,10 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*Operation, er
|
|||||||
// now we should have [] as the last element on the opStack, get rid of it
|
// now we should have [] as the last element on the opStack, get rid of it
|
||||||
opStack = opStack[0 : len(opStack)-1]
|
opStack = opStack[0 : len(opStack)-1]
|
||||||
//and append a collect to the opStack
|
//and append a collect to the opStack
|
||||||
opStack = append(opStack, &Token{TokenType: OperationToken, Operation: &Operation{OperationType: Pipe}})
|
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: shortPipeOpType}})
|
||||||
opStack = append(opStack, &Token{TokenType: OperationToken, Operation: &Operation{OperationType: collectOperator}})
|
opStack = append(opStack, &token{TokenType: operationToken, Operation: &Operation{OperationType: collectOperator}})
|
||||||
case CloseBracket:
|
case closeBracket:
|
||||||
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != OpenBracket {
|
for len(opStack) > 0 && opStack[len(opStack)-1].TokenType != openBracket {
|
||||||
opStack, result = popOpToResult(opStack, result)
|
opStack, result = popOpToResult(opStack, result)
|
||||||
}
|
}
|
||||||
if len(opStack) == 0 {
|
if len(opStack) == 0 {
|
||||||
@@ -69,22 +69,22 @@ func (p *pathPostFixer) ConvertToPostfix(infixTokens []*Token) ([]*Operation, er
|
|||||||
opStack = opStack[0 : len(opStack)-1]
|
opStack = opStack[0 : len(opStack)-1]
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var currentPrecedence = token.Operation.OperationType.Precedence
|
var currentPrecedence = currentToken.Operation.OperationType.Precedence
|
||||||
// pop off higher precedent operators onto the result
|
// pop off higher precedent operators onto the result
|
||||||
for len(opStack) > 0 &&
|
for len(opStack) > 0 &&
|
||||||
opStack[len(opStack)-1].TokenType == OperationToken &&
|
opStack[len(opStack)-1].TokenType == operationToken &&
|
||||||
opStack[len(opStack)-1].Operation.OperationType.Precedence >= currentPrecedence {
|
opStack[len(opStack)-1].Operation.OperationType.Precedence >= currentPrecedence {
|
||||||
opStack, result = popOpToResult(opStack, result)
|
opStack, result = popOpToResult(opStack, result)
|
||||||
}
|
}
|
||||||
// add this operator to the opStack
|
// add this operator to the opStack
|
||||||
opStack = append(opStack, token)
|
opStack = append(opStack, currentToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if log.IsEnabledFor(logging.DEBUG) {
|
if log.IsEnabledFor(logging.DEBUG) {
|
||||||
log.Debugf("PostFix Result:")
|
log.Debugf("PostFix Result:")
|
||||||
for _, token := range result {
|
for _, currentToken := range result {
|
||||||
log.Debugf("> %v", token.toString())
|
log.Debugf("> %v", currentToken.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
196
pkg/yqlib/expression_processing_test.go
Normal file
196
pkg/yqlib/expression_processing_test.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v4/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pathTests = []struct {
|
||||||
|
path string
|
||||||
|
expectedTokens []interface{}
|
||||||
|
expectedPostFix []interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
`[]`,
|
||||||
|
append(make([]interface{}, 0), "[", "]"),
|
||||||
|
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.[]`,
|
||||||
|
append(make([]interface{}, 0), "TRAVERSE_ARRAY", "[", "]"),
|
||||||
|
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a[]`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "]"),
|
||||||
|
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a.[]`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "]"),
|
||||||
|
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a[0]`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
|
||||||
|
append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a.[0]`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "0 (int64)", "]"),
|
||||||
|
append(make([]interface{}, 0), "a", "0 (int64)", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a[].c`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "c"),
|
||||||
|
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "c", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[3]`,
|
||||||
|
append(make([]interface{}, 0), "[", "3 (int64)", "]"),
|
||||||
|
append(make([]interface{}, 0), "3 (int64)", "COLLECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`d0.a`,
|
||||||
|
append(make([]interface{}, 0), "d0", "SHORT_PIPE", "a"),
|
||||||
|
append(make([]interface{}, 0), "d0", "a", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a | .[].b == "apple"`,
|
||||||
|
append(make([]interface{}, 0), "a", "PIPE", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"),
|
||||||
|
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "apple (string)", "EQUALS", "PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`(.a | .[].b) == "apple"`,
|
||||||
|
append(make([]interface{}, 0), "(", "a", "PIPE", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "b", ")", "EQUALS", "apple (string)"),
|
||||||
|
append(make([]interface{}, 0), "a", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "b", "SHORT_PIPE", "PIPE", "apple (string)", "EQUALS"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.[] | select(. == "*at")`,
|
||||||
|
append(make([]interface{}, 0), "TRAVERSE_ARRAY", "[", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"),
|
||||||
|
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true]`,
|
||||||
|
append(make([]interface{}, 0), "[", "true (bool)", "]"),
|
||||||
|
append(make([]interface{}, 0), "true (bool)", "COLLECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`[true, false]`,
|
||||||
|
append(make([]interface{}, 0), "[", "true (bool)", "UNION", "false (bool)", "]"),
|
||||||
|
append(make([]interface{}, 0), "true (bool)", "false (bool)", "UNION", "COLLECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`"mike": .a`,
|
||||||
|
append(make([]interface{}, 0), "mike (string)", "CREATE_MAP", "a"),
|
||||||
|
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a: "mike"`,
|
||||||
|
append(make([]interface{}, 0), "a", "CREATE_MAP", "mike (string)"),
|
||||||
|
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`{"mike": .a}`,
|
||||||
|
append(make([]interface{}, 0), "{", "mike (string)", "CREATE_MAP", "a", "}"),
|
||||||
|
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`{.a: "mike"}`,
|
||||||
|
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "mike (string)", "}"),
|
||||||
|
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`{.a: .c, .b.[]: .f.g.[]}`,
|
||||||
|
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "]", "CREATE_MAP", "f", "SHORT_PIPE", "g", "SHORT_PIPE", "TRAVERSE_ARRAY", "[", "]", "}"),
|
||||||
|
append(make([]interface{}, 0), "a", "c", "CREATE_MAP", "b", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "f", "g", "SHORT_PIPE", "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SHORT_PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`explode(.a.b)`,
|
||||||
|
append(make([]interface{}, 0), "EXPLODE", "(", "a", "SHORT_PIPE", "b", ")"),
|
||||||
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "EXPLODE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a.b style="folded"`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_STYLE", "folded (string)"),
|
||||||
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "folded (string)", "ASSIGN_STYLE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`tag == "str"`,
|
||||||
|
append(make([]interface{}, 0), "GET_TAG", "EQUALS", "str (string)"),
|
||||||
|
append(make([]interface{}, 0), "GET_TAG", "str (string)", "EQUALS"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`. tag= "str"`,
|
||||||
|
append(make([]interface{}, 0), "SELF", "ASSIGN_TAG", "str (string)"),
|
||||||
|
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_TAG"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`lineComment == "str"`,
|
||||||
|
append(make([]interface{}, 0), "GET_COMMENT", "EQUALS", "str (string)"),
|
||||||
|
append(make([]interface{}, 0), "GET_COMMENT", "str (string)", "EQUALS"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`. lineComment= "str"`,
|
||||||
|
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
|
||||||
|
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`. lineComment |= "str"`,
|
||||||
|
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
|
||||||
|
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.a.b tag="!!str"`,
|
||||||
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_TAG", "!!str (string)"),
|
||||||
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "!!str (string)", "ASSIGN_TAG"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`""`,
|
||||||
|
append(make([]interface{}, 0), " (string)"),
|
||||||
|
append(make([]interface{}, 0), " (string)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`.foo* | (. style="flow")`,
|
||||||
|
append(make([]interface{}, 0), "foo*", "PIPE", "(", "SELF", "ASSIGN_STYLE", "flow (string)", ")"),
|
||||||
|
append(make([]interface{}, 0), "foo*", "SELF", "flow (string)", "ASSIGN_STYLE", "PIPE"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`{}`,
|
||||||
|
append(make([]interface{}, 0), "{", "}"),
|
||||||
|
append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokeniser = newExpressionTokeniser()
|
||||||
|
var postFixer = newExpressionPostFixer()
|
||||||
|
|
||||||
|
func TestPathParsing(t *testing.T) {
|
||||||
|
for _, tt := range pathTests {
|
||||||
|
tokens, err := tokeniser.Tokenise(tt.path)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(tt.path, err)
|
||||||
|
}
|
||||||
|
var tokenValues []interface{}
|
||||||
|
for _, token := range tokens {
|
||||||
|
tokenValues = append(tokenValues, token.toString())
|
||||||
|
}
|
||||||
|
test.AssertResultComplexWithContext(t, tt.expectedTokens, tokenValues, fmt.Sprintf("tokenise: %v", tt.path))
|
||||||
|
|
||||||
|
results, errorP := postFixer.ConvertToPostfix(tokens)
|
||||||
|
|
||||||
|
var readableResults []interface{}
|
||||||
|
for _, token := range results {
|
||||||
|
readableResults = append(readableResults, token.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if errorP != nil {
|
||||||
|
t.Error(tt.path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
test.AssertResultComplexWithContext(t, tt.expectedPostFix, readableResults, fmt.Sprintf("postfix: %v", tt.path))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
407
pkg/yqlib/expression_tokeniser.go
Normal file
407
pkg/yqlib/expression_tokeniser.go
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
lex "github.com/timtadh/lexmachine"
|
||||||
|
"github.com/timtadh/lexmachine/machines"
|
||||||
|
)
|
||||||
|
|
||||||
|
func skip(*lex.Scanner, *machines.Match) (interface{}, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
operationToken = 1 << iota
|
||||||
|
openBracket
|
||||||
|
closeBracket
|
||||||
|
openCollect
|
||||||
|
closeCollect
|
||||||
|
openCollectObject
|
||||||
|
closeCollectObject
|
||||||
|
traverseArrayCollect
|
||||||
|
)
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
TokenType tokenType
|
||||||
|
Operation *Operation
|
||||||
|
AssignOperation *Operation // e.g. tag (GetTag) op becomes AssignTag if '=' follows it
|
||||||
|
CheckForPostTraverse bool // e.g. [1]cat should really be [1].cat
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *token) toString() string {
|
||||||
|
if t.TokenType == operationToken {
|
||||||
|
log.Debug("toString, its an op")
|
||||||
|
return t.Operation.toString()
|
||||||
|
} else if t.TokenType == openBracket {
|
||||||
|
return "("
|
||||||
|
} else if t.TokenType == closeBracket {
|
||||||
|
return ")"
|
||||||
|
} else if t.TokenType == openCollect {
|
||||||
|
return "["
|
||||||
|
} else if t.TokenType == closeCollect {
|
||||||
|
return "]"
|
||||||
|
} else if t.TokenType == openCollectObject {
|
||||||
|
return "{"
|
||||||
|
} else if t.TokenType == closeCollectObject {
|
||||||
|
return "}"
|
||||||
|
} else if t.TokenType == traverseArrayCollect {
|
||||||
|
return ".["
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return "NFI"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pathToken(wrapped bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
value := string(m.Bytes)
|
||||||
|
value = value[1:]
|
||||||
|
if wrapped {
|
||||||
|
value = unwrap(value)
|
||||||
|
}
|
||||||
|
log.Debug("PathToken %v", value)
|
||||||
|
op := &Operation{OperationType: traversePathOpType, Value: value, StringValue: value}
|
||||||
|
return &token{TokenType: operationToken, Operation: op, CheckForPostTraverse: true}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func documentToken() lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
var numberString = string(m.Bytes)
|
||||||
|
numberString = numberString[1:]
|
||||||
|
var number, errParsingInt = strconv.ParseInt(numberString, 10, 64) // nolint
|
||||||
|
if errParsingInt != nil {
|
||||||
|
return nil, errParsingInt
|
||||||
|
}
|
||||||
|
log.Debug("documentToken %v", string(m.Bytes))
|
||||||
|
op := &Operation{OperationType: documentFilterOpType, Value: number, StringValue: numberString}
|
||||||
|
return &token{TokenType: operationToken, Operation: op, CheckForPostTraverse: true}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opToken(op *operationType) lex.Action {
|
||||||
|
return opTokenWithPrefs(op, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func opAssignableToken(opType *operationType, assignOpType *operationType) lex.Action {
|
||||||
|
return opTokenWithPrefs(opType, assignOpType, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assignOpToken(updateAssign bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
log.Debug("assignOpToken %v", string(m.Bytes))
|
||||||
|
value := string(m.Bytes)
|
||||||
|
op := &Operation{OperationType: assignOpType, Value: assignOpType.Type, StringValue: value, UpdateAssign: updateAssign}
|
||||||
|
return &token{TokenType: operationToken, Operation: op}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func opTokenWithPrefs(op *operationType, assignOpType *operationType, preferences interface{}) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
log.Debug("opTokenWithPrefs %v", string(m.Bytes))
|
||||||
|
value := string(m.Bytes)
|
||||||
|
op := &Operation{OperationType: op, Value: op.Type, StringValue: value, Preferences: preferences}
|
||||||
|
var assign *Operation
|
||||||
|
if assignOpType != nil {
|
||||||
|
assign = &Operation{OperationType: assignOpType, Value: assignOpType.Type, StringValue: value, Preferences: preferences}
|
||||||
|
}
|
||||||
|
return &token{TokenType: operationToken, Operation: op, AssignOperation: assign}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assignAllCommentsOp(updateAssign bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
log.Debug("assignAllCommentsOp %v", string(m.Bytes))
|
||||||
|
value := string(m.Bytes)
|
||||||
|
op := &Operation{
|
||||||
|
OperationType: assignCommentOpType,
|
||||||
|
Value: assignCommentOpType.Type,
|
||||||
|
StringValue: value,
|
||||||
|
UpdateAssign: updateAssign,
|
||||||
|
Preferences: &commentOpPreferences{LineComment: true, HeadComment: true, FootComment: true},
|
||||||
|
}
|
||||||
|
return &token{TokenType: operationToken, Operation: op}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func literalToken(pType tokenType, checkForPost bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
return &token{TokenType: pType, CheckForPostTraverse: checkForPost}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unwrap(value string) string {
|
||||||
|
return value[1 : len(value)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberValue() lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
var numberString = string(m.Bytes)
|
||||||
|
var number, errParsingInt = strconv.ParseInt(numberString, 10, 64) // nolint
|
||||||
|
if errParsingInt != nil {
|
||||||
|
return nil, errParsingInt
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token{TokenType: operationToken, Operation: createValueOperation(number, numberString)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func floatValue() lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
var numberString = string(m.Bytes)
|
||||||
|
var number, errParsingInt = strconv.ParseFloat(numberString, 64) // nolint
|
||||||
|
if errParsingInt != nil {
|
||||||
|
return nil, errParsingInt
|
||||||
|
}
|
||||||
|
return &token{TokenType: operationToken, Operation: createValueOperation(number, numberString)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func booleanValue(val bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
return &token{TokenType: operationToken, Operation: createValueOperation(val, string(m.Bytes))}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringValue(wrapped bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
value := string(m.Bytes)
|
||||||
|
if wrapped {
|
||||||
|
value = unwrap(value)
|
||||||
|
}
|
||||||
|
return &token{TokenType: operationToken, Operation: createValueOperation(value, value)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func envOp(strenv bool) lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
value := string(m.Bytes)
|
||||||
|
preferences := &envOpPreferences{}
|
||||||
|
|
||||||
|
if strenv {
|
||||||
|
// strenv( )
|
||||||
|
value = value[7 : len(value)-1]
|
||||||
|
preferences.StringValue = true
|
||||||
|
} else {
|
||||||
|
//env( )
|
||||||
|
value = value[4 : len(value)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
envOperation := createValueOperation(value, value)
|
||||||
|
envOperation.OperationType = envOpType
|
||||||
|
envOperation.Preferences = preferences
|
||||||
|
|
||||||
|
return &token{TokenType: operationToken, Operation: envOperation}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nullValue() lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
return &token{TokenType: operationToken, Operation: createValueOperation(nil, string(m.Bytes))}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func selfToken() lex.Action {
|
||||||
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
|
op := &Operation{OperationType: selfReferenceOpType}
|
||||||
|
return &token{TokenType: operationToken, Operation: op}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initLexer() (*lex.Lexer, error) {
|
||||||
|
lexer := lex.NewLexer()
|
||||||
|
lexer.Add([]byte(`\(`), literalToken(openBracket, false))
|
||||||
|
lexer.Add([]byte(`\)`), literalToken(closeBracket, true))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\.\[`), literalToken(traverseArrayCollect, false))
|
||||||
|
lexer.Add([]byte(`\.\.`), opTokenWithPrefs(recursiveDescentOpType, nil, &recursiveDescentPreferences{RecurseArray: true,
|
||||||
|
TraversePreferences: &traversePreferences{FollowAlias: false, IncludeMapKeys: false}}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\.\.\.`), opTokenWithPrefs(recursiveDescentOpType, nil, &recursiveDescentPreferences{RecurseArray: true,
|
||||||
|
TraversePreferences: &traversePreferences{FollowAlias: false, IncludeMapKeys: true}}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`,`), opToken(unionOpType))
|
||||||
|
lexer.Add([]byte(`:\s*`), opToken(createMapOpType))
|
||||||
|
lexer.Add([]byte(`length`), opToken(lengthOpType))
|
||||||
|
lexer.Add([]byte(`sortKeys`), opToken(sortKeysOpType))
|
||||||
|
lexer.Add([]byte(`select`), opToken(selectOpType))
|
||||||
|
lexer.Add([]byte(`has`), opToken(hasOpType))
|
||||||
|
lexer.Add([]byte(`explode`), opToken(explodeOpType))
|
||||||
|
lexer.Add([]byte(`or`), opToken(orOpType))
|
||||||
|
lexer.Add([]byte(`and`), opToken(andOpType))
|
||||||
|
lexer.Add([]byte(`not`), opToken(notOpType))
|
||||||
|
lexer.Add([]byte(`\/\/`), opToken(alternativeOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType))
|
||||||
|
lexer.Add([]byte(`di`), opToken(getDocumentIndexOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`style`), opAssignableToken(getStyleOpType, assignStyleOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`tag`), opAssignableToken(getTagOpType, assignTagOpType))
|
||||||
|
lexer.Add([]byte(`anchor`), opAssignableToken(getAnchorOpType, assignAnchorOpType))
|
||||||
|
lexer.Add([]byte(`alias`), opAssignableToken(getAliasOptype, assignAliasOpType))
|
||||||
|
lexer.Add([]byte(`filename`), opToken(getFilenameOpType))
|
||||||
|
lexer.Add([]byte(`fileIndex`), opToken(getFileIndexOpType))
|
||||||
|
lexer.Add([]byte(`fi`), opToken(getFileIndexOpType))
|
||||||
|
lexer.Add([]byte(`path`), opToken(getPathOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`lineComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, &commentOpPreferences{LineComment: true}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`headComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, &commentOpPreferences{HeadComment: true}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`footComment`), opTokenWithPrefs(getCommentOpType, assignCommentOpType, &commentOpPreferences{FootComment: true}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`comments\s*=`), assignAllCommentsOp(false))
|
||||||
|
lexer.Add([]byte(`comments\s*\|=`), assignAllCommentsOp(true))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`collect`), opToken(collectOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\s*==\s*`), opToken(equalsOpType))
|
||||||
|
lexer.Add([]byte(`\s*=\s*`), assignOpToken(false))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`del`), opToken(deleteChildOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\s*\|=\s*`), assignOpToken(true))
|
||||||
|
|
||||||
|
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
||||||
|
|
||||||
|
lexer.Add([]byte(`d[0-9]+`), documentToken())
|
||||||
|
lexer.Add([]byte(`\."[^ "]+"`), pathToken(true))
|
||||||
|
lexer.Add([]byte(`\.[^ \}\{\:\[\],\|\.\[\(\)=]+`), pathToken(false))
|
||||||
|
lexer.Add([]byte(`\.`), selfToken())
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\|`), opToken(pipeOpType))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`-?\d+(\.\d+)`), floatValue())
|
||||||
|
lexer.Add([]byte(`-?[1-9](\.\d+)?[Ee][-+]?\d+`), floatValue())
|
||||||
|
lexer.Add([]byte(`-?\d+`), numberValue())
|
||||||
|
|
||||||
|
lexer.Add([]byte(`[Tt][Rr][Uu][Ee]`), booleanValue(true))
|
||||||
|
lexer.Add([]byte(`[Ff][Aa][Ll][Ss][Ee]`), booleanValue(false))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`[Nn][Uu][Ll][Ll]`), nullValue())
|
||||||
|
lexer.Add([]byte(`~`), nullValue())
|
||||||
|
|
||||||
|
lexer.Add([]byte(`"[^"]*"`), stringValue(true))
|
||||||
|
lexer.Add([]byte(`strenv\([^\)]+\)`), envOp(true))
|
||||||
|
lexer.Add([]byte(`env\([^\)]+\)`), envOp(false))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\[`), literalToken(openCollect, false))
|
||||||
|
lexer.Add([]byte(`\]`), literalToken(closeCollect, true))
|
||||||
|
lexer.Add([]byte(`\{`), literalToken(openCollectObject, false))
|
||||||
|
lexer.Add([]byte(`\}`), literalToken(closeCollectObject, true))
|
||||||
|
lexer.Add([]byte(`\*`), opTokenWithPrefs(multiplyOpType, nil, &multiplyPreferences{AppendArrays: false}))
|
||||||
|
lexer.Add([]byte(`\*\+`), opTokenWithPrefs(multiplyOpType, nil, &multiplyPreferences{AppendArrays: true}))
|
||||||
|
lexer.Add([]byte(`\+`), opToken(addOpType))
|
||||||
|
lexer.Add([]byte(`\+=`), opToken(addAssignOpType))
|
||||||
|
|
||||||
|
err := lexer.Compile()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return lexer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type expressionTokeniser interface {
|
||||||
|
Tokenise(expression string) ([]*token, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type expressionTokeniserImpl struct {
|
||||||
|
lexer *lex.Lexer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newExpressionTokeniser() expressionTokeniser {
|
||||||
|
var lexer, err = initLexer()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return &expressionTokeniserImpl{lexer}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *expressionTokeniserImpl) Tokenise(expression string) ([]*token, error) {
|
||||||
|
scanner, err := p.lexer.Scanner([]byte(expression))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
||||||
|
}
|
||||||
|
var tokens []*token
|
||||||
|
for tok, err, eof := scanner.Next(); !eof; tok, err, eof = scanner.Next() {
|
||||||
|
|
||||||
|
if tok != nil {
|
||||||
|
currentToken := tok.(*token)
|
||||||
|
log.Debugf("Tokenising %v", currentToken.toString())
|
||||||
|
tokens = append(tokens, currentToken)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var postProcessedTokens = make([]*token, 0)
|
||||||
|
|
||||||
|
skipNextToken := false
|
||||||
|
|
||||||
|
for index := range tokens {
|
||||||
|
if skipNextToken {
|
||||||
|
skipNextToken = false
|
||||||
|
} else {
|
||||||
|
postProcessedTokens, skipNextToken = p.handleToken(tokens, index, postProcessedTokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return postProcessedTokens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *expressionTokeniserImpl) handleToken(tokens []*token, index int, postProcessedTokens []*token) (tokensAccum []*token, skipNextToken bool) {
|
||||||
|
skipNextToken = false
|
||||||
|
currentToken := tokens[index]
|
||||||
|
|
||||||
|
if currentToken.TokenType == traverseArrayCollect {
|
||||||
|
//need to put a traverse array then a collect currentToken
|
||||||
|
// do this by adding traverse then converting currentToken to collect
|
||||||
|
|
||||||
|
op := &Operation{OperationType: traverseArrayOpType, StringValue: "TRAVERSE_ARRAY"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
||||||
|
|
||||||
|
currentToken = &token{TokenType: openCollect}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if index != len(tokens)-1 && currentToken.AssignOperation != nil &&
|
||||||
|
tokens[index+1].TokenType == operationToken &&
|
||||||
|
tokens[index+1].Operation.OperationType == assignOpType {
|
||||||
|
currentToken.Operation = currentToken.AssignOperation
|
||||||
|
currentToken.Operation.UpdateAssign = tokens[index+1].Operation.UpdateAssign
|
||||||
|
skipNextToken = true
|
||||||
|
}
|
||||||
|
|
||||||
|
postProcessedTokens = append(postProcessedTokens, currentToken)
|
||||||
|
|
||||||
|
if index != len(tokens)-1 && currentToken.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == operationToken &&
|
||||||
|
tokens[index+1].Operation.OperationType == traversePathOpType {
|
||||||
|
op := &Operation{OperationType: shortPipeOpType, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
||||||
|
}
|
||||||
|
if index != len(tokens)-1 && currentToken.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == openCollect {
|
||||||
|
|
||||||
|
op := &Operation{OperationType: shortPipeOpType, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
||||||
|
|
||||||
|
op = &Operation{OperationType: traverseArrayOpType}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
||||||
|
}
|
||||||
|
if index != len(tokens)-1 && currentToken.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == traverseArrayCollect {
|
||||||
|
|
||||||
|
op := &Operation{OperationType: shortPipeOpType, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &token{TokenType: operationToken, Operation: op})
|
||||||
|
|
||||||
|
}
|
||||||
|
return postProcessedTokens, skipNextToken
|
||||||
|
}
|
||||||
50
pkg/yqlib/file_utils.go
Normal file
50
pkg/yqlib/file_utils.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func safelyRenameFile(from string, to string) {
|
||||||
|
if renameError := os.Rename(from, to); renameError != nil {
|
||||||
|
log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
|
||||||
|
log.Debug(renameError.Error())
|
||||||
|
// can't do this rename when running in docker to a file targeted in a mounted volume,
|
||||||
|
// so gracefully degrade to copying the entire contents.
|
||||||
|
if copyError := copyFileContents(from, to); copyError != nil {
|
||||||
|
log.Errorf("Failed copying from %v to %v", from, to)
|
||||||
|
log.Error(copyError.Error())
|
||||||
|
} else {
|
||||||
|
removeErr := os.Remove(from)
|
||||||
|
if removeErr != nil {
|
||||||
|
log.Errorf("failed removing original file: %s", from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
|
||||||
|
func copyFileContents(src, dst string) (err error) {
|
||||||
|
in, err := os.Open(src) // nolint gosec
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer safelyCloseFile(in)
|
||||||
|
out, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer safelyCloseFile(out)
|
||||||
|
if _, err = io.Copy(out, in); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return out.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func safelyCloseFile(file *os.File) {
|
||||||
|
err := file.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error closing file!")
|
||||||
|
log.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
108
pkg/yqlib/lib.go
108
pkg/yqlib/lib.go
@@ -1,3 +1,5 @@
|
|||||||
|
// Use the top level Evaluator or StreamEvaluator to evaluate expressions and return matches.
|
||||||
|
//
|
||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,77 +11,87 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OperationType struct {
|
var log = logging.MustGetLogger("yq-lib")
|
||||||
|
|
||||||
|
type operationType struct {
|
||||||
Type string
|
Type string
|
||||||
NumArgs uint // number of arguments to the op
|
NumArgs uint // number of arguments to the op
|
||||||
Precedence uint
|
Precedence uint
|
||||||
Handler OperatorHandler
|
Handler operatorHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
// operators TODO:
|
// operators TODO:
|
||||||
// - get path operator (like doc index)
|
|
||||||
// - get file index op (like doc index)
|
|
||||||
// - get file name op (like doc index)
|
|
||||||
// - write in place
|
|
||||||
// - mergeAppend (merges and appends arrays)
|
|
||||||
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
// - mergeEmpty (sets only if the document is empty, do I do that now?)
|
||||||
// - compare ??
|
|
||||||
// - validate ??
|
|
||||||
// - exists
|
|
||||||
|
|
||||||
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
|
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
||||||
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator}
|
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
||||||
|
|
||||||
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
|
var unionOpType = &operationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: unionOperator}
|
||||||
|
|
||||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
var pipeOpType = &operationType{Type: "PIPE", NumArgs: 2, Precedence: 30, Handler: pipeOperator}
|
||||||
|
|
||||||
var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: AssignAttributesOperator}
|
var assignOpType = &operationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: assignUpdateOperator}
|
||||||
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
var addAssignOpType = &operationType{Type: "ADD_ASSIGN", NumArgs: 2, Precedence: 40, Handler: addAssignOperator}
|
||||||
var AssignTag = &OperationType{Type: "ASSIGN_TAG", NumArgs: 2, Precedence: 40, Handler: AssignTagOperator}
|
|
||||||
var AssignComment = &OperationType{Type: "ASSIGN_COMMENT", NumArgs: 2, Precedence: 40, Handler: AssignCommentsOperator}
|
|
||||||
|
|
||||||
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 40, Handler: MultiplyOperator}
|
var assignAttributesOpType = &operationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: assignAttributesOperator}
|
||||||
|
var assignStyleOpType = &operationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: assignStyleOperator}
|
||||||
|
var assignTagOpType = &operationType{Type: "ASSIGN_TAG", NumArgs: 2, Precedence: 40, Handler: assignTagOperator}
|
||||||
|
var assignCommentOpType = &operationType{Type: "ASSIGN_COMMENT", NumArgs: 2, Precedence: 40, Handler: assignCommentsOperator}
|
||||||
|
var assignAnchorOpType = &operationType{Type: "ASSIGN_ANCHOR", NumArgs: 2, Precedence: 40, Handler: assignAnchorOperator}
|
||||||
|
var assignAliasOpType = &operationType{Type: "ASSIGN_ALIAS", NumArgs: 2, Precedence: 40, Handler: assignAliasOperator}
|
||||||
|
|
||||||
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
|
var multiplyOpType = &operationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 45, Handler: multiplyOperator}
|
||||||
var CreateMap = &OperationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: CreateMapOperator}
|
var addOpType = &operationType{Type: "ADD", NumArgs: 2, Precedence: 45, Handler: addOperator}
|
||||||
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 45, Handler: alternativeOperator}
|
||||||
|
|
||||||
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
|
var equalsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: equalsOperator}
|
||||||
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: createMapOperator}
|
||||||
var GetStyle = &OperationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: GetStyleOperator}
|
|
||||||
var GetTag = &OperationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: GetTagOperator}
|
|
||||||
var GetComment = &OperationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: GetCommentsOperator}
|
|
||||||
var GetDocumentIndex = &OperationType{Type: "GET_DOCUMENT_INDEX", NumArgs: 0, Precedence: 50, Handler: GetDocumentIndexOperator}
|
|
||||||
|
|
||||||
var Explode = &OperationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: ExplodeOperator}
|
var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator}
|
||||||
|
|
||||||
var CollectObject = &OperationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: CollectObjectOperator}
|
var lengthOpType = &operationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: lengthOperator}
|
||||||
var TraversePath = &OperationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
var collectOpType = &operationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: collectOperator}
|
||||||
|
var getStyleOpType = &operationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: getStyleOperator}
|
||||||
|
var getTagOpType = &operationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: getTagOperator}
|
||||||
|
var getCommentOpType = &operationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: getCommentsOperator}
|
||||||
|
var getAnchorOpType = &operationType{Type: "GET_ANCHOR", NumArgs: 0, Precedence: 50, Handler: getAnchorOperator}
|
||||||
|
var getAliasOptype = &operationType{Type: "GET_ALIAS", NumArgs: 0, Precedence: 50, Handler: getAliasOperator}
|
||||||
|
var getDocumentIndexOpType = &operationType{Type: "GET_DOCUMENT_INDEX", NumArgs: 0, Precedence: 50, Handler: getDocumentIndexOperator}
|
||||||
|
var getFilenameOpType = &operationType{Type: "GET_FILENAME", NumArgs: 0, Precedence: 50, Handler: getFilenameOperator}
|
||||||
|
var getFileIndexOpType = &operationType{Type: "GET_FILE_INDEX", NumArgs: 0, Precedence: 50, Handler: getFileIndexOperator}
|
||||||
|
var getPathOpType = &operationType{Type: "GET_PATH", NumArgs: 0, Precedence: 50, Handler: getPathOperator}
|
||||||
|
|
||||||
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
var explodeOpType = &operationType{Type: "EXPLODE", NumArgs: 1, Precedence: 50, Handler: explodeOperator}
|
||||||
var SelfReference = &OperationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: SelfOperator}
|
var sortKeysOpType = &operationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 50, Handler: sortKeysOperator}
|
||||||
var ValueOp = &OperationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: ValueOperator}
|
|
||||||
var Not = &OperationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: NotOperator}
|
|
||||||
var Empty = &OperationType{Type: "EMPTY", NumArgs: 50, Handler: EmptyOperator}
|
|
||||||
|
|
||||||
var RecursiveDescent = &OperationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: RecursiveDescentOperator}
|
var collectObjectOpType = &operationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: collectObjectOperator}
|
||||||
|
var traversePathOpType = &operationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: traversePathOperator}
|
||||||
|
var traverseArrayOpType = &operationType{Type: "TRAVERSE_ARRAY", NumArgs: 1, Precedence: 50, Handler: traverseArrayOperator}
|
||||||
|
|
||||||
var Select = &OperationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: SelectOperator}
|
var documentFilterOpType = &operationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: traversePathOperator}
|
||||||
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 1, Precedence: 40, Handler: DeleteChildOperator}
|
var selfReferenceOpType = &operationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: selfOperator}
|
||||||
|
var valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
||||||
|
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
||||||
|
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||||
|
var emptyOpType = &operationType{Type: "EMPTY", NumArgs: 50, Handler: emptyOperator}
|
||||||
|
|
||||||
// var Exists = &OperationType{Type: "Length", NumArgs: 2, Precedence: 35}
|
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
||||||
// filters matches if they have the existing path
|
|
||||||
|
var selectOpType = &operationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: selectOperator}
|
||||||
|
var hasOpType = &operationType{Type: "HAS", NumArgs: 1, Precedence: 50, Handler: hasOperator}
|
||||||
|
var deleteChildOpType = &operationType{Type: "DELETE", NumArgs: 1, Precedence: 40, Handler: deleteChildOperator}
|
||||||
|
var deleteImmediateChildOpType = &operationType{Type: "DELETE_IMMEDIATE_CHILD", NumArgs: 1, Precedence: 40, Handler: deleteImmediateChildOperator}
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
OperationType *OperationType
|
OperationType *operationType
|
||||||
Value interface{}
|
Value interface{}
|
||||||
StringValue string
|
StringValue string
|
||||||
CandidateNode *CandidateNode // used for Value Path elements
|
CandidateNode *CandidateNode // used for Value Path elements
|
||||||
Preferences interface{}
|
Preferences interface{}
|
||||||
|
UpdateAssign bool // used for assign ops, when true it means we evaluate the rhs given the lhs
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
func createValueOperation(value interface{}, stringValue string) *Operation {
|
||||||
var node yaml.Node = yaml.Node{Kind: yaml.ScalarNode}
|
var node yaml.Node = yaml.Node{Kind: yaml.ScalarNode}
|
||||||
node.Value = stringValue
|
node.Value = stringValue
|
||||||
|
|
||||||
@@ -97,7 +109,7 @@ func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Operation{
|
return &Operation{
|
||||||
OperationType: ValueOp,
|
OperationType: valueOpType,
|
||||||
Value: value,
|
Value: value,
|
||||||
StringValue: stringValue,
|
StringValue: stringValue,
|
||||||
CandidateNode: &CandidateNode{Node: &node},
|
CandidateNode: &CandidateNode{Node: &node},
|
||||||
@@ -106,13 +118,13 @@ func CreateValueOperation(value interface{}, stringValue string) *Operation {
|
|||||||
|
|
||||||
// debugging purposes only
|
// debugging purposes only
|
||||||
func (p *Operation) toString() string {
|
func (p *Operation) toString() string {
|
||||||
if p.OperationType == TraversePath {
|
if p.OperationType == traversePathOpType {
|
||||||
return fmt.Sprintf("%v", p.Value)
|
return fmt.Sprintf("%v", p.Value)
|
||||||
} else if p.OperationType == DocumentFilter {
|
} else if p.OperationType == documentFilterOpType {
|
||||||
return fmt.Sprintf("d%v", p.Value)
|
return fmt.Sprintf("d%v", p.Value)
|
||||||
} else if p.OperationType == SelfReference {
|
} else if p.OperationType == selfReferenceOpType {
|
||||||
return "SELF"
|
return "SELF"
|
||||||
} else if p.OperationType == ValueOp {
|
} else if p.OperationType == valueOpType {
|
||||||
return fmt.Sprintf("%v (%T)", p.Value, p.Value)
|
return fmt.Sprintf("%v (%T)", p.Value, p.Value)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%v", p.OperationType.Type)
|
return fmt.Sprintf("%v", p.OperationType.Type)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
func Match(name string, pattern string) (matched bool) {
|
func matchKey(name string, pattern string) (matched bool) {
|
||||||
if pattern == "" {
|
if pattern == "" {
|
||||||
return name == pattern
|
return name == pattern
|
||||||
}
|
}
|
||||||
|
|||||||
107
pkg/yqlib/operator_add.go
Normal file
107
pkg/yqlib/operator_add.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"container/list"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createAddOp(lhs *ExpressionNode, rhs *ExpressionNode) *ExpressionNode {
|
||||||
|
return &ExpressionNode{Operation: &Operation{OperationType: addOpType},
|
||||||
|
Lhs: lhs,
|
||||||
|
Rhs: rhs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addAssignOperator(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
|
||||||
|
assignmentOp := &Operation{OperationType: assignOpType}
|
||||||
|
assignmentOp.UpdateAssign = false
|
||||||
|
|
||||||
|
assignmentOpNode := &ExpressionNode{Operation: assignmentOp, Lhs: expressionNode.Lhs, Rhs: createAddOp(expressionNode.Lhs, expressionNode.Rhs)}
|
||||||
|
return d.GetMatchingNodes(matchingNodes, assignmentOpNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toNodes(candidate *CandidateNode) []*yaml.Node {
|
||||||
|
if candidate.Node.Tag == "!!null" {
|
||||||
|
return []*yaml.Node{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch candidate.Node.Kind {
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return candidate.Node.Content
|
||||||
|
default:
|
||||||
|
return []*yaml.Node{candidate.Node}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func addOperator(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
|
||||||
|
log.Debugf("Add operator")
|
||||||
|
|
||||||
|
return crossFunction(d, matchingNodes, expressionNode, add)
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
lhs.Node = unwrapDoc(lhs.Node)
|
||||||
|
rhs.Node = unwrapDoc(rhs.Node)
|
||||||
|
|
||||||
|
target := lhs.CreateChild(nil, &yaml.Node{})
|
||||||
|
lhsNode := lhs.Node
|
||||||
|
|
||||||
|
switch lhsNode.Kind {
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return nil, fmt.Errorf("Maps not yet supported for addition")
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
target.Node.Kind = yaml.SequenceNode
|
||||||
|
target.Node.Style = lhsNode.Style
|
||||||
|
target.Node.Tag = "!!seq"
|
||||||
|
target.Node.Content = append(lhsNode.Content, toNodes(rhs)...)
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
if rhs.Node.Kind != yaml.ScalarNode {
|
||||||
|
return nil, fmt.Errorf("%v (%v) cannot be added to a %v", rhs.Node.Tag, rhs.Path, lhsNode.Tag)
|
||||||
|
}
|
||||||
|
target.Node.Kind = yaml.ScalarNode
|
||||||
|
target.Node.Style = lhsNode.Style
|
||||||
|
return addScalars(target, lhsNode, rhs.Node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addScalars(target *CandidateNode, lhs *yaml.Node, rhs *yaml.Node) (*CandidateNode, error) {
|
||||||
|
|
||||||
|
if lhs.Tag == "!!str" {
|
||||||
|
target.Node.Tag = "!!str"
|
||||||
|
target.Node.Value = lhs.Value + rhs.Value
|
||||||
|
} else if lhs.Tag == "!!int" && rhs.Tag == "!!int" {
|
||||||
|
lhsNum, err := strconv.Atoi(lhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rhsNum, err := strconv.Atoi(rhs.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sum := lhsNum + rhsNum
|
||||||
|
target.Node.Tag = "!!int"
|
||||||
|
target.Node.Value = fmt.Sprintf("%v", sum)
|
||||||
|
} else if (lhs.Tag == "!!int" || lhs.Tag == "!!float") && (rhs.Tag == "!!int" || rhs.Tag == "!!float") {
|
||||||
|
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sum := lhsNum + rhsNum
|
||||||
|
target.Node.Tag = "!!float"
|
||||||
|
target.Node.Value = fmt.Sprintf("%v", sum)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("%v cannot be added to %v", lhs.Tag, rhs.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
113
pkg/yqlib/operator_add_test.go
Normal file
113
pkg/yqlib/operator_add_test.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var addOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Concatenate and assign arrays",
|
||||||
|
document: `{a: {val: thing, b: [cat,dog]}}`,
|
||||||
|
expression: ".a.b += [\"cow\"]",
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: {val: thing, b: [cat, dog, cow]}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Concatenate arrays",
|
||||||
|
document: `{a: [1,2], b: [3,4]}`,
|
||||||
|
expression: `.a + .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!seq)::[1, 2, 3, 4]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
expression: `[1] + ([2], [3])`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::- 1\n- 2\n",
|
||||||
|
"D0, P[], (!!seq)::- 1\n- 3\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Concatenate null to array",
|
||||||
|
document: `{a: [1,2]}`,
|
||||||
|
expression: `.a + null`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!seq)::[1, 2]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Add new object to array",
|
||||||
|
document: `a: [{dog: woof}]`,
|
||||||
|
expression: `.a + {"cat": "meow"}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!seq)::[{dog: woof}, {cat: meow}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Add string to array",
|
||||||
|
document: `{a: [1,2]}`,
|
||||||
|
expression: `.a + "hello"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!seq)::[1, 2, hello]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Update array (append)",
|
||||||
|
document: `{a: [1,2], b: [3,4]}`,
|
||||||
|
expression: `.a = .a + .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: [1, 2, 3, 4], b: [3, 4]}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "String concatenation",
|
||||||
|
document: `{a: cat, b: meow}`,
|
||||||
|
expression: `.a = .a + .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: catmeow, b: meow}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Relative string concatenation",
|
||||||
|
document: `{a: cat, b: meow}`,
|
||||||
|
expression: `.a += .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: catmeow, b: meow}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Number addition - float",
|
||||||
|
subdescription: "If the lhs or rhs are floats then the expression will be calculated with floats.",
|
||||||
|
document: `{a: 3, b: 4.9}`,
|
||||||
|
expression: `.a = .a + .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: 7.9, b: 4.9}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Number addition - int",
|
||||||
|
subdescription: "If both the lhs and rhs are ints then the expression will be calculated with ints.",
|
||||||
|
document: `{a: 3, b: 4}`,
|
||||||
|
expression: `.a = .a + .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: 7, b: 4}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Increment number",
|
||||||
|
document: `{a: 3}`,
|
||||||
|
expression: `.a += 1`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: 4}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range addOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Add", addOperatorScenarios)
|
||||||
|
}
|
||||||
28
pkg/yqlib/operator_alternative.go
Normal file
28
pkg/yqlib/operator_alternative.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
// corssFunction no matches
|
||||||
|
// can boolean use crossfunction
|
||||||
|
|
||||||
|
func alternativeOperator(d *dataTreeNavigator, matchingNodes *list.List, expressionNode *ExpressionNode) (*list.List, error) {
|
||||||
|
log.Debugf("-- alternative")
|
||||||
|
return crossFunction(d, matchingNodes, expressionNode, alternativeFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func alternativeFunc(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
|
lhs.Node = unwrapDoc(lhs.Node)
|
||||||
|
rhs.Node = unwrapDoc(rhs.Node)
|
||||||
|
log.Debugf("Alternative LHS: %v", lhs.Node.Tag)
|
||||||
|
log.Debugf("- RHS: %v", rhs.Node.Tag)
|
||||||
|
|
||||||
|
isTrue, err := isTruthy(lhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if isTrue {
|
||||||
|
return lhs, nil
|
||||||
|
}
|
||||||
|
return rhs, nil
|
||||||
|
}
|
||||||
62
pkg/yqlib/operator_alternative_test.go
Normal file
62
pkg/yqlib/operator_alternative_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var alternativeOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "LHS is defined",
|
||||||
|
expression: `.a // "hello"`,
|
||||||
|
document: `{a: bridge}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!str)::bridge\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "LHS is not defined",
|
||||||
|
expression: `.a // "hello"`,
|
||||||
|
document: `{}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "LHS is null",
|
||||||
|
expression: `.a // "hello"`,
|
||||||
|
document: `{a: ~}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "LHS is false",
|
||||||
|
expression: `.a // "hello"`,
|
||||||
|
document: `{a: false}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::hello\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "RHS is an expression",
|
||||||
|
expression: `.a // .b`,
|
||||||
|
document: `{a: false, b: cat}`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[b], (!!str)::cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
expression: `false // true`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlternativeOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range alternativeOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Alternative (Default value)", alternativeOperatorScenarios)
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user