mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
77 Commits
4.0.0-beta
...
cswarth-do
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
f42728eef7 | ||
|
|
93136ba840 | ||
|
|
5665dc7b71 | ||
|
|
9302279dd2 | ||
|
|
5972bb2f23 | ||
|
|
ec43f5e7c3 | ||
|
|
62f262147c | ||
|
|
0259bb44c1 | ||
|
|
e07a5b6065 | ||
|
|
f69a81b79b | ||
|
|
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,12 @@ 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:
|
Version of yq: 3.X.X
|
||||||
operating system:
|
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
|
||||||
49
.github/ISSUE_TEMPLATE/bug_report_v4.md
vendored
Normal file
49
.github/ISSUE_TEMPLATE/bug_report_v4.md
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,17 +1,21 @@
|
|||||||
---
|
---
|
||||||
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.
|
||||||
|
Ex. I wish I could use yq to [...]
|
||||||
|
|
||||||
|
Please note that 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 +24,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
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
90
README.md
90
README.md
@@ -7,11 +7,17 @@ a lightweight and portable command-line YAML processor
|
|||||||
|
|
||||||
The aim of the project is to be the [jq](https://github.com/stedolan/jq) or sed of yaml files.
|
The aim of the project is to be the [jq](https://github.com/stedolan/jq) or sed of yaml files.
|
||||||
|
|
||||||
|
## 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).
|
||||||
|
|
||||||
## 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:
|
### MacOS:
|
||||||
|
Using [Homebrew](https://brew.sh/)
|
||||||
```
|
```
|
||||||
brew install yq
|
brew install yq
|
||||||
```
|
```
|
||||||
@@ -25,16 +31,16 @@ snap install yq
|
|||||||
`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
|
||||||
```
|
```
|
||||||
@@ -44,19 +50,18 @@ rm /etc/myfile.tmp
|
|||||||
Use wget to download the pre-compiled binaries:
|
Use wget to download the pre-compiled binaries:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/mikefarah/yq/releases/download/{VERSION}/{BINARY} -O /usr/bin/yq &&\
|
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq &&\
|
||||||
chmod +x /usr/bin/yq
|
chmod +x /usr/bin/yq
|
||||||
```
|
```
|
||||||
|
|
||||||
For instance, VERSION=3.4.0 and BINARY=yq_linux_amd64
|
For instance, VERSION=4.0.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,13 +74,13 @@ 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
|
||||||
@@ -88,6 +93,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 +121,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 +144,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)
|
|
||||||
|
|||||||
@@ -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 completedSuccessfully = false
|
var completedSuccessfully = false
|
||||||
|
|||||||
@@ -15,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,
|
||||||
@@ -66,19 +65,19 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
|
|||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = allAtOnceEvaluator.EvaluateFiles("", []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.NewStreamEvaluator().EvaluateNew(args[0], printer)
|
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer)
|
||||||
} else {
|
} else {
|
||||||
err = allAtOnceEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = allAtOnceEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
completedSuccessfully = err == nil
|
completedSuccessfully = err == nil
|
||||||
|
|||||||
@@ -15,15 +15,34 @@ 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
|
cmd.SilenceUsage = true
|
||||||
// 0 args, read std in
|
// 0 args, read std in
|
||||||
@@ -67,16 +86,16 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
|||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
if pipingStdIn {
|
if pipingStdIn {
|
||||||
err = streamEvaluator.EvaluateFiles("", []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 = streamEvaluator.EvaluateNew(args[0], printer)
|
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer)
|
||||||
} else {
|
} else {
|
||||||
err = streamEvaluator.EvaluateFiles("", []string{args[0]}, printer)
|
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ 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(&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(&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")
|
||||||
|
|||||||
@@ -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-beta1"
|
Version = "4.2.0"
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM mikefarah/yq:3
|
FROM mikefarah/yq:4.2.0
|
||||||
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -6,8 +6,7 @@ require (
|
|||||||
github.com/goccy/go-yaml v1.8.1
|
github.com/goccy/go-yaml v1.8.1
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||||
github.com/mattn/go-colorable v0.1.7 // indirect
|
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.1.1
|
||||||
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-20200930185726-fdedc70b468f // indirect
|
||||||
|
|||||||
180
go.sum
180
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=
|
||||||
@@ -26,6 +43,7 @@ github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
|||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/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=
|
||||||
@@ -39,20 +57,54 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||||||
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.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o=
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
|
||||||
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,11 +116,13 @@ 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.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||||
github.com/mattn/go-colorable v0.1.7/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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||||
@@ -76,14 +130,26 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
|
|||||||
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 +160,171 @@ 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/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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-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-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
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/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-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
gopkg.in/go-playground/validator.v9 v9.30.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/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 +332,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.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
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-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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=
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ 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) CreateChildPath(path interface{}) []interface{} {
|
||||||
|
//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)
|
||||||
|
|||||||
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
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,4 +1,67 @@
|
|||||||
Explodes (or dereferences) aliases and anchors.
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
```
|
||||||
|
|
||||||
## Explode alias and anchor
|
## Explode alias and anchor
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
@@ -8,7 +8,7 @@ This will do a similar thing to the plain form, however, the RHS expression is r
|
|||||||
## Create yaml file
|
## Create yaml file
|
||||||
Running
|
Running
|
||||||
```bash
|
```bash
|
||||||
yq eval --null-input '(.a.b = "cat") | (.x = "frog")'
|
yq eval --null-input '.a.b = "cat" | .x = "frog"'
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -112,7 +112,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
|
||||||
@@ -130,7 +130,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
|
||||||
|
|||||||
@@ -14,6 +14,23 @@ will output
|
|||||||
a: cat
|
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
|
## Delete entry in array
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
@@ -31,6 +48,21 @@ will output
|
|||||||
- 3
|
- 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
|
## Delete no matches
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ a: frog
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval 'select(. | documentIndex == 1)' sample.yml
|
yq eval 'select(documentIndex == 1)' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -42,7 +42,7 @@ a: frog
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.a | ({"match": ., "doc": (. | documentIndex)})' sample.yml
|
yq eval '.a | ({"match": ., "doc": documentIndex})' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
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
|
||||||
|
```
|
||||||
|
|
||||||
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
|
||||||
|
```
|
||||||
|
|
||||||
@@ -1,8 +1,55 @@
|
|||||||
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:
|
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. 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
|
```bash
|
||||||
yq eval '.. style= "flow"' file.yaml
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
## Aliases are not traversed
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -40,6 +40,26 @@ c: "3.2"
|
|||||||
e: "true"
|
e: "true"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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
|
## Set single quote style
|
||||||
Given a sample.yml file of:
|
Given a sample.yml file of:
|
||||||
```yaml
|
```yaml
|
||||||
@@ -126,18 +146,18 @@ will output
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Pretty print
|
## Pretty print
|
||||||
Set empty (default) quote style
|
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
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ b: *cat
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.b.[]' sample.yml
|
yq eval '.b[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -290,7 +290,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobar.[]' sample.yml
|
yq eval '.foobar[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -356,7 +356,7 @@ foobar:
|
|||||||
```
|
```
|
||||||
then
|
then
|
||||||
```bash
|
```bash
|
||||||
yq eval '.foobarList.[]' sample.yml
|
yq eval '.foobarList[]' sample.yml
|
||||||
```
|
```
|
||||||
will output
|
will output
|
||||||
```yaml
|
```yaml
|
||||||
@@ -366,3 +366,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
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 +0,0 @@
|
|||||||
Explodes (or dereferences) aliases and anchors.
|
|
||||||
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.
|
||||||
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.
|
||||||
@@ -1,5 +1,19 @@
|
|||||||
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:
|
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. 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
|
```bash
|
||||||
yq eval '.. style= "flow"' file.yaml
|
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
|
||||||
```
|
```
|
||||||
@@ -19,16 +19,16 @@ type OperationType struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// operators TODO:
|
// operators TODO:
|
||||||
// - cookbook doc for common things
|
// - keys operator for controlling key metadata (particularly anchors/aliases)
|
||||||
// - 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 ??
|
|
||||||
|
|
||||||
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
|
var Or = &OperationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: OrOperator}
|
||||||
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator}
|
var And = &OperationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: AndOperator}
|
||||||
|
|
||||||
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
|
var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: UnionOperator}
|
||||||
|
|
||||||
|
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 30, Handler: PipeOperator}
|
||||||
|
|
||||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
||||||
var AddAssign = &OperationType{Type: "ADD_ASSIGN", NumArgs: 2, Precedence: 40, Handler: AddAssignOperator}
|
var AddAssign = &OperationType{Type: "ADD_ASSIGN", NumArgs: 2, Precedence: 40, Handler: AddAssignOperator}
|
||||||
|
|
||||||
@@ -36,19 +36,25 @@ var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Pre
|
|||||||
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
||||||
var AssignTag = &OperationType{Type: "ASSIGN_TAG", NumArgs: 2, Precedence: 40, Handler: AssignTagOperator}
|
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 AssignComment = &OperationType{Type: "ASSIGN_COMMENT", NumArgs: 2, Precedence: 40, Handler: AssignCommentsOperator}
|
||||||
|
var AssignAnchor = &OperationType{Type: "ASSIGN_ANCHOR", NumArgs: 2, Precedence: 40, Handler: AssignAnchorOperator}
|
||||||
|
var AssignAlias = &OperationType{Type: "ASSIGN_ALIAS", NumArgs: 2, Precedence: 40, Handler: AssignAliasOperator}
|
||||||
|
|
||||||
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 45, Handler: MultiplyOperator}
|
var Multiply = &OperationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 45, Handler: MultiplyOperator}
|
||||||
var Add = &OperationType{Type: "ADD", NumArgs: 2, Precedence: 45, Handler: AddOperator}
|
var Add = &OperationType{Type: "ADD", NumArgs: 2, Precedence: 45, Handler: AddOperator}
|
||||||
|
var Alternative = &OperationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 45, Handler: AlternativeOperator}
|
||||||
|
|
||||||
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
|
var Equals = &OperationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: EqualsOperator}
|
||||||
var CreateMap = &OperationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: CreateMapOperator}
|
var CreateMap = &OperationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: CreateMapOperator}
|
||||||
var Pipe = &OperationType{Type: "PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
|
||||||
|
var ShortPipe = &OperationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: PipeOperator}
|
||||||
|
|
||||||
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
|
var Length = &OperationType{Type: "LENGTH", NumArgs: 0, Precedence: 50, Handler: LengthOperator}
|
||||||
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
var Collect = &OperationType{Type: "COLLECT", NumArgs: 0, Precedence: 50, Handler: CollectOperator}
|
||||||
var GetStyle = &OperationType{Type: "GET_STYLE", NumArgs: 0, Precedence: 50, Handler: GetStyleOperator}
|
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 GetTag = &OperationType{Type: "GET_TAG", NumArgs: 0, Precedence: 50, Handler: GetTagOperator}
|
||||||
var GetComment = &OperationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: GetCommentsOperator}
|
var GetComment = &OperationType{Type: "GET_COMMENT", NumArgs: 0, Precedence: 50, Handler: GetCommentsOperator}
|
||||||
|
var GetAnchor = &OperationType{Type: "GET_ANCHOR", NumArgs: 0, Precedence: 50, Handler: GetAnchorOperator}
|
||||||
|
var GetAlias = &OperationType{Type: "GET_ALIAS", NumArgs: 0, Precedence: 50, Handler: GetAliasOperator}
|
||||||
var GetDocumentIndex = &OperationType{Type: "GET_DOCUMENT_INDEX", NumArgs: 0, Precedence: 50, Handler: GetDocumentIndexOperator}
|
var GetDocumentIndex = &OperationType{Type: "GET_DOCUMENT_INDEX", NumArgs: 0, Precedence: 50, Handler: GetDocumentIndexOperator}
|
||||||
var GetFilename = &OperationType{Type: "GET_FILENAME", NumArgs: 0, Precedence: 50, Handler: GetFilenameOperator}
|
var GetFilename = &OperationType{Type: "GET_FILENAME", NumArgs: 0, Precedence: 50, Handler: GetFilenameOperator}
|
||||||
var GetFileIndex = &OperationType{Type: "GET_FILE_INDEX", NumArgs: 0, Precedence: 50, Handler: GetFileIndexOperator}
|
var GetFileIndex = &OperationType{Type: "GET_FILE_INDEX", NumArgs: 0, Precedence: 50, Handler: GetFileIndexOperator}
|
||||||
@@ -59,6 +65,7 @@ var SortKeys = &OperationType{Type: "SORT_KEYS", NumArgs: 1, Precedence: 50, Han
|
|||||||
|
|
||||||
var CollectObject = &OperationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: CollectObjectOperator}
|
var CollectObject = &OperationType{Type: "COLLECT_OBJECT", NumArgs: 0, Precedence: 50, Handler: CollectObjectOperator}
|
||||||
var TraversePath = &OperationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
var TraversePath = &OperationType{Type: "TRAVERSE_PATH", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
||||||
|
var TraverseArray = &OperationType{Type: "TRAVERSE_ARRAY", NumArgs: 1, Precedence: 50, Handler: TraverseArrayOperator}
|
||||||
|
|
||||||
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
var DocumentFilter = &OperationType{Type: "DOCUMENT_FILTER", NumArgs: 0, Precedence: 50, Handler: TraversePathOperator}
|
||||||
var SelfReference = &OperationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: SelfOperator}
|
var SelfReference = &OperationType{Type: "SELF", NumArgs: 0, Precedence: 50, Handler: SelfOperator}
|
||||||
@@ -71,6 +78,7 @@ var RecursiveDescent = &OperationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Pre
|
|||||||
var Select = &OperationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: SelectOperator}
|
var Select = &OperationType{Type: "SELECT", NumArgs: 1, Precedence: 50, Handler: SelectOperator}
|
||||||
var Has = &OperationType{Type: "HAS", NumArgs: 1, Precedence: 50, Handler: HasOperator}
|
var Has = &OperationType{Type: "HAS", NumArgs: 1, Precedence: 50, Handler: HasOperator}
|
||||||
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 1, Precedence: 40, Handler: DeleteChildOperator}
|
var DeleteChild = &OperationType{Type: "DELETE", NumArgs: 1, Precedence: 40, Handler: DeleteChildOperator}
|
||||||
|
var DeleteImmediateChild = &OperationType{Type: "DELETE_IMMEDIATE_CHILD", NumArgs: 1, Precedence: 40, Handler: DeleteImmediateChildOperator}
|
||||||
|
|
||||||
type Operation struct {
|
type Operation struct {
|
||||||
OperationType *OperationType
|
OperationType *OperationType
|
||||||
|
|||||||
@@ -22,13 +22,7 @@ func AddAssignOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode
|
|||||||
return d.GetMatchingNodes(matchingNodes, assignmentOpNode)
|
return d.GetMatchingNodes(matchingNodes, assignmentOpNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toNodes(candidates *list.List) []*yaml.Node {
|
func toNodes(candidate *CandidateNode) []*yaml.Node {
|
||||||
|
|
||||||
if candidates.Len() == 0 {
|
|
||||||
return []*yaml.Node{}
|
|
||||||
}
|
|
||||||
candidate := candidates.Front().Value.(*CandidateNode)
|
|
||||||
|
|
||||||
if candidate.Node.Tag == "!!null" {
|
if candidate.Node.Tag == "!!null" {
|
||||||
return []*yaml.Node{}
|
return []*yaml.Node{}
|
||||||
}
|
}
|
||||||
@@ -44,40 +38,33 @@ func toNodes(candidates *list.List) []*yaml.Node {
|
|||||||
|
|
||||||
func AddOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func AddOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("Add operator")
|
log.Debugf("Add operator")
|
||||||
var results = list.New()
|
|
||||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
|
||||||
|
|
||||||
if err != nil {
|
return crossFunction(d, matchingNodes, pathNode, add)
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
func add(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
lhs.Node = UnwrapDoc(lhs.Node)
|
||||||
lhsCandidate := el.Value.(*CandidateNode)
|
rhs.Node = UnwrapDoc(rhs.Node)
|
||||||
lhsNode := UnwrapDoc(lhsCandidate.Node)
|
|
||||||
|
target := &CandidateNode{
|
||||||
target := &CandidateNode{
|
Path: lhs.Path,
|
||||||
Path: lhsCandidate.Path,
|
Document: lhs.Document,
|
||||||
Document: lhsCandidate.Document,
|
Filename: lhs.Filename,
|
||||||
Filename: lhsCandidate.Filename,
|
Node: &yaml.Node{},
|
||||||
Node: &yaml.Node{},
|
}
|
||||||
}
|
lhsNode := lhs.Node
|
||||||
|
|
||||||
switch lhsNode.Kind {
|
switch lhsNode.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
return nil, fmt.Errorf("Maps not yet supported for addition")
|
return nil, fmt.Errorf("Maps not yet supported for addition")
|
||||||
case yaml.SequenceNode:
|
case yaml.SequenceNode:
|
||||||
target.Node.Kind = yaml.SequenceNode
|
target.Node.Kind = yaml.SequenceNode
|
||||||
target.Node.Style = lhsNode.Style
|
target.Node.Style = lhsNode.Style
|
||||||
target.Node.Tag = "!!seq"
|
target.Node.Tag = "!!seq"
|
||||||
target.Node.Content = append(lhsNode.Content, toNodes(rhs)...)
|
target.Node.Content = append(lhsNode.Content, toNodes(rhs)...)
|
||||||
results.PushBack(target)
|
case yaml.ScalarNode:
|
||||||
case yaml.ScalarNode:
|
return nil, fmt.Errorf("Scalars not yet supported for addition")
|
||||||
return nil, fmt.Errorf("Scalars not yet supported for addition")
|
}
|
||||||
}
|
|
||||||
}
|
return target, nil
|
||||||
return results, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ var addOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a], (!!seq)::[1, 2, 3, 4]\n",
|
"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",
|
description: "Concatenate null to array",
|
||||||
document: `{a: [1,2]}`,
|
document: `{a: [1,2]}`,
|
||||||
|
|||||||
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, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
log.Debugf("-- alternative")
|
||||||
|
return crossFunction(d, matchingNodes, pathNode, 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)
|
||||||
|
}
|
||||||
@@ -6,6 +6,88 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func AssignAliasOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
|
||||||
|
log.Debugf("AssignAlias operator!")
|
||||||
|
|
||||||
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
aliasName := ""
|
||||||
|
if rhs.Front() != nil {
|
||||||
|
aliasName = rhs.Front().Value.(*CandidateNode).Node.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
log.Debugf("Setting aliasName : %v", candidate.GetKey())
|
||||||
|
candidate.Node.Kind = yaml.AliasNode
|
||||||
|
candidate.Node.Value = aliasName
|
||||||
|
}
|
||||||
|
return matchingNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAliasOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
log.Debugf("GetAlias operator!")
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
node := &yaml.Node{Kind: yaml.ScalarNode, Value: candidate.Node.Value, Tag: "!!str"}
|
||||||
|
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||||
|
results.PushBack(lengthCand)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AssignAnchorOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
|
||||||
|
log.Debugf("AssignAnchor operator!")
|
||||||
|
|
||||||
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
anchorName := ""
|
||||||
|
if rhs.Front() != nil {
|
||||||
|
anchorName = rhs.Front().Value.(*CandidateNode).Node.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
log.Debugf("Setting anchorName of : %v", candidate.GetKey())
|
||||||
|
candidate.Node.Anchor = anchorName
|
||||||
|
}
|
||||||
|
return matchingNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAnchorOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
log.Debugf("GetAnchor operator!")
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
anchor := candidate.Node.Anchor
|
||||||
|
node := &yaml.Node{Kind: yaml.ScalarNode, Value: anchor, Tag: "!!str"}
|
||||||
|
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||||
|
results.PushBack(lengthCand)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ExplodeOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func ExplodeOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("-- ExplodeOperation")
|
log.Debugf("-- ExplodeOperation")
|
||||||
|
|
||||||
@@ -4,7 +4,39 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var explodeTest = []expressionScenario{
|
var anchorOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Get anchor",
|
||||||
|
document: `a: &billyBob cat`,
|
||||||
|
expression: `.a | anchor`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!str)::billyBob\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Set anchor",
|
||||||
|
document: `a: cat`,
|
||||||
|
expression: `.a anchor = "foobar"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::a: &foobar cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Get alias",
|
||||||
|
document: `{b: &billyBob meow, a: *billyBob}`,
|
||||||
|
expression: `.a | alias`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!str)::billyBob\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Set alias",
|
||||||
|
document: `{b: &meow purr, a: cat}`,
|
||||||
|
expression: `.a alias = "meow"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{b: &meow purr, a: *meow}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Explode alias and anchor",
|
description: "Explode alias and anchor",
|
||||||
document: `{f : {a: &a cat, b: *a}}`,
|
document: `{f : {a: &a cat, b: *a}}`,
|
||||||
@@ -82,9 +114,9 @@ foobar:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExplodeOperatorScenarios(t *testing.T) {
|
func TestAnchorAliaseOperatorScenarios(t *testing.T) {
|
||||||
for _, tt := range explodeTest {
|
for _, tt := range anchorOperatorScenarios {
|
||||||
testScenario(t, &tt)
|
testScenario(t, &tt)
|
||||||
}
|
}
|
||||||
documentScenarios(t, "Explode", explodeTest)
|
documentScenarios(t, "Anchor and Alias Operators", anchorOperatorScenarios)
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
var assignOperatorScenarios = []expressionScenario{
|
var assignOperatorScenarios = []expressionScenario{
|
||||||
{
|
{
|
||||||
description: "Create yaml file",
|
description: "Create yaml file",
|
||||||
expression: `(.a.b = "cat") | (.x = "frog")`,
|
expression: `.a.b = "cat" | .x = "frog"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], ()::a:\n b: cat\nx: frog\n",
|
"D0, P[], ()::a:\n b: cat\nx: frog\n",
|
||||||
},
|
},
|
||||||
@@ -80,7 +80,15 @@ var assignOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Update selected results",
|
description: "Update selected results",
|
||||||
document: `{a: {b: apple, c: cactus}}`,
|
document: `{a: {b: apple, c: cactus}}`,
|
||||||
expression: `.a.[] | select(. == "apple") |= "frog"`,
|
expression: `(.a[] | select(. == "apple")) = "frog"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: {b: apple, c: cactus}}`,
|
||||||
|
expression: `(.a.[] | select(. == "apple")) = "frog"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
"D0, P[], (doc)::{a: {b: frog, c: cactus}}\n",
|
||||||
},
|
},
|
||||||
@@ -88,7 +96,7 @@ var assignOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Update array values",
|
description: "Update array values",
|
||||||
document: `[candy, apple, sandy]`,
|
document: `[candy, apple, sandy]`,
|
||||||
expression: `.[] | select(. == "*andy") |= "bogs"`,
|
expression: `(.[] | select(. == "*andy")) = "bogs"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (doc)::[bogs, apple, bogs]\n",
|
"D0, P[], (doc)::[bogs, apple, bogs]\n",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,74 +25,39 @@ func isTruthy(c *CandidateNode) (bool, error) {
|
|||||||
|
|
||||||
type boolOp func(bool, bool) bool
|
type boolOp func(bool, bool) bool
|
||||||
|
|
||||||
func performBoolOp(results *list.List, lhs *list.List, rhs *list.List, op boolOp) error {
|
func performBoolOp(op boolOp) func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
for lhsChild := lhs.Front(); lhsChild != nil; lhsChild = lhsChild.Next() {
|
return func(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||||
lhsCandidate := lhsChild.Value.(*CandidateNode)
|
lhs.Node = UnwrapDoc(lhs.Node)
|
||||||
lhsTrue, errDecoding := isTruthy(lhsCandidate)
|
rhs.Node = UnwrapDoc(rhs.Node)
|
||||||
|
|
||||||
|
lhsTrue, errDecoding := isTruthy(lhs)
|
||||||
if errDecoding != nil {
|
if errDecoding != nil {
|
||||||
return errDecoding
|
return nil, errDecoding
|
||||||
}
|
}
|
||||||
|
|
||||||
for rhsChild := rhs.Front(); rhsChild != nil; rhsChild = rhsChild.Next() {
|
rhsTrue, errDecoding := isTruthy(rhs)
|
||||||
rhsCandidate := rhsChild.Value.(*CandidateNode)
|
if errDecoding != nil {
|
||||||
rhsTrue, errDecoding := isTruthy(rhsCandidate)
|
return nil, errDecoding
|
||||||
if errDecoding != nil {
|
|
||||||
return errDecoding
|
|
||||||
}
|
|
||||||
boolResult := createBooleanCandidate(lhsCandidate, op(lhsTrue, rhsTrue))
|
|
||||||
results.PushBack(boolResult)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createBooleanCandidate(lhs, op(lhsTrue, rhsTrue)), nil
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func booleanOp(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode, op boolOp) (*list.List, error) {
|
|
||||||
var results = list.New()
|
|
||||||
|
|
||||||
if matchingNodes.Len() == 0 {
|
|
||||||
lhs, err := d.GetMatchingNodes(list.New(), pathNode.Lhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rhs, err := d.GetMatchingNodes(list.New(), pathNode.Rhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return results, performBoolOp(results, lhs, rhs, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
|
||||||
candidate := el.Value.(*CandidateNode)
|
|
||||||
lhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Lhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = performBoolOp(results, lhs, rhs, op)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return results, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func OrOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func OrOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("-- orOp")
|
log.Debugf("-- orOp")
|
||||||
return booleanOp(d, matchingNodes, pathNode, func(b1 bool, b2 bool) bool {
|
return crossFunction(d, matchingNodes, pathNode, performBoolOp(
|
||||||
return b1 || b2
|
func(b1 bool, b2 bool) bool {
|
||||||
})
|
return b1 || b2
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func AndOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func AndOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("-- AndOp")
|
log.Debugf("-- AndOp")
|
||||||
return booleanOp(d, matchingNodes, pathNode, func(b1 bool, b2 bool) bool {
|
return crossFunction(d, matchingNodes, pathNode, performBoolOp(
|
||||||
return b1 && b2
|
func(b1 bool, b2 bool) bool {
|
||||||
})
|
return b1 && b2
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func NotOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func CollectObjectOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *
|
|||||||
func createChildCandidate(candidate *CandidateNode, index int) *CandidateNode {
|
func createChildCandidate(candidate *CandidateNode, index int) *CandidateNode {
|
||||||
return &CandidateNode{
|
return &CandidateNode{
|
||||||
Document: candidate.Document,
|
Document: candidate.Document,
|
||||||
Path: append(candidate.Path, index),
|
Path: candidate.CreateChildPath(index),
|
||||||
Filename: candidate.Filename,
|
Filename: candidate.Filename,
|
||||||
Node: candidate.Node.Content[index],
|
Node: candidate.Node.Content[index],
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,9 @@ func collect(d *dataTreeNavigator, aggregate *list.List, remainingMatches *list.
|
|||||||
}
|
}
|
||||||
|
|
||||||
candidate := remainingMatches.Remove(remainingMatches.Front()).(*CandidateNode)
|
candidate := remainingMatches.Remove(remainingMatches.Front()).(*CandidateNode)
|
||||||
splatted, err := Splat(d, nodeToMap(candidate))
|
|
||||||
|
splatted, err := Splat(d, nodeToMap(candidate),
|
||||||
|
&TraversePreferences{FollowAlias: false, IncludeMapKeys: false})
|
||||||
|
|
||||||
for splatEl := splatted.Front(); splatEl != nil; splatEl = splatEl.Next() {
|
for splatEl := splatted.Front(); splatEl != nil; splatEl = splatEl.Next() {
|
||||||
splatEl.Value.(*CandidateNode).Path = nil
|
splatEl.Value.(*CandidateNode).Path = nil
|
||||||
|
|||||||
@@ -2,39 +2,67 @@ package yqlib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func DeleteChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
// for each lhs, splat the node,
|
|
||||||
// the intersect it against the rhs expression
|
|
||||||
// recreate the contents using only the intersection result.
|
|
||||||
|
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
nodesToDelete, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for el := nodesToDelete.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
elMap := list.New()
|
|
||||||
elMap.PushBack(candidate)
|
deleteImmediateChildOp := &Operation{
|
||||||
nodesToDelete, err := d.GetMatchingNodes(elMap, pathNode.Rhs)
|
OperationType: DeleteImmediateChild,
|
||||||
log.Debug("nodesToDelete:\n%v", NodesToString(nodesToDelete))
|
Value: candidate.Path[len(candidate.Path)-1],
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
realNode := UnwrapDoc(candidate.Node)
|
deleteImmediateChildOpNode := &PathTreeNode{
|
||||||
|
Operation: deleteImmediateChildOp,
|
||||||
|
Rhs: createTraversalTree(candidate.Path[0 : len(candidate.Path)-1]),
|
||||||
|
}
|
||||||
|
|
||||||
if realNode.Kind == yaml.SequenceNode {
|
_, err := d.GetMatchingNodes(matchingNodes, deleteImmediateChildOpNode)
|
||||||
deleteFromArray(candidate, nodesToDelete)
|
if err != nil {
|
||||||
} else if realNode.Kind == yaml.MappingNode {
|
return nil, err
|
||||||
deleteFromMap(candidate, nodesToDelete)
|
|
||||||
} else {
|
|
||||||
log.Debug("Cannot delete from node that's not a map or array %v", NodeToString(candidate))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matchingNodes, nil
|
return matchingNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteFromMap(candidate *CandidateNode, nodesToDelete *list.List) {
|
func DeleteImmediateChildOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
parents, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
childPath := pathNode.Operation.Value
|
||||||
|
|
||||||
|
log.Debug("childPath to remove %v", childPath)
|
||||||
|
|
||||||
|
for el := parents.Front(); el != nil; el = el.Next() {
|
||||||
|
parent := el.Value.(*CandidateNode)
|
||||||
|
parentNode := UnwrapDoc(parent.Node)
|
||||||
|
if parentNode.Kind == yaml.MappingNode {
|
||||||
|
deleteFromMap(parent, childPath)
|
||||||
|
} else if parentNode.Kind == yaml.SequenceNode {
|
||||||
|
deleteFromArray(parent, childPath)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Cannot delete nodes from parent of tag %v", parentNode.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return matchingNodes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteFromMap(candidate *CandidateNode, childPath interface{}) {
|
||||||
log.Debug("deleteFromMap")
|
log.Debug("deleteFromMap")
|
||||||
node := UnwrapDoc(candidate.Node)
|
node := UnwrapDoc(candidate.Node)
|
||||||
contents := node.Content
|
contents := node.Content
|
||||||
@@ -47,15 +75,10 @@ func deleteFromMap(candidate *CandidateNode, nodesToDelete *list.List) {
|
|||||||
childCandidate := &CandidateNode{
|
childCandidate := &CandidateNode{
|
||||||
Node: value,
|
Node: value,
|
||||||
Document: candidate.Document,
|
Document: candidate.Document,
|
||||||
Path: append(candidate.Path, key.Value),
|
Path: candidate.CreateChildPath(key.Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldDelete := false
|
shouldDelete := key.Value == childPath
|
||||||
for el := nodesToDelete.Front(); el != nil && !shouldDelete; el = el.Next() {
|
|
||||||
if el.Value.(*CandidateNode).GetKey() == childCandidate.GetKey() {
|
|
||||||
shouldDelete = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("shouldDelete %v ? %v", childCandidate.GetKey(), shouldDelete)
|
log.Debugf("shouldDelete %v ? %v", childCandidate.GetKey(), shouldDelete)
|
||||||
|
|
||||||
@@ -66,7 +89,7 @@ func deleteFromMap(candidate *CandidateNode, nodesToDelete *list.List) {
|
|||||||
node.Content = newContents
|
node.Content = newContents
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteFromArray(candidate *CandidateNode, nodesToDelete *list.List) {
|
func deleteFromArray(candidate *CandidateNode, childPath interface{}) {
|
||||||
log.Debug("deleteFromArray")
|
log.Debug("deleteFromArray")
|
||||||
node := UnwrapDoc(candidate.Node)
|
node := UnwrapDoc(candidate.Node)
|
||||||
contents := node.Content
|
contents := node.Content
|
||||||
@@ -75,18 +98,7 @@ func deleteFromArray(candidate *CandidateNode, nodesToDelete *list.List) {
|
|||||||
for index := 0; index < len(contents); index = index + 1 {
|
for index := 0; index < len(contents); index = index + 1 {
|
||||||
value := contents[index]
|
value := contents[index]
|
||||||
|
|
||||||
childCandidate := &CandidateNode{
|
shouldDelete := fmt.Sprintf("%v", index) == fmt.Sprintf("%v", childPath)
|
||||||
Node: value,
|
|
||||||
Document: candidate.Document,
|
|
||||||
Path: append(candidate.Path, index),
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldDelete := false
|
|
||||||
for el := nodesToDelete.Front(); el != nil && !shouldDelete; el = el.Next() {
|
|
||||||
if el.Value.(*CandidateNode).GetKey() == childCandidate.GetKey() {
|
|
||||||
shouldDelete = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !shouldDelete {
|
if !shouldDelete {
|
||||||
newContents = append(newContents, value)
|
newContents = append(newContents, value)
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ var deleteOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::{a: cat}\n",
|
"D0, P[], (doc)::{a: cat}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Delete nested entry in map",
|
||||||
|
document: `{a: {a1: fred, a2: frood}}`,
|
||||||
|
expression: `del(.a.a1)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: {a2: frood}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: {a1: fred, a2: frood}}`,
|
||||||
|
expression: `del(.. | select(.=="frood"))`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: {a1: fred}}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Delete entry in array",
|
description: "Delete entry in array",
|
||||||
document: `[1,2,3]`,
|
document: `[1,2,3]`,
|
||||||
@@ -21,6 +37,14 @@ var deleteOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (doc)::[1, 3]\n",
|
"D0, P[], (doc)::[1, 3]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Delete nested entry in array",
|
||||||
|
document: `[{a: cat, b: dog}]`,
|
||||||
|
expression: `del(.[0].a)`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::[{b: dog}]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Delete no matches",
|
description: "Delete no matches",
|
||||||
document: `{a: cat, b: dog}`,
|
document: `{a: cat, b: dog}`,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ var documentIndexScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Filter by document index",
|
description: "Filter by document index",
|
||||||
document: "a: cat\n---\na: frog\n",
|
document: "a: cat\n---\na: frog\n",
|
||||||
expression: `select(. | documentIndex == 1)`,
|
expression: `select(documentIndex == 1)`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D1, P[], (doc)::a: frog\n",
|
"D1, P[], (doc)::a: frog\n",
|
||||||
},
|
},
|
||||||
@@ -25,7 +25,7 @@ var documentIndexScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Print Document Index with matches",
|
description: "Print Document Index with matches",
|
||||||
document: "a: cat\n---\na: frog\n",
|
document: "a: cat\n---\na: frog\n",
|
||||||
expression: `.a | ({"match": ., "doc": (. | documentIndex)})`,
|
expression: `.a | ({"match": ., "doc": documentIndex})`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::match: cat\ndoc: 0\n",
|
"D0, P[], (!!map)::match: cat\ndoc: 0\n",
|
||||||
"D0, P[], (!!map)::match: frog\ndoc: 1\n",
|
"D0, P[], (!!map)::match: frog\ndoc: 1\n",
|
||||||
|
|||||||
35
pkg/yqlib/operator_length.go
Normal file
35
pkg/yqlib/operator_length.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LengthOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
log.Debugf("-- lengthOperation")
|
||||||
|
var results = list.New()
|
||||||
|
|
||||||
|
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||||
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
targetNode := UnwrapDoc(candidate.Node)
|
||||||
|
var length int
|
||||||
|
switch targetNode.Kind {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
length = len(targetNode.Value)
|
||||||
|
case yaml.MappingNode:
|
||||||
|
length = len(targetNode.Content) / 2
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
length = len(targetNode.Content)
|
||||||
|
default:
|
||||||
|
length = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"}
|
||||||
|
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
||||||
|
results.PushBack(lengthCand)
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
42
pkg/yqlib/operator_length_test.go
Normal file
42
pkg/yqlib/operator_length_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var lengthOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "String length",
|
||||||
|
subdescription: "returns length of string",
|
||||||
|
document: `{a: cat}`,
|
||||||
|
expression: `.a | length`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a], (!!int)::3\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Map length",
|
||||||
|
subdescription: "returns number of entries",
|
||||||
|
document: `{a: cat, c: dog}`,
|
||||||
|
expression: `length`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!int)::2\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Array length",
|
||||||
|
subdescription: "returns number of elements",
|
||||||
|
document: `[2,4,6,8]`,
|
||||||
|
expression: `length`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!int)::4\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLengthOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range lengthOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Length", lengthOperatorScenarios)
|
||||||
|
}
|
||||||
@@ -85,7 +85,9 @@ func mergeObjects(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode,
|
|||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
// shouldn't recurse arrays if appending
|
// shouldn't recurse arrays if appending
|
||||||
err := recursiveDecent(d, results, nodeToMap(rhs), !shouldAppendArrays)
|
prefs := &RecursiveDescentPreferences{RecurseArray: !shouldAppendArrays,
|
||||||
|
TraversePreferences: &TraversePreferences{FollowAlias: false}}
|
||||||
|
err := recursiveDecent(d, results, nodeToMap(rhs), prefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -104,19 +106,6 @@ func mergeObjects(d *dataTreeNavigator, lhs *CandidateNode, rhs *CandidateNode,
|
|||||||
return lhs, nil
|
return lhs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTraversalTree(path []interface{}) *PathTreeNode {
|
|
||||||
if len(path) == 0 {
|
|
||||||
return &PathTreeNode{Operation: &Operation{OperationType: SelfReference}}
|
|
||||||
} else if len(path) == 1 {
|
|
||||||
return &PathTreeNode{Operation: &Operation{OperationType: TraversePath, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
|
|
||||||
}
|
|
||||||
return &PathTreeNode{
|
|
||||||
Operation: &Operation{OperationType: Pipe},
|
|
||||||
Lhs: createTraversalTree(path[0:1]),
|
|
||||||
Rhs: createTraversalTree(path[1:])}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode, shouldAppendArrays bool) error {
|
func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode, shouldAppendArrays bool) error {
|
||||||
|
|
||||||
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", NodeToString(lhs), NodeToString(rhs))
|
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", NodeToString(lhs), NodeToString(rhs))
|
||||||
|
|||||||
@@ -13,6 +13,23 @@ var pathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a b], (!!seq)::- a\n- b\n",
|
"D0, P[a b], (!!seq)::- a\n- b\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `a:
|
||||||
|
b:
|
||||||
|
c:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- 3`,
|
||||||
|
expression: `.a.b.c.[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a b c 0], (!!int)::0\n",
|
||||||
|
"D0, P[a b c 1], (!!int)::1\n",
|
||||||
|
"D0, P[a b c 2], (!!int)::2\n",
|
||||||
|
"D0, P[a b c 3], (!!int)::3\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Get map key",
|
description: "Get map key",
|
||||||
document: `{a: {b: cat}}`,
|
document: `{a: {b: cat}}`,
|
||||||
|
|||||||
11
pkg/yqlib/operator_pipe.go
Normal file
11
pkg/yqlib/operator_pipe.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "container/list"
|
||||||
|
|
||||||
|
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
|
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
||||||
|
}
|
||||||
31
pkg/yqlib/operator_pipe_test.go
Normal file
31
pkg/yqlib/operator_pipe_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pipeOperatorScenarios = []expressionScenario{
|
||||||
|
{
|
||||||
|
description: "Simple Pipe",
|
||||||
|
document: `{a: {b: cat}}`,
|
||||||
|
expression: `.a | .b`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a b], (!!str)::cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Multiple updates",
|
||||||
|
document: `{a: cow, b: sheep, c: same}`,
|
||||||
|
expression: `.a = "cat" | .b = "dog"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (doc)::{a: cat, b: dog, c: same}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPipeOperatorScenarios(t *testing.T) {
|
||||||
|
for _, tt := range pipeOperatorScenarios {
|
||||||
|
testScenario(t, &tt)
|
||||||
|
}
|
||||||
|
documentScenarios(t, "Pipe", pipeOperatorScenarios)
|
||||||
|
}
|
||||||
@@ -6,10 +6,16 @@ import (
|
|||||||
yaml "gopkg.in/yaml.v3"
|
yaml "gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RecursiveDescentPreferences struct {
|
||||||
|
TraversePreferences *TraversePreferences
|
||||||
|
RecurseArray bool
|
||||||
|
}
|
||||||
|
|
||||||
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
var results = list.New()
|
var results = list.New()
|
||||||
|
|
||||||
err := recursiveDecent(d, results, matchMap, true)
|
preferences := pathNode.Operation.Preferences.(*RecursiveDescentPreferences)
|
||||||
|
err := recursiveDecent(d, results, matchMap, preferences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -17,7 +23,7 @@ func RecursiveDescentOperator(d *dataTreeNavigator, matchMap *list.List, pathNod
|
|||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List, recurseArray bool) error {
|
func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.List, preferences *RecursiveDescentPreferences) error {
|
||||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
candidate := el.Value.(*CandidateNode)
|
||||||
|
|
||||||
@@ -27,14 +33,14 @@ func recursiveDecent(d *dataTreeNavigator, results *list.List, matchMap *list.Li
|
|||||||
results.PushBack(candidate)
|
results.PushBack(candidate)
|
||||||
|
|
||||||
if candidate.Node.Kind != yaml.AliasNode && len(candidate.Node.Content) > 0 &&
|
if candidate.Node.Kind != yaml.AliasNode && len(candidate.Node.Content) > 0 &&
|
||||||
(recurseArray || candidate.Node.Kind != yaml.SequenceNode) {
|
(preferences.RecurseArray || candidate.Node.Kind != yaml.SequenceNode) {
|
||||||
|
|
||||||
children, err := Splat(d, nodeToMap(candidate))
|
children, err := Splat(d, nodeToMap(candidate), preferences.TraversePreferences)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = recursiveDecent(d, results, children, recurseArray)
|
err = recursiveDecent(d, results, children, preferences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::{}\n",
|
"D0, P[], (!!map)::{}\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{}`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{}\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[]`,
|
document: `[]`,
|
||||||
@@ -21,6 +29,14 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::[]\n",
|
"D0, P[], (!!seq)::[]\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[]`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `cat`,
|
document: `cat`,
|
||||||
@@ -31,13 +47,32 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: frog}`,
|
document: `cat`,
|
||||||
expression: `..`,
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Recurse map (values only)",
|
||||||
|
document: `{a: frog}`,
|
||||||
|
expression: `..`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::{a: frog}\n",
|
"D0, P[], (!!map)::{a: frog}\n",
|
||||||
"D0, P[a], (!!str)::frog\n",
|
"D0, P[a], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Recurse map (values and keys)",
|
||||||
|
subdescription: "Note that the map key appears in the results",
|
||||||
|
document: `{a: frog}`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: frog}\n",
|
||||||
|
"D0, P[a], (!!str)::a\n",
|
||||||
|
"D0, P[a], (!!str)::frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{a: {b: apple}}`,
|
document: `{a: {b: apple}}`,
|
||||||
@@ -48,6 +83,18 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a b], (!!str)::apple\n",
|
"D0, P[a b], (!!str)::apple\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: {b: apple}}`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: {b: apple}}\n",
|
||||||
|
"D0, P[a], (!!str)::a\n",
|
||||||
|
"D0, P[a], (!!map)::{b: apple}\n",
|
||||||
|
"D0, P[a b], (!!str)::b\n",
|
||||||
|
"D0, P[a b], (!!str)::apple\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[1,2,3]`,
|
document: `[1,2,3]`,
|
||||||
@@ -59,6 +106,17 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[2], (!!int)::3\n",
|
"D0, P[2], (!!int)::3\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[1,2,3]`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[1, 2, 3]\n",
|
||||||
|
"D0, P[0], (!!int)::1\n",
|
||||||
|
"D0, P[1], (!!int)::2\n",
|
||||||
|
"D0, P[2], (!!int)::3\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `[{a: cat},2,true]`,
|
document: `[{a: cat},2,true]`,
|
||||||
@@ -71,6 +129,19 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[2], (!!bool)::true\n",
|
"D0, P[2], (!!bool)::true\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[{a: cat},2,true]`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[{a: cat}, 2, true]\n",
|
||||||
|
"D0, P[0], (!!map)::{a: cat}\n",
|
||||||
|
"D0, P[0 a], (!!str)::a\n",
|
||||||
|
"D0, P[0 a], (!!str)::cat\n",
|
||||||
|
"D0, P[1], (!!int)::2\n",
|
||||||
|
"D0, P[2], (!!bool)::true\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Aliases are not traversed",
|
description: "Aliases are not traversed",
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
@@ -79,6 +150,20 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[a], (!!seq)::- {a: &cat {c: frog}, b: *cat}\n- &cat {c: frog}\n- frog\n- *cat\n",
|
"D0, P[a], (!!seq)::- {a: &cat {c: frog}, b: *cat}\n- &cat {c: frog}\n- frog\n- *cat\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
|
expression: `...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::{a: &cat {c: frog}, b: *cat}\n",
|
||||||
|
"D0, P[a], (!!str)::a\n",
|
||||||
|
"D0, P[a], (!!map)::&cat {c: frog}\n",
|
||||||
|
"D0, P[a c], (!!str)::c\n",
|
||||||
|
"D0, P[a c], (!!str)::frog\n",
|
||||||
|
"D0, P[b], (!!str)::b\n",
|
||||||
|
"D0, P[b], (alias)::*cat\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Merge docs are not traversed",
|
description: "Merge docs are not traversed",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
@@ -87,6 +172,14 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n",
|
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- foobar_c\n- *foo\n- foobar_thing\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: mergeDocSample,
|
||||||
|
expression: `.foobar | [...]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[foobar], (!!seq)::- c: foobar_c\n !!merge <<: *foo\n thing: foobar_thing\n- c\n- foobar_c\n- !!merge <<\n- *foo\n- thing\n- foobar_thing\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
@@ -100,6 +193,22 @@ var recursiveDescentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: mergeDocSample,
|
||||||
|
expression: `.foobarList | ...`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[foobarList], (!!map)::b: foobarList_b\n!!merge <<: [*foo, *bar]\nc: foobarList_c\n",
|
||||||
|
"D0, P[foobarList b], (!!str)::b\n",
|
||||||
|
"D0, P[foobarList b], (!!str)::foobarList_b\n",
|
||||||
|
"D0, P[foobarList <<], (!!merge)::!!merge <<\n",
|
||||||
|
"D0, P[foobarList <<], (!!seq)::[*foo, *bar]\n",
|
||||||
|
"D0, P[foobarList << 0], (alias)::*foo\n",
|
||||||
|
"D0, P[foobarList << 1], (alias)::*bar\n",
|
||||||
|
"D0, P[foobarList c], (!!str)::c\n",
|
||||||
|
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
func TestRecursiveDescentOperatorScenarios(t *testing.T) {
|
||||||
|
|||||||
@@ -21,6 +21,22 @@ var styleOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!map)::a: \"cat\"\nb: \"5\"\nc: \"3.2\"\ne: \"true\"\n",
|
"D0, P[], (!!map)::a: \"cat\"\nb: \"5\"\nc: \"3.2\"\ne: \"true\"\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Set double quote style on map keys too",
|
||||||
|
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
||||||
|
expression: `... style="double"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::\"a\": \"cat\"\n\"b\": \"5\"\n\"c\": \"3.2\"\n\"e\": \"true\"\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: "bing: &foo frog\na:\n c: cat\n <<: [*foo]",
|
||||||
|
expression: `(... | select(tag=="!!str")) style="single"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!map)::'bing': &foo 'frog'\n'a':\n 'c': 'cat'\n !!merge <<: [*foo]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Set single quote style",
|
description: "Set single quote style",
|
||||||
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
||||||
@@ -71,9 +87,9 @@ e: >-
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
description: "Pretty print",
|
description: "Pretty print",
|
||||||
subdescription: "Set empty (default) quote style",
|
subdescription: "Set empty (default) quote style, note the usage of `...` to match keys too. Note that there is a `--prettyPrint/-P` short flag for this.",
|
||||||
document: `{a: cat, b: 5, c: 3.2, e: true}`,
|
document: `{a: cat, "b": 5, 'c': 3.2, "e": true}`,
|
||||||
expression: `.. style=""`,
|
expression: `... style=""`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!map)::a: cat\nb: 5\nc: 3.2\ne: true\n",
|
"D0, P[], (!!map)::a: cat\nb: 5\nc: 3.2\ne: true\n",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,46 +1,39 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"container/list"
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/elliotchance/orderedmap"
|
"github.com/elliotchance/orderedmap"
|
||||||
|
yaml "gopkg.in/yaml.v3"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TraversePreferences struct {
|
type TraversePreferences struct {
|
||||||
DontFollowAlias bool
|
FollowAlias bool
|
||||||
|
IncludeMapKeys bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Splat(d *dataTreeNavigator, matches *list.List) (*list.List, error) {
|
func Splat(d *dataTreeNavigator, matches *list.List, prefs *TraversePreferences) (*list.List, error) {
|
||||||
preferences := &TraversePreferences{DontFollowAlias: true}
|
return traverseNodesWithArrayIndices(matches, make([]*yaml.Node, 0), prefs)
|
||||||
splatOperation := &Operation{OperationType: TraversePath, Value: "[]", Preferences: preferences}
|
|
||||||
splatTreeNode := &PathTreeNode{Operation: splatOperation}
|
|
||||||
return TraversePathOperator(d, matches, splatTreeNode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func TraversePathOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
log.Debugf("-- Traversing")
|
log.Debugf("-- Traversing")
|
||||||
var matchingNodeMap = list.New()
|
var matchingNodeMap = list.New()
|
||||||
var newNodes []*CandidateNode
|
|
||||||
var err error
|
|
||||||
|
|
||||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
for el := matchMap.Front(); el != nil; el = el.Next() {
|
||||||
newNodes, err = traverse(d, el.Value.(*CandidateNode), pathNode.Operation)
|
newNodes, err := traverse(d, el.Value.(*CandidateNode), pathNode.Operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, n := range newNodes {
|
matchingNodeMap.PushBackList(newNodes)
|
||||||
matchingNodeMap.PushBack(n)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return matchingNodeMap, nil
|
return matchingNodeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Operation) ([]*CandidateNode, error) {
|
func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Operation) (*list.List, error) {
|
||||||
log.Debug("Traversing %v", NodeToString(matchingNode))
|
log.Debug("Traversing %v", NodeToString(matchingNode))
|
||||||
value := matchingNode.Node
|
value := matchingNode.Node
|
||||||
|
|
||||||
@@ -61,34 +54,8 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Oper
|
|||||||
switch value.Kind {
|
switch value.Kind {
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
log.Debug("its a map with %v entries", len(value.Content)/2)
|
log.Debug("its a map with %v entries", len(value.Content)/2)
|
||||||
var newMatches = orderedmap.NewOrderedMap()
|
prefs := &TraversePreferences{FollowAlias: true}
|
||||||
err := traverseMap(newMatches, matchingNode, operation)
|
return traverseMap(matchingNode, operation.StringValue, prefs, false)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if newMatches.Len() == 0 {
|
|
||||||
//no matches, create one automagically
|
|
||||||
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
|
|
||||||
node := matchingNode.Node
|
|
||||||
node.Content = append(node.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: operation.StringValue}, valueNode)
|
|
||||||
candidateNode := &CandidateNode{
|
|
||||||
Node: valueNode,
|
|
||||||
Path: append(matchingNode.Path, operation.StringValue),
|
|
||||||
Document: matchingNode.Document,
|
|
||||||
}
|
|
||||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayMatches := make([]*CandidateNode, newMatches.Len())
|
|
||||||
i := 0
|
|
||||||
for el := newMatches.Front(); el != nil; el = el.Next() {
|
|
||||||
arrayMatches[i] = el.Value.(*CandidateNode)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return arrayMatches, nil
|
|
||||||
|
|
||||||
case yaml.SequenceNode:
|
case yaml.SequenceNode:
|
||||||
log.Debug("its a sequence of %v things!", len(value.Content))
|
log.Debug("its a sequence of %v things!", len(value.Content))
|
||||||
@@ -101,105 +68,118 @@ func traverse(d *dataTreeNavigator, matchingNode *CandidateNode, operation *Oper
|
|||||||
case yaml.DocumentNode:
|
case yaml.DocumentNode:
|
||||||
log.Debug("digging into doc node")
|
log.Debug("digging into doc node")
|
||||||
return traverse(d, &CandidateNode{
|
return traverse(d, &CandidateNode{
|
||||||
Node: matchingNode.Node.Content[0],
|
Node: matchingNode.Node.Content[0],
|
||||||
Document: matchingNode.Document}, operation)
|
Filename: matchingNode.Filename,
|
||||||
|
FileIndex: matchingNode.FileIndex,
|
||||||
|
Document: matchingNode.Document}, operation)
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return list.New(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyMatches(key *yaml.Node, pathNode *Operation) bool {
|
func TraverseArrayOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||||
return pathNode.Value == "[]" || Match(key.Value, pathNode.StringValue)
|
// rhs is a collect expression that will yield indexes to retreive of the arrays
|
||||||
}
|
|
||||||
|
|
||||||
func traverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, operation *Operation) error {
|
rhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||||
// value.Content is a concatenated array of key, value,
|
if err != nil {
|
||||||
// so keys are in the even indexes, values in odd.
|
return nil, err
|
||||||
// merge aliases are defined first, but we only want to traverse them
|
|
||||||
// if we don't find a match directly on this node first.
|
|
||||||
//TODO ALIASES, auto creation?
|
|
||||||
|
|
||||||
node := candidate.Node
|
|
||||||
|
|
||||||
followAlias := true
|
|
||||||
|
|
||||||
if operation.Preferences != nil {
|
|
||||||
followAlias = !operation.Preferences.(*TraversePreferences).DontFollowAlias
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var contents = node.Content
|
var indicesToTraverse = rhs.Front().Value.(*CandidateNode).Node.Content
|
||||||
for index := 0; index < len(contents); index = index + 2 {
|
prefs := &TraversePreferences{FollowAlias: true}
|
||||||
key := contents[index]
|
return traverseNodesWithArrayIndices(matchingNodes, indicesToTraverse, prefs)
|
||||||
value := contents[index+1]
|
}
|
||||||
|
|
||||||
log.Debug("checking %v (%v)", key.Value, key.Tag)
|
func traverseNodesWithArrayIndices(matchingNodes *list.List, indicesToTraverse []*yaml.Node, prefs *TraversePreferences) (*list.List, error) {
|
||||||
//skip the 'merge' tag, find a direct match first
|
var matchingNodeMap = list.New()
|
||||||
if key.Tag == "!!merge" && followAlias {
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
log.Debug("Merge anchor")
|
candidate := el.Value.(*CandidateNode)
|
||||||
err := traverseMergeAnchor(newMatches, candidate, value, operation)
|
newNodes, err := traverseArrayIndices(candidate, indicesToTraverse, prefs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
|
||||||
} else if keyMatches(key, operation) {
|
|
||||||
log.Debug("MATCHED")
|
|
||||||
candidateNode := &CandidateNode{
|
|
||||||
Node: value,
|
|
||||||
Path: append(candidate.Path, key.Value),
|
|
||||||
Document: candidate.Document,
|
|
||||||
}
|
|
||||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
|
||||||
}
|
}
|
||||||
|
matchingNodeMap.PushBackList(newNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return matchingNodeMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, operation *Operation) error {
|
func traverseArrayIndices(matchingNode *CandidateNode, indicesToTraverse []*yaml.Node, prefs *TraversePreferences) (*list.List, error) { // call this if doc / alias like the other traverse
|
||||||
switch value.Kind {
|
node := matchingNode.Node
|
||||||
case yaml.AliasNode:
|
if node.Tag == "!!null" {
|
||||||
candidateNode := &CandidateNode{
|
log.Debugf("OperatorArrayTraverse got a null - turning it into an empty array")
|
||||||
Node: value.Alias,
|
// auto vivification, make it into an empty array
|
||||||
Path: originalCandidate.Path,
|
node.Tag = ""
|
||||||
Document: originalCandidate.Document,
|
node.Kind = yaml.SequenceNode
|
||||||
}
|
|
||||||
return traverseMap(newMatches, candidateNode, operation)
|
|
||||||
case yaml.SequenceNode:
|
|
||||||
for _, childValue := range value.Content {
|
|
||||||
err := traverseMergeAnchor(newMatches, originalCandidate, childValue, operation)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
if node.Kind == yaml.AliasNode {
|
||||||
|
matchingNode.Node = node.Alias
|
||||||
|
return traverseArrayIndices(matchingNode, indicesToTraverse, prefs)
|
||||||
|
} else if node.Kind == yaml.SequenceNode {
|
||||||
|
return traverseArrayWithIndices(matchingNode, indicesToTraverse)
|
||||||
|
} else if node.Kind == yaml.MappingNode {
|
||||||
|
return traverseMapWithIndices(matchingNode, indicesToTraverse, prefs)
|
||||||
|
} else if node.Kind == yaml.DocumentNode {
|
||||||
|
return traverseArrayIndices(&CandidateNode{
|
||||||
|
Node: matchingNode.Node.Content[0],
|
||||||
|
Filename: matchingNode.Filename,
|
||||||
|
FileIndex: matchingNode.FileIndex,
|
||||||
|
Document: matchingNode.Document}, indicesToTraverse, prefs)
|
||||||
|
}
|
||||||
|
log.Debugf("OperatorArrayTraverse skipping %v as its a %v", matchingNode, node.Tag)
|
||||||
|
return list.New(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func traverseArray(candidate *CandidateNode, operation *Operation) ([]*CandidateNode, error) {
|
func traverseMapWithIndices(candidate *CandidateNode, indices []*yaml.Node, prefs *TraversePreferences) (*list.List, error) {
|
||||||
log.Debug("operation Value %v", operation.Value)
|
if len(indices) == 0 {
|
||||||
if operation.Value == "[]" {
|
return traverseMap(candidate, "", prefs, true)
|
||||||
|
}
|
||||||
|
|
||||||
var contents = candidate.Node.Content
|
var matchingNodeMap = list.New()
|
||||||
var newMatches = make([]*CandidateNode, len(contents))
|
|
||||||
|
for _, indexNode := range indices {
|
||||||
|
log.Debug("traverseMapWithIndices: %v", indexNode.Value)
|
||||||
|
newNodes, err := traverseMap(candidate, indexNode.Value, prefs, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
matchingNodeMap.PushBackList(newNodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingNodeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func traverseArrayWithIndices(candidate *CandidateNode, indices []*yaml.Node) (*list.List, error) {
|
||||||
|
log.Debug("traverseArrayWithIndices")
|
||||||
|
var newMatches = list.New()
|
||||||
|
node := UnwrapDoc(candidate.Node)
|
||||||
|
if len(indices) == 0 {
|
||||||
|
log.Debug("splatting")
|
||||||
var index int64
|
var index int64
|
||||||
for index = 0; index < int64(len(contents)); index = index + 1 {
|
for index = 0; index < int64(len(node.Content)); index = index + 1 {
|
||||||
newMatches[index] = &CandidateNode{
|
|
||||||
|
newMatches.PushBack(&CandidateNode{
|
||||||
Document: candidate.Document,
|
Document: candidate.Document,
|
||||||
Path: append(candidate.Path, index),
|
Path: candidate.CreateChildPath(index),
|
||||||
Node: contents[index],
|
Node: node.Content[index],
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
return newMatches, nil
|
return newMatches, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch operation.Value.(type) {
|
for _, indexNode := range indices {
|
||||||
case int64:
|
log.Debug("traverseArrayWithIndices: '%v'", indexNode.Value)
|
||||||
index := operation.Value.(int64)
|
index, err := strconv.ParseInt(indexNode.Value, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Cannot index array with '%v' (%v)", indexNode.Value, err)
|
||||||
|
}
|
||||||
indexToUse := index
|
indexToUse := index
|
||||||
contentLength := int64(len(candidate.Node.Content))
|
contentLength := int64(len(node.Content))
|
||||||
for contentLength <= index {
|
for contentLength <= index {
|
||||||
candidate.Node.Content = append(candidate.Node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
|
node.Content = append(node.Content, &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"})
|
||||||
contentLength = int64(len(candidate.Node.Content))
|
contentLength = int64(len(node.Content))
|
||||||
}
|
}
|
||||||
|
|
||||||
if indexToUse < 0 {
|
if indexToUse < 0 {
|
||||||
@@ -210,14 +190,115 @@ func traverseArray(candidate *CandidateNode, operation *Operation) ([]*Candidate
|
|||||||
return nil, fmt.Errorf("Index [%v] out of range, array size is %v", index, contentLength)
|
return nil, fmt.Errorf("Index [%v] out of range, array size is %v", index, contentLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []*CandidateNode{&CandidateNode{
|
newMatches.PushBack(&CandidateNode{
|
||||||
Node: candidate.Node.Content[indexToUse],
|
Node: node.Content[indexToUse],
|
||||||
Document: candidate.Document,
|
Document: candidate.Document,
|
||||||
Path: append(candidate.Path, index),
|
Path: candidate.CreateChildPath(index),
|
||||||
}}, nil
|
})
|
||||||
default:
|
}
|
||||||
log.Debug("argument not an int (%v), no array matches", operation.Value)
|
return newMatches, nil
|
||||||
return nil, nil
|
}
|
||||||
|
|
||||||
|
func keyMatches(key *yaml.Node, wantedKey string) bool {
|
||||||
|
return Match(key.Value, wantedKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traverseMap(matchingNode *CandidateNode, key string, prefs *TraversePreferences, splat bool) (*list.List, error) {
|
||||||
|
var newMatches = orderedmap.NewOrderedMap()
|
||||||
|
err := doTraverseMap(newMatches, matchingNode, key, prefs, splat)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if newMatches.Len() == 0 {
|
||||||
|
//no matches, create one automagically
|
||||||
|
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
|
||||||
|
node := matchingNode.Node
|
||||||
|
node.Content = append(node.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: key}, valueNode)
|
||||||
|
candidateNode := &CandidateNode{
|
||||||
|
Node: valueNode,
|
||||||
|
Path: append(matchingNode.Path, key),
|
||||||
|
Document: matchingNode.Document,
|
||||||
|
}
|
||||||
|
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
results := list.New()
|
||||||
|
i := 0
|
||||||
|
for el := newMatches.Front(); el != nil; el = el.Next() {
|
||||||
|
results.PushBack(el.Value)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, prefs *TraversePreferences, splat bool) error {
|
||||||
|
// value.Content is a concatenated array of key, value,
|
||||||
|
// so keys are in the even indexes, values in odd.
|
||||||
|
// merge aliases are defined first, but we only want to traverse them
|
||||||
|
// if we don't find a match directly on this node first.
|
||||||
|
|
||||||
|
node := candidate.Node
|
||||||
|
|
||||||
|
var contents = node.Content
|
||||||
|
for index := 0; index < len(contents); index = index + 2 {
|
||||||
|
key := contents[index]
|
||||||
|
value := contents[index+1]
|
||||||
|
|
||||||
|
log.Debug("checking %v (%v)", key.Value, key.Tag)
|
||||||
|
//skip the 'merge' tag, find a direct match first
|
||||||
|
if key.Tag == "!!merge" && prefs.FollowAlias {
|
||||||
|
log.Debug("Merge anchor")
|
||||||
|
err := traverseMergeAnchor(newMatches, candidate, value, wantedKey, prefs, splat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if splat || keyMatches(key, wantedKey) {
|
||||||
|
log.Debug("MATCHED")
|
||||||
|
if prefs.IncludeMapKeys {
|
||||||
|
candidateNode := &CandidateNode{
|
||||||
|
Node: key,
|
||||||
|
Path: candidate.CreateChildPath(key.Value),
|
||||||
|
Document: candidate.Document,
|
||||||
|
}
|
||||||
|
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
|
||||||
|
}
|
||||||
|
candidateNode := &CandidateNode{
|
||||||
|
Node: value,
|
||||||
|
Path: candidate.CreateChildPath(key.Value),
|
||||||
|
Document: candidate.Document,
|
||||||
|
}
|
||||||
|
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func traverseMergeAnchor(newMatches *orderedmap.OrderedMap, originalCandidate *CandidateNode, value *yaml.Node, wantedKey string, prefs *TraversePreferences, splat bool) error {
|
||||||
|
switch value.Kind {
|
||||||
|
case yaml.AliasNode:
|
||||||
|
candidateNode := &CandidateNode{
|
||||||
|
Node: value.Alias,
|
||||||
|
Path: originalCandidate.Path,
|
||||||
|
Document: originalCandidate.Document,
|
||||||
|
}
|
||||||
|
return doTraverseMap(newMatches, candidateNode, wantedKey, prefs, splat)
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
for _, childValue := range value.Content {
|
||||||
|
err := traverseMergeAnchor(newMatches, originalCandidate, childValue, wantedKey, prefs, splat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func traverseArray(candidate *CandidateNode, operation *Operation) (*list.List, error) {
|
||||||
|
log.Debug("operation Value %v", operation.Value)
|
||||||
|
indices := []*yaml.Node{&yaml.Node{Value: operation.StringValue}}
|
||||||
|
return traverseArrayWithIndices(candidate, indices)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
skipDoc: true,
|
skipDoc: true,
|
||||||
document: `{}`,
|
document: ``,
|
||||||
expression: `.[1].a`,
|
expression: `.[1].a`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[1 a], (!!null)::null\n",
|
"D0, P[1 a], (!!null)::null\n",
|
||||||
@@ -137,7 +137,15 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Traversing aliases with splat",
|
description: "Traversing aliases with splat",
|
||||||
document: `{a: &cat {c: frog}, b: *cat}`,
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
expression: `.b.[]`,
|
expression: `.b[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[b c], (!!str)::frog\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: &cat {c: frog}, b: *cat}`,
|
||||||
|
expression: `.b.[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[b c], (!!str)::frog\n",
|
"D0, P[b c], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
@@ -150,12 +158,6 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[b c], (!!str)::frog\n",
|
"D0, P[b c], (!!str)::frog\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
skipDoc: true,
|
|
||||||
document: `[1,2,3]`,
|
|
||||||
expression: `.b`,
|
|
||||||
expected: []string{},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
description: "Traversing arrays by index",
|
description: "Traversing arrays by index",
|
||||||
document: `[1,2,3]`,
|
document: `[1,2,3]`,
|
||||||
@@ -215,7 +217,17 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Splatting merge anchors",
|
description: "Splatting merge anchors",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
expression: `.foobar.[]`,
|
expression: `.foobar[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[foobar c], (!!str)::foo_c\n",
|
||||||
|
"D0, P[foobar a], (!!str)::foo_a\n",
|
||||||
|
"D0, P[foobar thing], (!!str)::foobar_thing\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: mergeDocSample,
|
||||||
|
expression: `.foobar.[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[foobar c], (!!str)::foo_c\n",
|
"D0, P[foobar c], (!!str)::foo_c\n",
|
||||||
"D0, P[foobar a], (!!str)::foo_a\n",
|
"D0, P[foobar a], (!!str)::foo_a\n",
|
||||||
@@ -266,7 +278,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
{
|
{
|
||||||
description: "Splatting merge anchor lists",
|
description: "Splatting merge anchor lists",
|
||||||
document: mergeDocSample,
|
document: mergeDocSample,
|
||||||
expression: `.foobarList.[]`,
|
expression: `.foobarList[]`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[foobarList b], (!!str)::bar_b\n",
|
"D0, P[foobarList b], (!!str)::bar_b\n",
|
||||||
"D0, P[foobarList a], (!!str)::foo_a\n",
|
"D0, P[foobarList a], (!!str)::foo_a\n",
|
||||||
@@ -274,6 +286,123 @@ var traversePathOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: mergeDocSample,
|
||||||
|
expression: `.foobarList.[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[foobarList b], (!!str)::bar_b\n",
|
||||||
|
"D0, P[foobarList a], (!!str)::foo_a\n",
|
||||||
|
"D0, P[foobarList thing], (!!str)::bar_thing\n",
|
||||||
|
"D0, P[foobarList c], (!!str)::foobarList_c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[a,b,c]`,
|
||||||
|
expression: `.[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[0], (!!str)::a\n",
|
||||||
|
"D0, P[1], (!!str)::b\n",
|
||||||
|
"D0, P[2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `[a,b,c]`,
|
||||||
|
expression: `[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!seq)::[]\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a[0]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Select multiple indices",
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a[0, 2]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a.[0, 2]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a[-1]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a -1], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a.[-1]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a -1], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a[-2]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a -2], (!!str)::b\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a.[-2]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a -2], (!!str)::b\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
"D0, P[a 1], (!!str)::b\n",
|
||||||
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a.[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
"D0, P[a 1], (!!str)::b\n",
|
||||||
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
document: `{a: [a,b,c]}`,
|
||||||
|
expression: `.a | .[]`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[a 0], (!!str)::a\n",
|
||||||
|
"D0, P[a 1], (!!str)::b\n",
|
||||||
|
"D0, P[a 2], (!!str)::c\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTraversePathOperatorScenarios(t *testing.T) {
|
func TestTraversePathOperatorScenarios(t *testing.T) {
|
||||||
|
|||||||
@@ -36,13 +36,22 @@ var valueOperatorScenarios = []expressionScenario{
|
|||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!float)::5e-10\n",
|
"D0, P[], (!!float)::5e-10\n",
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
document: ``,
|
document: ``,
|
||||||
expression: `"cat"`,
|
expression: `"cat"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
"D0, P[], (!!str)::cat\n",
|
"D0, P[], (!!str)::cat\n",
|
||||||
},
|
},
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
document: ``,
|
||||||
|
expression: `"frog jumps"`,
|
||||||
|
expected: []string{
|
||||||
|
"D0, P[], (!!str)::frog jumps\n",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
document: ``,
|
document: ``,
|
||||||
expression: `"1.3"`,
|
expression: `"1.3"`,
|
||||||
expected: []string{
|
expected: []string{
|
||||||
|
|||||||
@@ -20,14 +20,6 @@ func EmptyOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *Pat
|
|||||||
return list.New(), nil
|
return list.New(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PipeOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
|
||||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return d.GetMatchingNodes(lhs, pathNode.Rhs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
||||||
valString := "true"
|
valString := "true"
|
||||||
if !value {
|
if !value {
|
||||||
@@ -43,28 +35,14 @@ func nodeToMap(candidate *CandidateNode) *list.List {
|
|||||||
return elMap
|
return elMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func LengthOperator(d *dataTreeNavigator, matchMap *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
func createTraversalTree(path []interface{}) *PathTreeNode {
|
||||||
log.Debugf("-- lengthOperation")
|
if len(path) == 0 {
|
||||||
var results = list.New()
|
return &PathTreeNode{Operation: &Operation{OperationType: SelfReference}}
|
||||||
|
} else if len(path) == 1 {
|
||||||
for el := matchMap.Front(); el != nil; el = el.Next() {
|
return &PathTreeNode{Operation: &Operation{OperationType: TraversePath, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
|
||||||
candidate := el.Value.(*CandidateNode)
|
|
||||||
var length int
|
|
||||||
switch candidate.Node.Kind {
|
|
||||||
case yaml.ScalarNode:
|
|
||||||
length = len(candidate.Node.Value)
|
|
||||||
case yaml.MappingNode:
|
|
||||||
length = len(candidate.Node.Content) / 2
|
|
||||||
case yaml.SequenceNode:
|
|
||||||
length = len(candidate.Node.Content)
|
|
||||||
default:
|
|
||||||
length = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
node := &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", length), Tag: "!!int"}
|
|
||||||
lengthCand := &CandidateNode{Node: node, Document: candidate.Document, Path: candidate.Path}
|
|
||||||
results.PushBack(lengthCand)
|
|
||||||
}
|
}
|
||||||
|
return &PathTreeNode{
|
||||||
return results, nil
|
Operation: &Operation{OperationType: ShortPipe},
|
||||||
|
Lhs: createTraversalTree(path[0:1]),
|
||||||
|
Rhs: createTraversalTree(path[1:])}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func testScenario(t *testing.T, s *expressionScenario) {
|
|||||||
if s.document != "" {
|
if s.document != "" {
|
||||||
inputs, err = readDocuments(strings.NewReader(s.document), "sample.yml", 0)
|
inputs, err = readDocuments(strings.NewReader(s.document), "sample.yml", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err, s.document)
|
t.Error(err, s.document, s.expression)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -55,7 +55,7 @@ func testScenario(t *testing.T, s *expressionScenario) {
|
|||||||
results, err = treeNavigator.GetMatchingNodes(inputs, node)
|
results, err = treeNavigator.GetMatchingNodes(inputs, node)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(fmt.Errorf("%v: %v", err, s.expression))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
test.AssertResultComplexWithContext(t, s.expected, resultsToString(results), fmt.Sprintf("exp: %v\ndoc: %v", s.expression, s.document))
|
test.AssertResultComplexWithContext(t, s.expected, resultsToString(results), fmt.Sprintf("exp: %v\ndoc: %v", s.expression, s.document))
|
||||||
@@ -167,17 +167,17 @@ func documentScenarios(t *testing.T, title string, scenarios []expressionScenari
|
|||||||
if s.document != "" {
|
if s.document != "" {
|
||||||
node, err := treeCreator.ParsePath(s.expression)
|
node, err := treeCreator.ParsePath(s.expression)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err, s.expression)
|
||||||
}
|
}
|
||||||
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(formattedDoc), node, printer)
|
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(formattedDoc), node, printer)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err, s.expression)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = streamEvaluator.EvaluateNew(s.expression, printer)
|
err = streamEvaluator.EvaluateNew(s.expression, printer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err, s.expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,73 +11,76 @@ var pathTests = []struct {
|
|||||||
path string
|
path string
|
||||||
expectedTokens []interface{}
|
expectedTokens []interface{}
|
||||||
expectedPostFix []interface{}
|
expectedPostFix []interface{}
|
||||||
}{ // TODO: Ensure ALL documented examples have tests! sheesh
|
}{
|
||||||
// {"len(.)", append(make([]interface{}, 0), "LENGTH", "(", "SELF", ")")},
|
|
||||||
// {"\"len\"(.)", append(make([]interface{}, 0), "len", "TRAVERSE", "(", "SELF", ")")},
|
|
||||||
// {".a OR (.b OR .c)", append(make([]interface{}, 0), "a", "OR", "(", "b", "OR", "c", ")")},
|
|
||||||
// {"a OR (b OR c)", append(make([]interface{}, 0), "a", "OR", "(", "b", "OR", "c", ")")},
|
|
||||||
// {"a .- (b OR c)", append(make([]interface{}, 0), "a", " .- ", "(", "b", "OR", "c", ")")},
|
|
||||||
// {"(animal==3)", append(make([]interface{}, 0), "(", "animal", "==", int64(3), ")")},
|
|
||||||
// {"(animal==f3)", append(make([]interface{}, 0), "(", "animal", "==", "f3", ")")},
|
|
||||||
// {"apples.BANANAS", append(make([]interface{}, 0), "apples", "TRAVERSE", "BANANAS")},
|
|
||||||
// {"appl*.BANA*", append(make([]interface{}, 0), "appl*", "TRAVERSE", "BANA*")},
|
|
||||||
// {"a.b.**", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "**")},
|
|
||||||
// {"a.\"=\".frog", append(make([]interface{}, 0), "a", "TRAVERSE", "=", "TRAVERSE", "frog")},
|
|
||||||
// {"a.b.*", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "*")},
|
|
||||||
// {"a.b.thin*", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "thin*")},
|
|
||||||
// {".a.b.[0]", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", int64(0))},
|
|
||||||
// {".a.b.[]", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "[]")},
|
|
||||||
// {".a.b.[+]", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "[+]")},
|
|
||||||
// {".a.b.[-12]", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", int64(-12))},
|
|
||||||
// {".a.b.0", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "0")},
|
|
||||||
// {".a", append(make([]interface{}, 0), "a")},
|
|
||||||
// {".\"a.b\".c", append(make([]interface{}, 0), "a.b", "TRAVERSE", "c")},
|
|
||||||
// {`.b."foo.bar"`, append(make([]interface{}, 0), "b", "TRAVERSE", "foo.bar")},
|
|
||||||
// {`f | . == *og | length`, append(make([]interface{}, 0), "f", "TRAVERSE", "SELF", "EQUALS", "*og", "TRAVERSE", "LENGTH")},
|
|
||||||
// {`.a, .b`, append(make([]interface{}, 0), "a", "OR", "b")},
|
|
||||||
// {`[.a, .b]`, append(make([]interface{}, 0), "[", "a", "OR", "b", "]")},
|
|
||||||
// {`."[a", ."b]"`, append(make([]interface{}, 0), "[a", "OR", "b]")},
|
|
||||||
// {`.a.[]`, append(make([]interface{}, 0), "a", "PIPE", "[]")},
|
|
||||||
// {`.[].a`, append(make([]interface{}, 0), "[]", "PIPE", "a")},
|
|
||||||
// {
|
|
||||||
// `["cat"]`,
|
|
||||||
// append(make([]interface{}, 0), "[", "cat (string)", "]"),
|
|
||||||
// append(make([]interface{}, 0), "cat (string)", "COLLECT", "PIPE"),
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
`[]`,
|
`[]`,
|
||||||
append(make([]interface{}, 0), "[", "]"),
|
append(make([]interface{}, 0), "[", "]"),
|
||||||
append(make([]interface{}, 0), "EMPTY", "COLLECT", "PIPE"),
|
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]`,
|
`[3]`,
|
||||||
append(make([]interface{}, 0), "[", "3 (int64)", "]"),
|
append(make([]interface{}, 0), "[", "3 (int64)", "]"),
|
||||||
append(make([]interface{}, 0), "3 (int64)", "COLLECT", "PIPE"),
|
append(make([]interface{}, 0), "3 (int64)", "COLLECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`d0.a`,
|
`d0.a`,
|
||||||
append(make([]interface{}, 0), "d0", "PIPE", "a"),
|
append(make([]interface{}, 0), "d0", "SHORT_PIPE", "a"),
|
||||||
append(make([]interface{}, 0), "d0", "a", "PIPE"),
|
append(make([]interface{}, 0), "d0", "a", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`.a | (.[].b == "apple")`,
|
`.a | .[].b == "apple"`,
|
||||||
append(make([]interface{}, 0), "a", "PIPE", "(", "[]", "PIPE", "b", "EQUALS", "apple (string)", ")"),
|
append(make([]interface{}, 0), "a", "PIPE", "TRAVERSE_ARRAY", "[", "]", "SHORT_PIPE", "b", "EQUALS", "apple (string)"),
|
||||||
append(make([]interface{}, 0), "a", "[]", "b", "PIPE", "apple (string)", "EQUALS", "PIPE"),
|
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")`,
|
`.[] | select(. == "*at")`,
|
||||||
append(make([]interface{}, 0), "[]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"),
|
append(make([]interface{}, 0), "TRAVERSE_ARRAY", "[", "]", "PIPE", "SELECT", "(", "SELF", "EQUALS", "*at (string)", ")"),
|
||||||
append(make([]interface{}, 0), "[]", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"),
|
append(make([]interface{}, 0), "EMPTY", "COLLECT", "SHORT_PIPE", "TRAVERSE_ARRAY", "SELF", "*at (string)", "EQUALS", "SELECT", "PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`[true]`,
|
`[true]`,
|
||||||
append(make([]interface{}, 0), "[", "true (bool)", "]"),
|
append(make([]interface{}, 0), "[", "true (bool)", "]"),
|
||||||
append(make([]interface{}, 0), "true (bool)", "COLLECT", "PIPE"),
|
append(make([]interface{}, 0), "true (bool)", "COLLECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`[true, false]`,
|
`[true, false]`,
|
||||||
append(make([]interface{}, 0), "[", "true (bool)", "UNION", "false (bool)", "]"),
|
append(make([]interface{}, 0), "[", "true (bool)", "UNION", "false (bool)", "]"),
|
||||||
append(make([]interface{}, 0), "true (bool)", "false (bool)", "UNION", "COLLECT", "PIPE"),
|
append(make([]interface{}, 0), "true (bool)", "false (bool)", "UNION", "COLLECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`"mike": .a`,
|
`"mike": .a`,
|
||||||
@@ -92,27 +95,27 @@ var pathTests = []struct {
|
|||||||
{
|
{
|
||||||
`{"mike": .a}`,
|
`{"mike": .a}`,
|
||||||
append(make([]interface{}, 0), "{", "mike (string)", "CREATE_MAP", "a", "}"),
|
append(make([]interface{}, 0), "{", "mike (string)", "CREATE_MAP", "a", "}"),
|
||||||
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP", "COLLECT_OBJECT", "PIPE"),
|
append(make([]interface{}, 0), "mike (string)", "a", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`{.a: "mike"}`,
|
`{.a: "mike"}`,
|
||||||
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "mike (string)", "}"),
|
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "mike (string)", "}"),
|
||||||
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "PIPE"),
|
append(make([]interface{}, 0), "a", "mike (string)", "CREATE_MAP", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`{.a: .c, .b.[]: .f.g.[]}`,
|
`{.a: .c, .b.[]: .f.g.[]}`,
|
||||||
append(make([]interface{}, 0), "{", "a", "CREATE_MAP", "c", "UNION", "b", "PIPE", "[]", "CREATE_MAP", "f", "PIPE", "g", "PIPE", "[]", "}"),
|
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", "[]", "PIPE", "f", "g", "PIPE", "[]", "PIPE", "CREATE_MAP", "UNION", "COLLECT_OBJECT", "PIPE"),
|
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)`,
|
`explode(.a.b)`,
|
||||||
append(make([]interface{}, 0), "EXPLODE", "(", "a", "PIPE", "b", ")"),
|
append(make([]interface{}, 0), "EXPLODE", "(", "a", "SHORT_PIPE", "b", ")"),
|
||||||
append(make([]interface{}, 0), "a", "b", "PIPE", "EXPLODE"),
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "EXPLODE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`.a.b style="folded"`,
|
`.a.b style="folded"`,
|
||||||
append(make([]interface{}, 0), "a", "PIPE", "b", "ASSIGN_STYLE", "folded (string)"),
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_STYLE", "folded (string)"),
|
||||||
append(make([]interface{}, 0), "a", "b", "PIPE", "folded (string)", "ASSIGN_STYLE"),
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "folded (string)", "ASSIGN_STYLE"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
`tag == "str"`,
|
`tag == "str"`,
|
||||||
@@ -134,12 +137,11 @@ var pathTests = []struct {
|
|||||||
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
|
append(make([]interface{}, 0), "SELF", "ASSIGN_COMMENT", "str (string)"),
|
||||||
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
|
append(make([]interface{}, 0), "SELF", "str (string)", "ASSIGN_COMMENT"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
// {
|
`.a.b tag="!!str"`,
|
||||||
// `.a.b tag="!!str"`,
|
append(make([]interface{}, 0), "a", "SHORT_PIPE", "b", "ASSIGN_TAG", "!!str (string)"),
|
||||||
// append(make([]interface{}, 0), "EXPLODE", "(", "a", "PIPE", "b", ")"),
|
append(make([]interface{}, 0), "a", "b", "SHORT_PIPE", "!!str (string)", "ASSIGN_TAG"),
|
||||||
// append(make([]interface{}, 0), "a", "b", "PIPE", "EXPLODE"),
|
},
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
`""`,
|
`""`,
|
||||||
append(make([]interface{}, 0), " (string)"),
|
append(make([]interface{}, 0), " (string)"),
|
||||||
@@ -153,27 +155,8 @@ var pathTests = []struct {
|
|||||||
{
|
{
|
||||||
`{}`,
|
`{}`,
|
||||||
append(make([]interface{}, 0), "{", "}"),
|
append(make([]interface{}, 0), "{", "}"),
|
||||||
append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "PIPE"),
|
append(make([]interface{}, 0), "EMPTY", "COLLECT_OBJECT", "SHORT_PIPE"),
|
||||||
},
|
},
|
||||||
|
|
||||||
// {".animals | .==cat", append(make([]interface{}, 0), "animals", "TRAVERSE", "SELF", "EQUALS", "cat")},
|
|
||||||
// {".animals | (. == cat)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "SELF", "EQUALS", "cat", ")")},
|
|
||||||
// {".animals | (.==c*)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "SELF", "EQUALS", "c*", ")")},
|
|
||||||
// {"animals(a.b==c*)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "a", "TRAVERSE", "b", "==", "c*", ")")},
|
|
||||||
// {"animals.(a.b==c*)", append(make([]interface{}, 0), "animals", "TRAVERSE", "(", "a", "TRAVERSE", "b", "==", "c*", ")")},
|
|
||||||
// {"(a.b==c*).animals", append(make([]interface{}, 0), "(", "a", "TRAVERSE", "b", "==", "c*", ")", "TRAVERSE", "animals")},
|
|
||||||
// {"(a.b==c*)animals", append(make([]interface{}, 0), "(", "a", "TRAVERSE", "b", "==", "c*", ")", "TRAVERSE", "animals")},
|
|
||||||
// {"[1].a.d", append(make([]interface{}, 0), int64(1), "TRAVERSE", "a", "TRAVERSE", "d")},
|
|
||||||
// {"[1]a.d", append(make([]interface{}, 0), int64(1), "TRAVERSE", "a", "TRAVERSE", "d")},
|
|
||||||
// {"a[0]c", append(make([]interface{}, 0), "a", "TRAVERSE", int64(0), "TRAVERSE", "c")},
|
|
||||||
// {"a.[0].c", append(make([]interface{}, 0), "a", "TRAVERSE", int64(0), "TRAVERSE", "c")},
|
|
||||||
// {"[0]", append(make([]interface{}, 0), int64(0))},
|
|
||||||
// {"0", append(make([]interface{}, 0), int64(0))},
|
|
||||||
// {"a.b[+]c", append(make([]interface{}, 0), "a", "TRAVERSE", "b", "TRAVERSE", "[+]", "TRAVERSE", "c")},
|
|
||||||
// {"a.cool(s.d.f == cool)", append(make([]interface{}, 0), "a", "TRAVERSE", "cool", "TRAVERSE", "(", "s", "TRAVERSE", "d", "TRAVERSE", "f", " == ", "cool", ")")},
|
|
||||||
// {"a.cool.(s.d.f==cool OR t.b.h==frog).caterpillar", append(make([]interface{}, 0), "a", "TRAVERSE", "cool", "TRAVERSE", "(", "s", "TRAVERSE", "d", "TRAVERSE", "f", "==", "cool", "OR", "t", "TRAVERSE", "b", "TRAVERSE", "h", "==", "frog", ")", "TRAVERSE", "caterpillar")},
|
|
||||||
// {"a.cool(s.d.f==cool and t.b.h==frog)*", append(make([]interface{}, 0), "a", "TRAVERSE", "cool", "TRAVERSE", "(", "s", "TRAVERSE", "d", "TRAVERSE", "f", "==", "cool", "and", "t", "TRAVERSE", "b", "TRAVERSE", "h", "==", "frog", ")", "TRAVERSE", "*")},
|
|
||||||
// {"a.cool(s.d.f==cool and t.b.h==frog).th*", append(make([]interface{}, 0), "a", "TRAVERSE", "cool", "TRAVERSE", "(", "s", "TRAVERSE", "d", "TRAVERSE", "f", "==", "cool", "and", "t", "TRAVERSE", "b", "TRAVERSE", "h", "==", "frog", ")", "TRAVERSE", "th*")},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokeniser = NewPathTokeniser()
|
var tokeniser = NewPathTokeniser()
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ 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: ShortPipe}})
|
||||||
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 {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
lex "github.com/timtadh/lexmachine"
|
lex "github.com/timtadh/lexmachine"
|
||||||
@@ -21,6 +22,7 @@ const (
|
|||||||
CloseCollect
|
CloseCollect
|
||||||
OpenCollectObject
|
OpenCollectObject
|
||||||
CloseCollectObject
|
CloseCollectObject
|
||||||
|
TraverseArrayCollect
|
||||||
)
|
)
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
@@ -47,6 +49,9 @@ func (t *Token) toString() string {
|
|||||||
return "{"
|
return "{"
|
||||||
} else if t.TokenType == CloseCollectObject {
|
} else if t.TokenType == CloseCollectObject {
|
||||||
return "}"
|
return "}"
|
||||||
|
} else if t.TokenType == TraverseArrayCollect {
|
||||||
|
return ".["
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return "NFI"
|
return "NFI"
|
||||||
}
|
}
|
||||||
@@ -110,23 +115,6 @@ func unwrap(value string) string {
|
|||||||
return value[1 : len(value)-1]
|
return value[1 : len(value)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func arrayIndextoken(precedingDot bool) lex.Action {
|
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
|
||||||
var numberString = string(m.Bytes)
|
|
||||||
startIndex := 1
|
|
||||||
if precedingDot {
|
|
||||||
startIndex = 2
|
|
||||||
}
|
|
||||||
numberString = numberString[startIndex : len(numberString)-1]
|
|
||||||
var number, errParsingInt = strconv.ParseInt(numberString, 10, 64) // nolint
|
|
||||||
if errParsingInt != nil {
|
|
||||||
return nil, errParsingInt
|
|
||||||
}
|
|
||||||
op := &Operation{OperationType: TraversePath, Value: number, StringValue: numberString}
|
|
||||||
return &Token{TokenType: OperationToken, Operation: op, CheckForPostTraverse: true}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func numberValue() lex.Action {
|
func numberValue() lex.Action {
|
||||||
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
return func(s *lex.Scanner, m *machines.Match) (interface{}, error) {
|
||||||
var numberString = string(m.Bytes)
|
var numberString = string(m.Bytes)
|
||||||
@@ -184,8 +172,12 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
lexer.Add([]byte(`\(`), literalToken(OpenBracket, false))
|
||||||
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
lexer.Add([]byte(`\)`), literalToken(CloseBracket, true))
|
||||||
|
|
||||||
lexer.Add([]byte(`\.\[\]`), pathToken(false))
|
lexer.Add([]byte(`\.\[`), literalToken(TraverseArrayCollect, false))
|
||||||
lexer.Add([]byte(`\.\.`), opToken(RecursiveDescent))
|
lexer.Add([]byte(`\.\.`), opTokenWithPrefs(RecursiveDescent, nil, &RecursiveDescentPreferences{RecurseArray: true,
|
||||||
|
TraversePreferences: &TraversePreferences{FollowAlias: false, IncludeMapKeys: false}}))
|
||||||
|
|
||||||
|
lexer.Add([]byte(`\.\.\.`), opTokenWithPrefs(RecursiveDescent, nil, &RecursiveDescentPreferences{RecurseArray: true,
|
||||||
|
TraversePreferences: &TraversePreferences{FollowAlias: false, IncludeMapKeys: true}}))
|
||||||
|
|
||||||
lexer.Add([]byte(`,`), opToken(Union))
|
lexer.Add([]byte(`,`), opToken(Union))
|
||||||
lexer.Add([]byte(`:\s*`), opToken(CreateMap))
|
lexer.Add([]byte(`:\s*`), opToken(CreateMap))
|
||||||
@@ -197,12 +189,15 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`or`), opToken(Or))
|
lexer.Add([]byte(`or`), opToken(Or))
|
||||||
lexer.Add([]byte(`and`), opToken(And))
|
lexer.Add([]byte(`and`), opToken(And))
|
||||||
lexer.Add([]byte(`not`), opToken(Not))
|
lexer.Add([]byte(`not`), opToken(Not))
|
||||||
|
lexer.Add([]byte(`\/\/`), opToken(Alternative))
|
||||||
|
|
||||||
lexer.Add([]byte(`documentIndex`), opToken(GetDocumentIndex))
|
lexer.Add([]byte(`documentIndex`), opToken(GetDocumentIndex))
|
||||||
|
|
||||||
lexer.Add([]byte(`style`), opAssignableToken(GetStyle, AssignStyle))
|
lexer.Add([]byte(`style`), opAssignableToken(GetStyle, AssignStyle))
|
||||||
|
|
||||||
lexer.Add([]byte(`tag`), opAssignableToken(GetTag, AssignTag))
|
lexer.Add([]byte(`tag`), opAssignableToken(GetTag, AssignTag))
|
||||||
|
lexer.Add([]byte(`anchor`), opAssignableToken(GetAnchor, AssignAnchor))
|
||||||
|
lexer.Add([]byte(`alias`), opAssignableToken(GetAlias, AssignAlias))
|
||||||
lexer.Add([]byte(`filename`), opToken(GetFilename))
|
lexer.Add([]byte(`filename`), opToken(GetFilename))
|
||||||
lexer.Add([]byte(`fileIndex`), opToken(GetFileIndex))
|
lexer.Add([]byte(`fileIndex`), opToken(GetFileIndex))
|
||||||
lexer.Add([]byte(`path`), opToken(GetPath))
|
lexer.Add([]byte(`path`), opToken(GetPath))
|
||||||
@@ -224,8 +219,6 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
|
|
||||||
lexer.Add([]byte(`\s*\|=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{true}))
|
lexer.Add([]byte(`\s*\|=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{true}))
|
||||||
|
|
||||||
lexer.Add([]byte(`\.\[-?[0-9]+\]`), arrayIndextoken(true))
|
|
||||||
|
|
||||||
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
lexer.Add([]byte("( |\t|\n|\r)+"), skip)
|
||||||
|
|
||||||
lexer.Add([]byte(`d[0-9]+`), documentToken())
|
lexer.Add([]byte(`d[0-9]+`), documentToken())
|
||||||
@@ -245,7 +238,7 @@ func initLexer() (*lex.Lexer, error) {
|
|||||||
lexer.Add([]byte(`[Nn][Uu][Ll][Ll]`), nullValue())
|
lexer.Add([]byte(`[Nn][Uu][Ll][Ll]`), nullValue())
|
||||||
lexer.Add([]byte(`~`), nullValue())
|
lexer.Add([]byte(`~`), nullValue())
|
||||||
|
|
||||||
lexer.Add([]byte(`"[^ "]*"`), stringValue(true))
|
lexer.Add([]byte(`"[^"]*"`), stringValue(true))
|
||||||
|
|
||||||
lexer.Add([]byte(`\[`), literalToken(OpenCollect, false))
|
lexer.Add([]byte(`\[`), literalToken(OpenCollect, false))
|
||||||
lexer.Add([]byte(`\]`), literalToken(CloseCollect, true))
|
lexer.Add([]byte(`\]`), literalToken(CloseCollect, true))
|
||||||
@@ -283,7 +276,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) {
|
|||||||
scanner, err := p.lexer.Scanner([]byte(path))
|
scanner, err := p.lexer.Scanner([]byte(path))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
||||||
}
|
}
|
||||||
var tokens []*Token
|
var tokens []*Token
|
||||||
for tok, err, eof := scanner.Next(); !eof; tok, err, eof = scanner.Next() {
|
for tok, err, eof := scanner.Next(); !eof; tok, err, eof = scanner.Next() {
|
||||||
@@ -294,35 +287,69 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) {
|
|||||||
tokens = append(tokens, token)
|
tokens = append(tokens, token)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Parsing expression: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var postProcessedTokens = make([]*Token, 0)
|
var postProcessedTokens = make([]*Token, 0)
|
||||||
|
|
||||||
skipNextToken := false
|
skipNextToken := false
|
||||||
|
|
||||||
for index, token := range tokens {
|
for index := range tokens {
|
||||||
if skipNextToken {
|
if skipNextToken {
|
||||||
skipNextToken = false
|
skipNextToken = false
|
||||||
} else {
|
} else {
|
||||||
|
postProcessedTokens, skipNextToken = p.handleToken(tokens, index, postProcessedTokens)
|
||||||
if index != len(tokens)-1 && token.AssignOperation != nil &&
|
|
||||||
tokens[index+1].TokenType == OperationToken &&
|
|
||||||
tokens[index+1].Operation.OperationType == Assign {
|
|
||||||
token.Operation = token.AssignOperation
|
|
||||||
skipNextToken = true
|
|
||||||
}
|
|
||||||
|
|
||||||
postProcessedTokens = append(postProcessedTokens, token)
|
|
||||||
|
|
||||||
if index != len(tokens)-1 && token.CheckForPostTraverse &&
|
|
||||||
tokens[index+1].TokenType == OperationToken &&
|
|
||||||
tokens[index+1].Operation.OperationType == TraversePath {
|
|
||||||
op := &Operation{OperationType: Pipe, Value: "PIPE"}
|
|
||||||
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return postProcessedTokens, nil
|
return postProcessedTokens, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *pathTokeniser) handleToken(tokens []*Token, index int, postProcessedTokens []*Token) (tokensAccum []*Token, skipNextToken bool) {
|
||||||
|
skipNextToken = false
|
||||||
|
token := tokens[index]
|
||||||
|
|
||||||
|
if token.TokenType == TraverseArrayCollect {
|
||||||
|
//need to put a traverse array then a collect token
|
||||||
|
// do this by adding traverse then converting token to collect
|
||||||
|
|
||||||
|
op := &Operation{OperationType: TraverseArray, StringValue: "TRAVERSE_ARRAY"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||||
|
|
||||||
|
token = &Token{TokenType: OpenCollect}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if index != len(tokens)-1 && token.AssignOperation != nil &&
|
||||||
|
tokens[index+1].TokenType == OperationToken &&
|
||||||
|
tokens[index+1].Operation.OperationType == Assign {
|
||||||
|
token.Operation = token.AssignOperation
|
||||||
|
skipNextToken = true
|
||||||
|
}
|
||||||
|
|
||||||
|
postProcessedTokens = append(postProcessedTokens, token)
|
||||||
|
|
||||||
|
if index != len(tokens)-1 && token.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == OperationToken &&
|
||||||
|
tokens[index+1].Operation.OperationType == TraversePath {
|
||||||
|
op := &Operation{OperationType: ShortPipe, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||||
|
}
|
||||||
|
if index != len(tokens)-1 && token.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == OpenCollect {
|
||||||
|
|
||||||
|
op := &Operation{OperationType: ShortPipe, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||||
|
|
||||||
|
op = &Operation{OperationType: TraverseArray}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||||
|
}
|
||||||
|
if index != len(tokens)-1 && token.CheckForPostTraverse &&
|
||||||
|
tokens[index+1].TokenType == TraverseArrayCollect {
|
||||||
|
|
||||||
|
op := &Operation{OperationType: ShortPipe, Value: "PIPE"}
|
||||||
|
postProcessedTokens = append(postProcessedTokens, &Token{TokenType: OperationToken, Operation: op})
|
||||||
|
|
||||||
|
}
|
||||||
|
return postProcessedTokens, skipNextToken
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
var myPathTokeniser = NewPathTokeniser()
|
var myPathTokeniser = NewPathTokeniser()
|
||||||
var myPathPostfixer = NewPathPostFixer()
|
var myPathPostfixer = NewPathPostFixer()
|
||||||
@@ -49,10 +52,16 @@ func (p *pathTreeCreator) CreatePathTree(postFixPath []*Operation) (*PathTreeNod
|
|||||||
if Operation.OperationType.NumArgs > 0 {
|
if Operation.OperationType.NumArgs > 0 {
|
||||||
numArgs := Operation.OperationType.NumArgs
|
numArgs := Operation.OperationType.NumArgs
|
||||||
if numArgs == 1 {
|
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]
|
remaining, rhs := stack[:len(stack)-1], stack[len(stack)-1]
|
||||||
newNode.Rhs = rhs
|
newNode.Rhs = rhs
|
||||||
stack = remaining
|
stack = remaining
|
||||||
} else if numArgs == 2 {
|
} 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]
|
remaining, lhs, rhs := stack[:len(stack)-2], stack[len(stack)-2], stack[len(stack)-1]
|
||||||
newNode.Lhs = lhs
|
newNode.Lhs = lhs
|
||||||
newNode.Rhs = rhs
|
newNode.Rhs = rhs
|
||||||
@@ -62,7 +71,7 @@ func (p *pathTreeCreator) CreatePathTree(postFixPath []*Operation) (*PathTreeNod
|
|||||||
stack = append(stack, &newNode)
|
stack = append(stack, &newNode)
|
||||||
}
|
}
|
||||||
if len(stack) != 1 {
|
if len(stack) != 1 {
|
||||||
return nil, fmt.Errorf("expected stack to have 1 thing but its %v", stack)
|
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
|
return stack[0], nil
|
||||||
}
|
}
|
||||||
|
|||||||
42
pkg/yqlib/path_tree_test.go
Normal file
42
pkg/yqlib/path_tree_test.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mikefarah/yq/v4/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPathTreeNoArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath("=")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 0", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneLhsArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath(".a =")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneRhsArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath("= .a")
|
||||||
|
test.AssertResultComplex(t, "'=' expects 2 args but there is 1", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeTwoArgsForTwoArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath(".a = .b")
|
||||||
|
test.AssertResultComplex(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeNoArgsForOneArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath("explode")
|
||||||
|
test.AssertResultComplex(t, "'explode' expects 1 arg but received none", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeOneArgForOneArgOp(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath("explode(.)")
|
||||||
|
test.AssertResultComplex(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPathTreeExtraArgs(t *testing.T) {
|
||||||
|
_, err := treeCreator.ParsePath("sortKeys(.) explode(.)")
|
||||||
|
test.AssertResultComplex(t, "expected end of expression but found 'explode', please check expression syntax", err.Error())
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ type resultsPrinter struct {
|
|||||||
writer io.Writer
|
writer io.Writer
|
||||||
firstTimePrinting bool
|
firstTimePrinting bool
|
||||||
previousDocIndex uint
|
previousDocIndex uint
|
||||||
|
previousFileIndex int
|
||||||
printedMatches bool
|
printedMatches bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,19 +90,20 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if p.firstTimePrinting {
|
if p.firstTimePrinting {
|
||||||
p.previousDocIndex = matchingNodes.Front().Value.(*CandidateNode).Document
|
node := matchingNodes.Front().Value.(*CandidateNode)
|
||||||
|
p.previousDocIndex = node.Document
|
||||||
|
p.previousFileIndex = node.FileIndex
|
||||||
p.firstTimePrinting = false
|
p.firstTimePrinting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
for el := matchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
mappedDoc := el.Value.(*CandidateNode)
|
mappedDoc := el.Value.(*CandidateNode)
|
||||||
log.Debug("-- print sep logic: p.firstTimePrinting: %v, previousDocIndex: %v, mappedDoc.Document: %v, printDocSeparators: %v", p.firstTimePrinting, p.previousDocIndex, mappedDoc.Document, p.printDocSeparators)
|
log.Debug("-- print sep logic: p.firstTimePrinting: %v, previousDocIndex: %v, mappedDoc.Document: %v, printDocSeparators: %v", p.firstTimePrinting, p.previousDocIndex, mappedDoc.Document, p.printDocSeparators)
|
||||||
if (p.previousDocIndex != mappedDoc.Document) && p.printDocSeparators {
|
if (p.previousDocIndex != mappedDoc.Document || p.previousFileIndex != mappedDoc.FileIndex) && p.printDocSeparators {
|
||||||
log.Debug("-- writing doc sep")
|
log.Debug("-- writing doc sep")
|
||||||
if err := p.writeString(bufferedWriter, "---\n"); err != nil {
|
if err := p.writeString(bufferedWriter, "---\n"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.printNode(mappedDoc.Node, bufferedWriter); err != nil {
|
if err := p.printNode(mappedDoc.Node, bufferedWriter); err != nil {
|
||||||
|
|||||||
@@ -52,7 +52,53 @@ func TestPrinterMultipleDocsInSequence(t *testing.T) {
|
|||||||
|
|
||||||
writer.Flush()
|
writer.Flush()
|
||||||
test.AssertResult(t, multiDocSample, output.String())
|
test.AssertResult(t, multiDocSample, output.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrinterMultipleFilesInSequence(t *testing.T) {
|
||||||
|
var output bytes.Buffer
|
||||||
|
var writer = bufio.NewWriter(&output)
|
||||||
|
printer := NewPrinter(writer, false, true, false, 2, true)
|
||||||
|
|
||||||
|
inputs, err := readDocuments(strings.NewReader(multiDocSample), "sample.yml", 0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
el := inputs.Front()
|
||||||
|
elNode := el.Value.(*CandidateNode)
|
||||||
|
elNode.Document = 0
|
||||||
|
elNode.FileIndex = 0
|
||||||
|
sample1 := nodeToMap(elNode)
|
||||||
|
|
||||||
|
el = el.Next()
|
||||||
|
elNode = el.Value.(*CandidateNode)
|
||||||
|
elNode.Document = 0
|
||||||
|
elNode.FileIndex = 1
|
||||||
|
sample2 := nodeToMap(elNode)
|
||||||
|
|
||||||
|
el = el.Next()
|
||||||
|
elNode = el.Value.(*CandidateNode)
|
||||||
|
elNode.Document = 0
|
||||||
|
elNode.FileIndex = 2
|
||||||
|
sample3 := nodeToMap(elNode)
|
||||||
|
|
||||||
|
err = printer.PrintResults(sample1)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = printer.PrintResults(sample2)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = printer.PrintResults(sample3)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Flush()
|
||||||
|
test.AssertResult(t, multiDocSample, output.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPrinterMultipleDocsInSinglePrint(t *testing.T) {
|
func TestPrinterMultipleDocsInSinglePrint(t *testing.T) {
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
- increment version in version.go
|
- increment version in version.go
|
||||||
- increment version in snapcraft.yaml
|
- increment version in snapcraft.yaml
|
||||||
- commit
|
- increment version in github-action/Dockerfile
|
||||||
- tag git with same version number
|
|
||||||
- make sure local build passes
|
- make sure local build passes
|
||||||
- push tag to git
|
- tag git with same version number
|
||||||
- git push --tags
|
- commit vX tag - this will trigger github actions
|
||||||
- make local xcompile (builds binaries for all platforms)
|
- use github actions to publish docker and make github release
|
||||||
|
- check github updated yq action in marketplace
|
||||||
- git release
|
|
||||||
./scripts/release.sh
|
|
||||||
./scripts/upload.sh
|
|
||||||
|
|
||||||
- snapcraft
|
- snapcraft
|
||||||
- will auto create a candidate, test it works then promote
|
- will auto create a candidate, test it works then promote
|
||||||
@@ -30,7 +26,7 @@
|
|||||||
|
|
||||||
- docker
|
- docker
|
||||||
- build and push latest and new version tag
|
- build and push latest and new version tag
|
||||||
- docker build . -t mikefarah/yq:latest -t mikefarah/yq:VERSION
|
- docker build . -t mikefarah/yq:latest -t mikefarah/yq:3 -t mikefarah/yq:3.X
|
||||||
|
|
||||||
- debian package
|
- debian package
|
||||||
- ensure you get all vendor dependencies before packaging
|
- ensure you get all vendor dependencies before packaging
|
||||||
|
|||||||
@@ -3,7 +3,12 @@
|
|||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
./bin/golangci-lint run
|
if command -v golangci-lint &> /dev/null
|
||||||
|
then
|
||||||
|
golangci-lint run --timeout=5m
|
||||||
|
else
|
||||||
|
./bin/golangci-lint run --timeout=5m
|
||||||
|
fi
|
||||||
|
|
||||||
# ./bin/golangci-lint \
|
# ./bin/golangci-lint \
|
||||||
# --tests \
|
# --tests \
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
find . \( -path ./vendor \) -prune -o -name "*.go" -exec goimports -w {} \;
|
find . \( -path ./vendor \) -prune -o -name "*.go" -exec goimports -w {} \;
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
go mod vendor
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -ex
|
|
||||||
VERSION="$(git describe --tags --abbrev=0)"
|
|
||||||
docker build \
|
|
||||||
--target production \
|
|
||||||
--build-arg VERSION=${VERSION} \
|
|
||||||
-t mikefarah/yq:latest \
|
|
||||||
-t mikefarah/yq:${VERSION} \
|
|
||||||
.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -ex
|
|
||||||
GITHUB_TOKEN="${GITHUB_TOKEN:?missing required input \'GITHUB_TOKEN\'}"
|
|
||||||
|
|
||||||
CURRENT="$(git describe --tags --abbrev=0)"
|
|
||||||
PREVIOUS="$(git describe --tags --abbrev=0 --always "${CURRENT}"^)"
|
|
||||||
OWNER="mikefarah"
|
|
||||||
REPO="yq"
|
|
||||||
|
|
||||||
release() {
|
|
||||||
github-release release \
|
|
||||||
--user "$OWNER" \
|
|
||||||
--draft \
|
|
||||||
--repo "$REPO" \
|
|
||||||
--tag "$CURRENT"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
release
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -ex
|
|
||||||
GITHUB_TOKEN="${GITHUB_TOKEN:?missing required input \'GITHUB_TOKEN\'}"
|
|
||||||
|
|
||||||
CURRENT="$(git describe --tags --abbrev=0)"
|
|
||||||
PREVIOUS="$(git describe --tags --abbrev=0 --always "${CURRENT}"^)"
|
|
||||||
OWNER="mikefarah"
|
|
||||||
REPO="yq"
|
|
||||||
|
|
||||||
upload() {
|
|
||||||
mkdir -p ./build-done
|
|
||||||
while IFS= read -r -d $'\0'; do
|
|
||||||
file=$REPLY
|
|
||||||
BINARY=$(basename "${file}")
|
|
||||||
echo "--> ${BINARY}"
|
|
||||||
github-release upload \
|
|
||||||
--replace \
|
|
||||||
--user "$OWNER" \
|
|
||||||
--repo "$REPO" \
|
|
||||||
--tag "$CURRENT" \
|
|
||||||
--name "${BINARY}" \
|
|
||||||
--file "$file"
|
|
||||||
mv "$file" "./build-done/${BINARY}"
|
|
||||||
done < <(find ./build -mindepth 1 -maxdepth 1 -print0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
upload
|
|
||||||
@@ -1,14 +1,24 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
# This assumes that gonative and gox is installed as per the 'one time setup' instructions
|
# This assumes that gonative and gox is installed as per the 'one time setup' instructions
|
||||||
# at https://github.com/inconshreveable/gonative
|
# at https://github.com/inconshreveable/gonative
|
||||||
|
|
||||||
|
|
||||||
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}"
|
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}" --osarch="darwin/amd64 freebsd/386 freebsd/amd64 freebsd/arm linux/386 linux/amd64 linux/arm linux/arm64 linux/mips linux/mips64 linux/mips64le linux/mipsle linux/ppc64 linux/ppc64le linux/s390x netbsd/386 netbsd/amd64 netbsd/arm openbsd/386 openbsd/amd64 windows/386 windows/amd64"
|
||||||
# include non-default linux builds too
|
|
||||||
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -os=linux -output="build/yq_{{.OS}}_{{.Arch}}"
|
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
rhash -r -a . -P -o checksums
|
rhash -r -a . -o checksums
|
||||||
|
|
||||||
rhash --list-hashes > checksums_hashes_order
|
rhash --list-hashes > checksums_hashes_order
|
||||||
|
|
||||||
|
find . -executable -type f | xargs -I {} tar czvf {}.tar.gz {}
|
||||||
|
|
||||||
|
# just in case find thinks this is executable...
|
||||||
|
rm -f checksums_hashes_order.tar.gz
|
||||||
|
rm -f checksums.tar.gz
|
||||||
|
|
||||||
|
rm yq_windows_386.exe.tar.gz
|
||||||
|
rm yq_windows_amd64.exe.tar.gz
|
||||||
|
|
||||||
|
zip yq_windows_386.zip yq_windows_386.exe
|
||||||
|
zip yq_windows_amd64.zip yq_windows_amd64.exe
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '4.0.0-beta1'
|
version: '4.2.0'
|
||||||
summary: A lightweight and portable command-line YAML processor
|
summary: A lightweight and portable command-line YAML processor
|
||||||
description: |
|
description: |
|
||||||
The aim of the project is to be the jq or sed of yaml files.
|
The aim of the project is to be the jq or sed of yaml files.
|
||||||
|
|||||||
60
yq_test.go
60
yq_test.go
@@ -1,60 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "fmt"
|
|
||||||
// "runtime"
|
|
||||||
// "testing"
|
|
||||||
|
|
||||||
// "github.com/mikefarah/yq/v2/pkg/marshal"
|
|
||||||
// "github.com/mikefarah/yq/v2/test"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func TestMultilineString(t *testing.T) {
|
|
||||||
// testString := `
|
|
||||||
// abcd
|
|
||||||
// efg`
|
|
||||||
// formattedResult, _ := marshal.NewYamlConverter().YamlToString(testString, false)
|
|
||||||
// test.AssertResult(t, testString, formattedResult)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestNewYaml(t *testing.T) {
|
|
||||||
// result, _ := newYaml([]string{"b.c", "3"})
|
|
||||||
// formattedResult := fmt.Sprintf("%v", result)
|
|
||||||
// test.AssertResult(t,
|
|
||||||
// "[{b [{c 3}]}]",
|
|
||||||
// formattedResult)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestNewYamlArray(t *testing.T) {
|
|
||||||
// result, _ := newYaml([]string{"[0].cat", "meow"})
|
|
||||||
// formattedResult := fmt.Sprintf("%v", result)
|
|
||||||
// test.AssertResult(t,
|
|
||||||
// "[[{cat meow}]]",
|
|
||||||
// formattedResult)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestNewYaml_WithScript(t *testing.T) {
|
|
||||||
// writeScript = "examples/instruction_sample.yaml"
|
|
||||||
// expectedResult := `b:
|
|
||||||
// c: cat
|
|
||||||
// e:
|
|
||||||
// - name: Mike Farah`
|
|
||||||
// result, _ := newYaml([]string{""})
|
|
||||||
// actualResult, _ := marshal.NewYamlConverter().YamlToString(result, true)
|
|
||||||
// test.AssertResult(t, expectedResult, actualResult)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestNewYaml_WithUnknownScript(t *testing.T) {
|
|
||||||
// writeScript = "fake-unknown"
|
|
||||||
// _, err := newYaml([]string{""})
|
|
||||||
// if err == nil {
|
|
||||||
// t.Error("Expected error 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, err.Error())
|
|
||||||
// }
|
|
||||||
Reference in New Issue
Block a user