Compare commits

..
Author SHA1 Message Date
Mike Farah c28e5c58ae Pretty Print tests 2021-08-20 12:21:32 +10:00
Mike Farah 09e5c5b5c5 wip - pretty print 1.1 compat mode 2021-08-15 22:07:05 +10:00
348 changed files with 3367 additions and 18632 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ country: Australia
And we run a command:
```bash
yq 'predictWeatherOf(.country)'
yq eval 'predictWeatherOf(.country)'
```
it could output
-22
View File
@@ -1,22 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: docker
directory: /
schedule:
day: thursday
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
day: thursday
interval: weekly
- package-ecosystem: gomod
directory: /
schedule:
day: thursday
interval: weekly
-70
View File
@@ -1,70 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '24 3 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
-62
View File
@@ -1,62 +0,0 @@
name: Release Docker
on:
release:
types: [released]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
publishDocker:
environment: dockerhub
env:
IMAGE_NAME: mikefarah/yq
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }} && docker version
- name: Build and push image
run: |
echo "GithubRef: ${GITHUB_REF}"
VERSION=${GITHUB_REF##*/}
echo "VERSION: ${VERSION}"
IMAGE_VERSION=${VERSION:1}
echo "IMAGE_VERSION: ${IMAGE_VERSION}"
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 \
--label "org.opencontainers.image.authors=https://github.com/mikefarah/yq/graphs/contributors" \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--label "org.opencontainers.image.description=yq is a portable command-line YAML processor" \
--label "org.opencontainers.image.documentation=https://mikefarah.gitbook.io/yq/" \
--label "org.opencontainers.image.licenses=MIT" \
--label "org.opencontainers.image.revision=$(git rev-parse HEAD)" \
--label "org.opencontainers.image.source=https://github.com/mikefarah/yq" \
--label "org.opencontainers.image.title=yq" \
--label "org.opencontainers.image.url=https://mikefarah.gitbook.io/yq/" \
--label "org.opencontainers.image.version=${IMAGE_VERSION}" \
--platform "${PLATFORMS}" \
--pull \
--push \
-t "${IMAGE_NAME}:${IMAGE_VERSION}" \
-t "${IMAGE_NAME}:4" \
-t "${IMAGE_NAME}:latest" \
.
+7 -11
View File
@@ -1,8 +1,5 @@
name: Build
on: [push, pull_request]
permissions:
contents: read
on: [push]
jobs:
build:
@@ -10,14 +7,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.18
uses: actions/setup-go@v3
- name: Set up Go 1.15
uses: actions/setup-go@v1
with:
go-version: 1.18
go-version: 1.15
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Get dependencies
run: |
@@ -27,9 +24,8 @@ jobs:
dep ensure
fi
- name: Check the build
shell: bash -l {0}
- name: Download deps
run: |
export PATH=${PATH}:`go env GOPATH`/bin
scripts/devtools.sh
make local build
make local build
+52 -35
View File
@@ -3,51 +3,68 @@ on:
push:
tags:
- 'v*'
- 'draft-*'
jobs:
publishGitRelease:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.18'
- name: Compile man page markup
id: gen-man-page-md
run: |
./scripts/generate-man-page-md.sh
echo "::set-output name=man-page-md::man.md"
- name: Get the version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF##*/}
- name: Generate man page
uses: docker://pandoc/core:2.14.2
id: gen-man-page
with:
args: >-
--standalone
--to man
--variable=title:"YQ"
--variable=section:"1"
--variable=header:"yq (https://github.com/mikefarah/yq/) version ${{ steps.get_version.outputs.VERSION }}"
--variable=author:"Mike Farah"
--output=yq.1
${{ steps.gen-man-page-md.outputs.man-page-md }}
go-version: '^1.15'
- name: Cross compile
run: |
sudo apt-get install rhash -y
go install github.com/mitchellh/gox@v1.0.1
mkdir -p build
cp yq.1 build/yq.1
go get github.com/mitchellh/gox
./scripts/xcompile.sh
- name: Release
uses: softprops/action-gh-release@v1
- name: Create Release
id: create_release
uses: actions/create-release@v1.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: build/*
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
fail_on_unmatched_files: 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:
- uses: actions/checkout@v2
- 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 .
+3 -6
View File
@@ -1,8 +1,5 @@
name: Test Yq Action
on: [push]
permissions:
contents: read
jobs:
build:
@@ -10,13 +7,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Get test
uses: mikefarah/yq@master
with:
cmd: yq eval '.a' examples/sample.yaml
cmd: yq eval '.a' examples/data1.yaml
- name: Write inplace test
id: lookupSdkVersion
uses: mikefarah/yq@master
with:
cmd: yq eval -i '.b.c = 5' examples/sample.yaml
cmd: yq eval -i '.a.b = 5' examples/data1.yaml
+1 -18
View File
@@ -38,22 +38,5 @@ parts/
prime/
.snapcraft/
yq*.snap
test.yml
test*.yml
test*.yaml
0.yml
1.yml
2.yml
# man page
man.md
yq.1
# debian pkg
_build
debian/files
# intellij
/.idea
test2.yml
-40
View File
@@ -1,40 +0,0 @@
run:
timeout: 5m
linters:
enable:
- asciicheck
- depguard
- errorlint
- gci
- gochecknoinits
- gofmt
- goimports
- gosec
- megacheck
- misspell
- nakedret
- nolintlint
- predeclared
- revive
- unconvert
- unparam
linters-settings:
depguard:
list-type: blacklist
include-go-root: true
packages:
- io/ioutil
packages-with-error-message:
- io/ioutil: "The 'io/ioutil' package is deprecated. Use corresponding 'os' or 'io' functions instead."
issues:
exclude-rules:
- linters:
- gosec
text: "Implicit memory aliasing in for loop."
path: _test\.go
- linters:
- revive
text: "unexported-return"
- linters:
- revive
text: "var-naming"
-32
View File
@@ -1,5 +1,3 @@
# Development
1. Install (golang)[https://golang.org/]
1. Run `scripts/devtools.sh` to install the required devtools
2. Run `make [local] vendor` to install the vendor dependencies
@@ -8,33 +6,3 @@
4. Make the code changes.
5. `make [local] test` to lint code and run tests
6. Profit! ok no profit, but raise a PR and get kudos :)
# Documentation
The documentation is a bit of a mixed bag (sorry in advanced, I do plan on simplifying it...) - with some parts automatically generated and stiched together and some statically defined.
Documentation is written in markdown, and is published in the 'gitbook' branch.
The various operator documentation (e.g. 'strings') are generated from the 'master' branch, and have a statically defined header (e.g. `pkg/yqlib/doc/operators/headers/add.md`) and the bulk of the docs are generated from the unit tests e.g. `pkg/yqlib/operator_add_test.go`.
The pipeline will run the tests and automatically concatenate the files together, and put them under
`pkg/qylib/doc/add.md`. These files are checked in the master branch (and are copied to the gitbook branch as part of the release process).
## How to contribute
The first step is to find if what you want is automatically generated or not - start by looking in the master branch.
### Updating dynamic documentation from master
- Search for the documentation you want to update. If you find matches in a `*_test.go` file - update that, as that will automatically update the matching `*.md` file
- Assuming you are updating a `*_test.go` file, once updated, run the test to regenerated the docs. E.g. for the 'Add' test generated docs, from the pkg/yqlib folder run:
`go test -run TestAddOperatorScenarios` which will run that test defined in the `operator_add_test.go` file.
- Ensure the tests still pass, and check the generated documentation have your update.
- Note: If the documentation is only in a `headers/*.md` file, then just update that directly
- Raise a PR to merge the changes into master!
### Updating static documentation from the gitbook branch
If you haven't found what you want to update in the master branch, then check the gitbook branch directly as there are a few pages in there that are not in master.
- Update the `*.md` files
- Raise a PR to merge the changes into gitbook.
+18 -14
View File
@@ -1,28 +1,32 @@
FROM golang:1.18.4 as builder
FROM golang:1.15 as builder
WORKDIR /go/src/mikefarah/yq
COPY . .
# cache devtools
COPY ./scripts/devtools.sh /go/src/mikefarah/yq/scripts/devtools.sh
RUN ./scripts/devtools.sh
RUN CGO_ENABLED=0 go build .
# RUN ./scripts/test.sh -- this too often times out in the github pipeline.
RUN ./scripts/acceptance.sh
COPY . /go/src/mikefarah/yq
RUN CGO_ENABLED=0 make local build
# Choose alpine as a base image to make this useful for CI, as many
# CI tools expect an interactive shell inside the container
FROM alpine:3 as production
LABEL maintainer="Mike Farah <mikefarah@users.noreply.github.com>"
FROM alpine:3.13.5 as production
RUN mkdir /home/yq/
RUN addgroup -g 1000 yq && \
adduser -u 1000 -G yq -s /bin/bash -h /home/yq -D yq
RUN chown -R yq:yq /home/yq/
COPY --from=builder /go/src/mikefarah/yq/yq /usr/bin/yq
RUN chmod +x /usr/bin/yq
WORKDIR /workdir
RUN set -eux; \
addgroup -g 1000 yq; \
adduser -u 1000 -G yq -s /bin/sh -h /home/yq -D yq
RUN chown -R yq:yq /workdir
ARG VERSION=none
LABEL version=${VERSION}
USER yq
WORKDIR /workdir
ENTRYPOINT ["/usr/bin/yq"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.18.4
FROM golang:1.15
COPY scripts/devtools.sh /opt/devtools.sh
-2
View File
@@ -1,5 +1,3 @@
The MIT License (MIT)
Copyright (c) 2017 Mike Farah
Permission is hereby granted, free of charge, to any person obtaining a copy
+18 -23
View File
@@ -2,7 +2,6 @@ MAKEFLAGS += --warn-undefined-variables
SHELL := /bin/bash
.SHELLFLAGS := -o pipefail -euc
.DEFAULT_GOAL := install
ENGINE := $(shell { command -v podman || command -v docker; } 2>/dev/null)
include Makefile.variables
@@ -34,7 +33,7 @@ clean:
## prefix before other make targets to run in your local dev environment
local: | quiet
@$(eval ENGINERUN= )
@$(eval DOCKRUN= )
@mkdir -p tmp
@touch tmp/dev_image_id
quiet: # this is silly but shuts up 'Nothing to be done for `local`'
@@ -43,9 +42,9 @@ quiet: # this is silly but shuts up 'Nothing to be done for `local`'
prepare: tmp/dev_image_id
tmp/dev_image_id: Dockerfile.dev scripts/devtools.sh
@mkdir -p tmp
@${ENGINE} rmi -f ${DEV_IMAGE} > /dev/null 2>&1 || true
@${ENGINE} build -t ${DEV_IMAGE} -f Dockerfile.dev .
@${ENGINE} inspect -f "{{ .ID }}" ${DEV_IMAGE} > tmp/dev_image_id
@docker rmi -f ${DEV_IMAGE} > /dev/null 2>&1 || true
@docker build -t ${DEV_IMAGE} -f Dockerfile.dev .
@docker inspect -f "{{ .ID }}" ${DEV_IMAGE} > tmp/dev_image_id
# ----------------------------------------------
# build
@@ -55,61 +54,57 @@ build: build/dev
.PHONY: build/dev
build/dev: test *.go
@mkdir -p bin/
${ENGINERUN} go build --ldflags "$(LDFLAGS)"
${ENGINERUN} bash ./scripts/acceptance.sh
${DOCKRUN} go build --ldflags "$(LDFLAGS)"
${DOCKRUN} bash ./scripts/acceptance.sh
## Compile the project for multiple OS and Architectures.
xcompile: check
@rm -rf build/
@mkdir -p build
${ENGINERUN} bash ./scripts/xcompile.sh
${DOCKRUN} bash ./scripts/xcompile.sh
@find build -type d -exec chmod 755 {} \; || :
@find build -type f -exec chmod 755 {} \; || :
.PHONY: install
install: build
${ENGINERUN} go install
${DOCKRUN} go install
# Each of the fetch should be an entry within vendor.json; not currently included within project
.PHONY: vendor
vendor: tmp/dev_image_id
@mkdir -p vendor
${ENGINERUN} go mod vendor
${DOCKRUN} go mod vendor
# ----------------------------------------------
# develop and test
.PHONY: format
format: vendor
${ENGINERUN} bash ./scripts/format.sh
.PHONY: secure
secure: format
${ENGINERUN} bash ./scripts/secure.sh
${DOCKRUN} bash ./scripts/format.sh
.PHONY: check
check: secure
${ENGINERUN} bash ./scripts/check.sh
check: format
${DOCKRUN} bash ./scripts/check.sh
.PHONY: secure
secure:
${DOCKRUN} bash ./scripts/secure.sh
.PHONY: test
test: check
${ENGINERUN} bash ./scripts/test.sh
${DOCKRUN} bash ./scripts/test.sh
.PHONY: cover
cover: check
@rm -rf cover/
@mkdir -p cover
${ENGINERUN} bash ./scripts/coverage.sh
${DOCKRUN} bash ./scripts/coverage.sh
@find cover -type d -exec chmod 755 {} \; || :
@find cover -type f -exec chmod 644 {} \; || :
.PHONY: release
release: xcompile
${ENGINERUN} bash ./scripts/publish.sh
${DOCKRUN} bash ./scripts/publish.sh
# ----------------------------------------------
# utilities
+1 -1
View File
@@ -29,7 +29,7 @@ endif
DEV_IMAGE := ${PROJECT}_dev
ENGINERUN := ${ENGINE} run --rm \
DOCKRUN := docker run --rm \
-e LDFLAGS="${LDFLAGS}" \
-e GITHUB_TOKEN="${GITHUB_TOKEN}" \
-v ${ROOT}/vendor:/go/src \
+61 -137
View File
@@ -1,77 +1,45 @@
# yq
![Build](https://github.com/mikefarah/yq/workflows/Build/badge.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/mikefarah/yq.svg) ![Github Releases (by Release)](https://img.shields.io/github/downloads/mikefarah/yq/total.svg) ![Go Report](https://goreportcard.com/badge/github.com/mikefarah/yq) ![CodeQL](https://github.com/mikefarah/yq/workflows/CodeQL/badge.svg)
![Build](https://github.com/mikefarah/yq/workflows/Build/badge.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/mikefarah/yq.svg) ![Github Releases (by Release)](https://img.shields.io/github/downloads/mikefarah/yq/total.svg) ![Go Report](https://goreportcard.com/badge/github.com/mikefarah/yq)
a lightweight and portable command-line YAML, JSON and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json and xml. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
a lightweight and portable command-line YAML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
yq is written in go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as Docker and Podman, all listed below.
## Notice for v4.x versions prior to 4.18.1
Since 4.18.1, yq's 'eval/e' command is the _default_ command and no longer needs to be specified.
Older versions will still need to specify 'eval/e'.
Similarly, '-' is no longer required as a filename to read from STDIN (unless reading from one or more files).
TLDR:
Prior to 4.18.1
```bash
yq e '.cool' - < file.yaml
```
4.18+
```bash
yq '.cool' < file.yaml
```
When merging multiple files together, `eval-all/ea` is still required to tell `yq` to run the expression against all the document at once.
yq is written in go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as docker, all listed below.
## Quick Usage Guide
Read a value:
```bash
yq '.a.b[0].c' file.yaml
```
Pipe from STDIN:
```bash
yq '.a.b[0].c' < file.yaml
yq e '.a.b[0].c' file.yaml
```
Update a yaml file, inplace
```bash
yq -i '.a.b[0].c = "cool"' file.yaml
yq e -i '.a.b[0].c = "cool"' file.yaml
```
Update using environment variables
```bash
NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
NAME=mike yq e -i '.a.b[0].c = strenv(NAME)' file.yaml
```
Merge multiple files
```bash
# note the use of `ea` to evaluate all the files at once
# instead of in sequence
yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
```
yq ea '. as $item ireduce ({}; . * $item )' file1.yml file2.yml ...
```
Multiple updates to a yaml file
```bash
yq -i '
yq e -i '
.a.b[0].c = "cool" |
.x.y.z = "foobar" |
.person.name = strenv(NAME)
' file.yaml
```
Convert JSON to YAML
```bash
yq -P sample.json
```
See the [documentation](https://mikefarah.gitbook.io/yq/) for more examples.
See the [documentation](https://mikefarah.gitbook.io/yq/) for more.
## Install
@@ -101,41 +69,49 @@ Using [Homebrew](https://brew.sh/)
brew install yq
```
or, for the (deprecated) v3 version:
```
brew install yq@3
```
Note that for v3, as it is a versioned brew it will not add the `yq` command to your path automatically. Please follow the instructions given by brew upon installation.
### Linux via snap:
```
snap install yq
```
or, for the (deprecated) v3 version:
```
snap install yq --channel=v3/stable
```
#### Snap notes
`yq` installs with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. To read root files you can:
```
sudo cat /etc/myfile | yq '.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):
```
sudo cat /etc/myfile | yq '.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:
```
sudo cat /etc/myfile | yq '.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
rm /etc/myfile.tmp
```
### Run with Docker or Podman
### Run with Docker
#### Oneshot use:
```bash
docker run --rm -v "${PWD}":/workdir mikefarah/yq [command] [flags] [expression ]FILE...
```
Note that you can run `yq` in docker without network access and other privileges if you desire,
namely `--security-opt=no-new-privileges --cap-drop all --network none`.
```bash
podman run --rm -v "${PWD}":/workdir mikefarah/yq [command] [flags] [expression ]FILE...
docker run --rm -v "${PWD}":/workdir mikefarah/yq <command> [flags] [expression ]FILE...
```
#### Pipe in via STDIN:
@@ -143,11 +119,7 @@ podman run --rm -v "${PWD}":/workdir mikefarah/yq [command] [flags] [expression
You'll need to pass the `-i\--interactive` flag to docker:
```bash
docker run -i --rm mikefarah/yq '.this.thing' < myfile.yml
```
```bash
podman run -i --rm mikefarah/yq '.this.thing' < myfile.yml
cat myfile.yml | docker run -i --rm mikefarah/yq e . -
```
#### Run commands interactively:
@@ -156,10 +128,6 @@ podman run -i --rm mikefarah/yq '.this.thing' < myfile.yml
docker run --rm -it -v "${PWD}":/workdir --entrypoint sh mikefarah/yq
```
```bash
podman run --rm -it -v "${PWD}":/workdir --entrypoint sh mikefarah/yq
```
It can be useful to have a bash function to avoid typing the whole docker command:
```bash
@@ -168,42 +136,23 @@ yq() {
}
```
```bash
yq() {
podman run --rm -i -v "${PWD}":/workdir mikefarah/yq "$@"
}
```
#### Running as root:
`yq`'s container image no longer runs under root (https://github.com/mikefarah/yq/pull/860). If you'd like to install more things in the container image, or you're having permissions issues when attempting to read/write files you'll need to either:
`yq`'s docker image no longer runs under root (https://github.com/mikefarah/yq/pull/860). If you'd like to install more things in the docker image, or you're having permissions issues when attempting to read/write files you'll need to either:
```
docker run --user="root" -it --entrypoint sh mikefarah/yq
```
```
podman run --user="root" -it --entrypoint sh mikefarah/yq
```
Or, in your Dockerfile:
Or, in your docker file:
```
FROM mikefarah/yq
USER root
RUN apk add --no-cache bash
USER yq
```
#### Missing timezone data
By default, the alpine image yq uses does not include timezone data. If you'd like to use the `tz` operator, you'll need to include this data:
```
FROM mikefarah/yq
USER root
RUN apk add --no-cache tzdata
RUN apk add bash
USER yq
```
@@ -212,14 +161,14 @@ USER yq
- name: Set foobar to cool
uses: mikefarah/yq@master
with:
cmd: yq -i '.foo.bar = "cool"' 'config.yml'
cmd: yq eval -i '.foo.bar = "cool"' 'config.yml'
```
See https://mikefarah.gitbook.io/yq/usage/github-action for more.
### Go Install:
### Go Get:
```
go install github.com/mikefarah/yq/v4@latest
GO111MODULE=on go get github.com/mikefarah/yq/v4
```
## Community Supported Installation methods
@@ -234,12 +183,6 @@ webi yq
See [webi](https://webinstall.dev/)
Supported by @adithyasunil26 (https://github.com/webinstall/webi-installers/tree/master/yq)
### Arch Linux
```
pacman -S go-yq
```
### Windows:
[![Chocolatey](https://img.shields.io/chocolatey/v/yq.svg)](https://chocolatey.org/packages/yq)
[![Chocolatey](https://img.shields.io/chocolatey/dt/yq.svg)](https://chocolatey.org/packages/yq)
@@ -277,23 +220,18 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/yq)
## Features
- [Detailed documentation with many examples](https://mikefarah.gitbook.io/yq/)
- Written in portable go, so you can download a lovely dependency free binary
- Uses similar syntax as `jq` but works with YAML, [JSON](https://mikefarah.gitbook.io/yq/usage/convert) and [XML](https://mikefarah.gitbook.io/yq/usage/xml) files
- Uses similar syntax as `jq` but works with YAML and JSON files
- Fully supports multi document yaml files
- Supports yaml [front matter](https://mikefarah.gitbook.io/yq/usage/front-matter) blocks (e.g. jekyll/assemble)
- Colorized yaml output
- [Date/Time manipulation and formatting with TZ](https://mikefarah.gitbook.io/yq/operators/datetime)
- [Deeply data structures](https://mikefarah.gitbook.io/yq/operators/traverse-read)
- [Sort keys](https://mikefarah.gitbook.io/yq/operators/sort-keys)
- [Deeply traverse yaml](https://mikefarah.gitbook.io/yq/operators/traverse-read)
- [Sort yaml by keys](https://mikefarah.gitbook.io/yq/operators/sort-keys)
- Manipulate yaml [comments](https://mikefarah.gitbook.io/yq/operators/comment-operators), [styling](https://mikefarah.gitbook.io/yq/operators/style), [tags](https://mikefarah.gitbook.io/yq/operators/tag) and [anchors and aliases](https://mikefarah.gitbook.io/yq/operators/anchor-and-alias-operators).
- [Update inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
- [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
- [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/operators/select#select-and-update-matching-values-in-map)
- Keeps yaml formatting and comments when updating (though there are issues with whitespace)
- [Decode/Encode base64 data](https://mikefarah.gitbook.io/yq/operators/encode-decode)
- [Load content from other files](https://mikefarah.gitbook.io/yq/operators/load)
- [Convert to/from json](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert)
- [Convert to/from xml](https://mikefarah.gitbook.io/yq/v/v4.x/usage/xml)
- [Convert to/from properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties)
- [Convert to csv/tsv](https://mikefarah.gitbook.io/yq/usage/csv-tsv)
- [Convert to/from json to yaml](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert)
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate)
- [General shell completion scripts (bash/zsh/fish/powershell)](https://mikefarah.gitbook.io/yq/v/v4.x/commands/shell-completion)
- [Reduce](https://mikefarah.gitbook.io/yq/operators/reduce) to merge multiple files or sum an array or other fancy things.
- [Github Action](https://mikefarah.gitbook.io/yq/usage/github-action) to use in your automated pipeline (thanks @devorbitus)
@@ -307,46 +245,32 @@ Usage:
yq [flags]
yq [command]
Examples:
# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
yq '.stuff' < myfile.yml # outputs the data at the "stuff" node from "myfile.yml"
yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
Available Commands:
completion Generate the autocompletion script for the specified shell
eval (default) Apply the expression to each document in each yaml file in sequence
eval Apply the expression to each document in each yaml file in sequence
eval-all Loads _all_ yaml documents of _all_ yaml files and runs expression once
help Help about any command
shell-completion Generate completion script
Flags:
-C, --colors force print with colors
-e, --exit-status set exit status if there are no matches or null or false is returned
-f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
--header-preprocess Slurp any header comments and separators before processing expression. (default true)
-h, --help help for yq
-I, --indent int sets indent level for output (default 2)
-i, --inplace update the file inplace of first file given.
-p, --input-format string [yaml|y|xml|x] parse format for input. Note that json is a subset of yaml. (default "yaml")
-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 docs from scratch.
-o, --output-format string [yaml|y|json|j|props|p|xml|x] output format type. (default "yaml")
-P, --prettyPrint pretty print, shorthand for '... style = ""'
-s, --split-exp string print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.
--unwrapScalar unwrap scalar, print the value with no quotes, colors or comments (default true)
-v, --verbose verbose mode
-V, --version Print version information and quit
--xml-attribute-prefix string prefix for xml attributes (default "+")
--xml-content-name string name for xml content (if no attribute name is present). (default "+content")
-C, --colors force print with colors
-e, --exit-status set exit status if there are no matches or null or false is returned
-f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
-h, --help help for yq
-I, --indent int sets indent level for output (default 2)
-i, --inplace update the yaml file inplace of first yaml file given.
-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.
--unwrapScalar unwrap scalar, print the value with no quotes, colors or comments (default true)
-v, --verbose verbose mode
-V, --version Print version information and quit
Use "yq [command] --help" for more information about a command.
```
## 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)
- Powershell has its own...[opinions on quoting yq](https://mikefarah.gitbook.io/yq/usage/tips-and-tricks#quotes-in-windows-powershell)
- Powershell has its own...opinions: https://mikefarah.gitbook.io/yq/usage/tips-and-tricks#quotes-in-windows-powershell
See [tips and tricks](https://mikefarah.gitbook.io/yq/usage/tips-and-tricks) for more common problems and solutions.
See [tips and tricks](https://mikefarah.gitbook.io/yq/usage/tips-and-tricks) for more common problems and solutions.
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
testWriteInPlacePipeIn() {
result=$(./yq e -i -n '.a' 2>&1)
assertEquals 1 $?
assertEquals "Error: write inplace flag only applicable when giving an expression and at least one file" "$result"
}
testWriteInPlacePipeInEvalall() {
result=$(./yq ea -i -n '.a' 2>&1)
assertEquals 1 $?
assertEquals "Error: write inplace flag only applicable when giving an expression and at least one file" "$result"
}
testWriteInPlaceWithSplit() {
result=$(./yq e -s "cat" -i '.a = "thing"' test.yml 2>&1)
assertEquals 1 $?
assertEquals "Error: write inplace cannot be used with split file" "$result"
}
testWriteInPlaceWithSplitEvalAll() {
result=$(./yq ea -s "cat" -i '.a = "thing"' test.yml 2>&1)
assertEquals 1 $?
assertEquals "Error: write inplace cannot be used with split file" "$result"
}
testNullWithFiles() {
result=$(./yq e -n '.a = "thing"' test.yml 2>&1)
assertEquals 1 $?
assertEquals "Error: cannot pass files in when using null-input flag" "$result"
}
testNullWithFilesEvalAll() {
result=$(./yq ea -n '.a = "thing"' test.yml 2>&1)
assertEquals 1 $?
assertEquals "Error: cannot pass files in when using null-input flag" "$result"
}
source ./scripts/shunit2
+2 -286
View File
@@ -1,225 +1,12 @@
#!/bin/bash
setUp() {
rm test*.yml 2>/dev/null || true
rm .xyz 2>/dev/null || true
rm instructions.txt 2>/dev/null || true
rm -f test.yml
}
testBasicEvalRoundTrip() {
./yq -n ".a = 123" > test.yml
X=$(./yq '.a' test.yml)
assertEquals 123 "$X"
}
testBasicTrailingContent() {
cat >test-trailing.yml <<EOL
test:
# this comment will be removed
EOL
read -r -d '' expected << EOM
test:
# this comment will be removed
EOM
X=$(./yq test-trailing.yml -P)
assertEquals "$expected" "$X"
}
testBasicTrailingContent() {
cat >test-trailing.yml <<EOL
test:
# this comment will be removed
EOL
read -r -d '' expected << EOM
test:
# hi
EOM
X=$(./yq '. footComment = "hi"' test-trailing.yml)
assertEquals "$expected" "$X"
}
testBasicTrailingContentEvalAll() {
cat >test-trailing.yml <<EOL
test:
# this comment will be removed
EOL
read -r -d '' expected << EOM
test:
# this comment will be removed
EOM
X=$(./yq ea test-trailing.yml -P)
assertEquals "$expected" "$X"
}
testBasicTrailingContentEvalAll() {
cat >test-trailing.yml <<EOL
test:
# this comment will be removed
EOL
read -r -d '' expected << EOM
test:
# hi
EOM
X=$(./yq ea '. footComment = "hi"' test-trailing.yml)
assertEquals "$expected" "$X"
}
testBasicPipeWithDot() {
./yq -n ".a = 123" > test.yml
X=$(cat test.yml | ./yq '.')
assertEquals "a: 123" "$X"
}
testBasicExpressionMatchesFileName() {
./yq -n ".xyz = 123" > test.yml
touch .xyz
X=$(./yq --expression '.xyz' test.yml)
assertEquals "123" "$X"
X=$(./yq ea --expression '.xyz' test.yml)
assertEquals "123" "$X"
}
testBasicExpressionFromFile() {
./yq -n ".xyz = 123" > test.yml
echo '.xyz = "meow" | .cool = "frog"' > instructions.txt
X=$(./yq --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
X=$(./yq ea --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
}
testBasicGitHubAction() {
./yq -n ".a = 123" > test.yml
X=$(cat /dev/null | ./yq test.yml)
assertEquals "a: 123" "$X"
X=$(cat /dev/null | ./yq e test.yml)
assertEquals "a: 123" "$X"
X=$(cat /dev/null | ./yq ea test.yml)
assertEquals "a: 123" "$X"
}
testBasicGitHubActionWithExpression() {
./yq -n ".a = 123" > test.yml
X=$(cat /dev/null | ./yq '.a' test.yml)
assertEquals "123" "$X"
X=$(cat /dev/null | ./yq e '.a' test.yml)
assertEquals "123" "$X"
X=$(cat /dev/null | ./yq ea '.a' test.yml)
assertEquals "123" "$X"
}
testBasicEvalAllAllFiles() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(./yq ea test.yml test2.yml)
Y=$(./yq e '.' test.yml test2.yml)
assertEquals "$Y" "$X"
}
# when given a file, don't read STDIN
# otherwise strange things start happening
# in scripts
# https://github.com/mikefarah/yq/issues/1115
testBasicCatWithFilesNoDash() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq test2.yml)
Y=$(./yq e '.' test2.yml)
assertEquals "$Y" "$X"
}
# when the nullinput flag is used
# dont automatically read STDIN (this breaks github actions)
testBasicCreateFileGithubAction() {
cat /dev/null | ./yq -n ".a = 123" > test.yml
}
testBasicEvalAllCatWithFilesNoDash() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq ea test2.yml)
Y=$(./yq e '.' test2.yml)
assertEquals "$Y" "$X"
}
testBasicCatWithFilesNoDashWithExp() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq '.a' test2.yml)
Y=$(./yq e '.a' test2.yml)
assertEquals "$Y" "$X"
}
testBasicEvalAllCatWithFilesNoDashWithExp() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq ea '.a' test2.yml)
Y=$(./yq e '.a' test2.yml)
assertEquals "$Y" "$X"
}
testBasicStdInWithFiles() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq - test2.yml)
Y=$(./yq e '.' test.yml test2.yml)
assertEquals "$Y" "$X"
}
testBasicEvalAllStdInWithFiles() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq ea - test2.yml)
Y=$(./yq e '.' test.yml test2.yml)
assertEquals "$Y" "$X"
}
testBasicStdInWithFilesReverse() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq test2.yml -)
Y=$(./yq e '.' test2.yml test.yml)
assertEquals "$Y" "$X"
}
testBasicEvalAllStdInWithFilesReverse() {
./yq -n ".a = 123" > test.yml
./yq -n ".a = 124" > test2.yml
X=$(cat test.yml | ./yq ea test2.yml -)
Y=$(./yq e '.' test2.yml test.yml)
assertEquals "$Y" "$X"
}
testBasicEvalRoundTripNoEval() {
./yq -n ".a = 123" > test.yml
X=$(./yq '.a' test.yml)
assertEquals 123 "$X"
}
testBasicStdInWithOneArg() {
./yq e -n ".a = 123" > test.yml
X=$(cat test.yml | ./yq e ".a")
assertEquals 123 "$X"
X=$(cat test.yml | ./yq ea ".a")
assertEquals 123 "$X"
X=$(cat test.yml | ./yq ".a")
X=$(./yq e '.a' test.yml)
assertEquals 123 "$X"
}
@@ -232,15 +19,6 @@ EOL
assertEquals "10" "$X"
}
testBasicUpdateInPlaceSequenceNoEval() {
cat >test.yml <<EOL
a: 0
EOL
./yq -i ".a = 10" test.yml
X=$(./yq '.a' test.yml)
assertEquals "10" "$X"
}
testBasicUpdateInPlaceSequenceEvalAll() {
cat >test.yml <<EOL
a: 0
@@ -250,40 +28,6 @@ EOL
assertEquals "10" "$X"
}
testBasicUpdateInPlaceMultipleFilesNoExpressionEval() {
cat >test.yml <<EOL
a: 0
EOL
cat >test2.yml <<EOL
a: 1
EOL
read -r -d '' expected << EOM
0
---
1
EOM
./yq -i test.yml test2.yml
X=$(./yq e '.a' test.yml)
assertEquals "$expected" "$X"
}
testBasicUpdateInPlaceMultipleFilesNoExpressionEvalAll() {
cat >test.yml <<EOL
a: 0
EOL
cat >test2.yml <<EOL
a: 1
EOL
read -r -d '' expected << EOM
0
---
1
EOM
./yq -i ea test.yml test2.yml
X=$(./yq e '.a' test.yml)
assertEquals "$expected" "$X"
}
testBasicNoExitStatus() {
echo "a: cat" > test.yml
X=$(./yq e '.z' test.yml)
@@ -296,12 +40,6 @@ testBasicExitStatus() {
assertEquals 1 "$?"
}
testBasicExitStatusNoEval() {
echo "a: cat" > test.yml
X=$(./yq -e '.z' test.yml 2&>/dev/null)
assertEquals 1 "$?"
}
testBasicExtractFieldWithSeperator() {
cat >test.yml <<EOL
---
@@ -331,26 +69,4 @@ EOM
assertEquals "$expected" "$X"
}
testBasicMultiplyAssignMultiDoc() {
cat >test.yml <<EOL
a: 1
---
b: 2
EOL
read -r -d '' expected << EOM
a: 1
c: 3
---
b: 2
c: 3
EOM
X=$(./yq '. *= {"c":3}' test.yml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2
-9
View File
@@ -1,9 +0,0 @@
#!/bin/bash
testCompletionRuns() {
result=$(./yq __complete "" 2>&1)
assertEquals 0 $?
assertContains "$result" "Completion ended with directive:"
}
source ./scripts/shunit2
-1
View File
@@ -1,7 +1,6 @@
#!/bin/bash
setUp() {
rm test*.yml || true
cat >test.yml <<EOL
# comment
EOL
-1
View File
@@ -1,7 +1,6 @@
#!/bin/bash
setUp() {
rm test*.yml || true
cat >test.yml <<EOL
---
a: apple
-168
View File
@@ -1,168 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml 2>/dev/null || true
rm test*.properties 2>/dev/null || true
rm test*.csv 2>/dev/null || true
rm test*.tsv 2>/dev/null || true
rm test*.xml 2>/dev/null || true
}
testInputProperties() {
cat >test.properties <<EOL
mike.things = hello
EOL
read -r -d '' expected << EOM
mike:
things: hello
EOM
X=$(./yq e -p=props test.properties)
assertEquals "$expected" "$X"
X=$(./yq ea -p=props test.properties)
assertEquals "$expected" "$X"
}
testInputPropertiesGitHubAction() {
cat >test.properties <<EOL
mike.things = hello
EOL
read -r -d '' expected << EOM
mike:
things: hello
EOM
X=$(cat /dev/null | ./yq e -p=props test.properties)
assertEquals "$expected" "$X"
X=$(cat /dev/null | ./yq ea -p=props test.properties)
assertEquals "$expected" "$X"
}
testInputCSV() {
cat >test.csv <<EOL
fruit,yumLevel
apple,5
banana,4
EOL
read -r -d '' expected << EOM
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOM
X=$(./yq e -p=csv test.csv)
assertEquals "$expected" "$X"
X=$(./yq ea -p=csv test.csv)
assertEquals "$expected" "$X"
}
testInputTSV() {
cat >test.tsv <<EOL
fruit yumLevel
apple 5
banana 4
EOL
read -r -d '' expected << EOM
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOM
X=$(./yq e -p=t test.tsv)
assertEquals "$expected" "$X"
X=$(./yq ea -p=t test.tsv)
assertEquals "$expected" "$X"
}
testInputXml() {
cat >test.yml <<EOL
<cat legs="4">BiBi</cat>
EOL
read -r -d '' expected << EOM
cat:
+content: BiBi
+legs: "4"
EOM
X=$(./yq e -p=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -p=xml test.yml)
assertEquals "$expected" "$X"
}
testInputXmlNamespaces() {
cat >test.yml <<EOL
<?xml version="1.0"?>
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
</map>
EOL
read -r -d '' expected << EOM
map:
+xmlns: some-namespace
+xmlns:xsi: some-instance
+xsi:schemaLocation: some-url
EOM
X=$(./yq e -p=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -p=xml test.yml)
assertEquals "$expected" "$X"
}
testInputXmlStrict() {
cat >test.yml <<EOL
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY writer "Catherine.">
<!ENTITY copyright "(r) Great">
]>
<root>
<item>&writer;&copyright;</item>
</root>
EOL
X=$(./yq -p=xml --xml-strict-mode test.yml 2>&1)
assertEquals 1 $?
assertEquals "Error: bad file 'test.yml': XML syntax error on line 7: invalid character entity &writer;" "$X"
X=$(./yq ea -p=xml --xml-strict-mode test.yml 2>&1)
assertEquals "Error: bad file 'test.yml': XML syntax error on line 7: invalid character entity &writer;" "$X"
}
testInputXmlGithubAction() {
cat >test.yml <<EOL
<cat legs="4">BiBi</cat>
EOL
read -r -d '' expected << EOM
cat:
+content: BiBi
+legs: "4"
EOM
X=$(cat /dev/null | ./yq e -p=xml test.yml)
assertEquals "$expected" "$X"
X=$(cat /dev/null | ./yq ea -p=xml test.yml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2
-30
View File
@@ -1,7 +1,6 @@
#!/bin/bash
setUp() {
rm test*.yml || true
cat >test.yml <<EOL
---
a: test
@@ -297,35 +296,6 @@ EOM
assertEquals "$expected" "$X"
}
# https://github.com/mikefarah/yq/issues/919
testLeadingSeparatorDoesNotBreakCommentsOnOtherFiles() {
cat >test.yml <<EOL
# a1
a: 1
# a2
EOL
cat >test2.yml <<EOL
# b1
b: 2
# b2
EOL
read -r -d '' expected << EOM
# a1
a: 1
# a2
# b1
b: 2
# b2
EOM
X=$(./yq ea 'select(fi == 0) * select(fi == 1)' test.yml test2.yml)
assertEquals "$expected" "$X"
}
testLeadingSeperatorMultiDocEvalCommentsStripComments() {
cat >test.yml <<EOL
---
-27
View File
@@ -1,27 +0,0 @@
#!/bin/bash
testLoadFileNotExist() {
result=$(./yq e -n 'load("cat.yml")' 2>&1)
assertEquals 1 $?
assertEquals "Error: Failed to load cat.yml: open cat.yml: no such file or directory" "$result"
}
testLoadFileExpNotExist() {
result=$(./yq e -n 'load(.a)' 2>&1)
assertEquals 1 $?
assertEquals "Error: Filename expression returned nil" "$result"
}
testStrLoadFileNotExist() {
result=$(./yq e -n 'strload("cat.yml")' 2>&1)
assertEquals 1 $?
assertEquals "Error: Failed to load cat.yml: open cat.yml: no such file or directory" "$result"
}
testStrLoadFileExpNotExist() {
result=$(./yq e -n 'strload(.a)' 2>&1)
assertEquals 1 $?
assertEquals "Error: Filename expression returned nil" "$result"
}
source ./scripts/shunit2
-208
View File
@@ -1,208 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml || true
}
testOutputJsonDeprecated() {
cat >test.yml <<EOL
a: {b: ["cat"]}
EOL
read -r -d '' expected << EOM
{
"a": {
"b": [
"cat"
]
}
}
EOM
X=$(./yq e -j test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -j test.yml)
assertEquals "$expected" "$X"
}
testOutputJson() {
cat >test.yml <<EOL
a: {b: ["cat"]}
EOL
read -r -d '' expected << EOM
{
"a": {
"b": [
"cat"
]
}
}
EOM
X=$(./yq e --output-format=json test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=json test.yml)
assertEquals "$expected" "$X"
}
testOutputJsonShort() {
cat >test.yml <<EOL
a: {b: ["cat"]}
EOL
read -r -d '' expected << EOM
{
"a": {
"b": [
"cat"
]
}
}
EOM
X=$(./yq e -o=j test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -o=j test.yml)
assertEquals "$expected" "$X"
}
testOutputProperties() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
a.b.c.0 = cat
EOM
X=$(./yq e --output-format=props test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=props test.yml)
assertEquals "$expected" "$X"
}
testOutputPropertiesShort() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
a.b.c.0 = cat
EOM
X=$(./yq e -o=p test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -o=p test.yml)
assertEquals "$expected" "$X"
}
testOutputCSV() {
cat >test.yml <<EOL
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOL
read -r -d '' expected << EOM
fruit,yumLevel
apple,5
banana,4
EOM
X=$(./yq -o=c test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -o=csv test.yml)
assertEquals "$expected" "$X"
}
testOutputTSV() {
cat >test.yml <<EOL
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOL
read -r -d '' expected << EOM
fruit yumLevel
apple 5
banana 4
EOM
X=$(./yq -o=t test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -o=tsv test.yml)
assertEquals "$expected" "$X"
}
testOutputXml() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
<a>
<b>
<c>cat</c>
</b>
</a>
EOM
X=$(./yq e --output-format=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=xml test.yml)
assertEquals "$expected" "$X"
}
testOutputXmlShort() {
cat >test.yml <<EOL
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
<a>
<b>
<c>cat</c>
</b>
</a>
EOM
X=$(./yq e --output-format=x test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=x test.yml)
assertEquals "$expected" "$X"
}
testOutputXmComplex() {
cat >test.yml <<EOL
a: {b: {c: ["cat", "dog"], +f: meow}}
EOL
read -r -d '' expected << EOM
<a>
<b f="meow">
<c>cat</c>
<c>dog</c>
</b>
</a>
EOM
X=$(./yq e --output-format=x test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea --output-format=x test.yml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2
-70
View File
@@ -1,70 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml || true
cat >test.yml <<EOL
a: frog
EOL
}
testPipeViaCatWithParam() {
X=$(cat test.yml | ./yq '.a')
assertEquals "frog" "$X"
}
testPipeViaCatWithParamEval() {
X=$(cat test.yml | ./yq e '.a')
assertEquals "frog" "$X"
}
testPipeViaCatWithParamEvalAll() {
X=$(cat test.yml | ./yq ea '.a')
assertEquals "frog" "$X"
}
testPipeViaCatNoParam() {
X=$(cat test.yml | ./yq)
assertEquals "a: frog" "$X"
}
testPipeViaCatNoParamEval() {
X=$(cat test.yml | ./yq e)
assertEquals "a: frog" "$X"
}
testPipeViaCatNoParamEvalAll() {
X=$(cat test.yml | ./yq ea)
assertEquals "a: frog" "$X"
}
testPipeViaFileishWithParam() {
X=$(./yq '.a' < test.yml)
assertEquals "frog" "$X"
}
testPipeViaFileishWithParamEval() {
X=$(./yq e '.a' < test.yml)
assertEquals "frog" "$X"
}
testPipeViaFileishWithParamEvalAll() {
X=$(./yq ea '.a' < test.yml)
assertEquals "frog" "$X"
}
testPipeViaFileishNoParam() {
X=$(./yq < test.yml)
assertEquals "a: frog" "$X"
}
testPipeViaFileishNoParamEval() {
X=$(./yq e < test.yml)
assertEquals "a: frog" "$X"
}
testPipeViaFileishNoParamEvalAll() {
X=$(./yq ea < test.yml)
assertEquals "a: frog" "$X"
}
source ./scripts/shunit2
-3
View File
@@ -1,8 +1,5 @@
#!/bin/bash
setUp() {
rm test*.yml || true
}
testPrettyPrintWithBooleans() {
cat >test.yml <<EOL
-207
View File
@@ -1,207 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml || true
}
testBasicSplitWithName() {
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
./yq e test.yml -s ".a"
doc1=$(cat test_doc1.yml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_doc2.yml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testBasicSplitWithNameCustomExtension() {
rm test*.yaml || true
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
./yq e test.yml -s '.a + ".yaml"'
doc1=$(cat test_doc1.yaml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_doc2.yaml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testSplitFromFile() {
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
cat >test_splitExp.yml <<EOL
.a
EOL
./yq test.yml --split-exp-file test_splitExp.yml
doc1=$(cat test_doc1.yml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_doc2.yml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testBasicSplitWithNameEvalAll() {
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
./yq ea test.yml -s ".a"
doc1=$(cat test_doc1.yml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_doc2.yml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testBasicSplitWithIndex() {
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
./yq e test.yml -s '"test_" + $index'
doc1=$(cat test_0.yml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_1.yml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testBasicSplitWithIndexEvalAll() {
cat >test.yml <<EOL
a: test_doc1
---
a: test_doc2
EOL
./yq ea test.yml -s '"test_" + $index'
doc1=$(cat test_0.yml)
assertEquals "a: test_doc1" "$doc1"
doc2=$(cat test_1.yml)
read -r -d '' expectedDoc2 << EOM
---
a: test_doc2
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testArraySplitWithNameNoSeparators() {
cat >test.yml <<EOL
- name: test_fred
age: 35
- name: test_catherine
age: 37
EOL
./yq e --no-doc -s ".name" ".[]" test.yml
doc1=$(cat test_fred.yml)
read -r -d '' expectedDoc1 << EOM
name: test_fred
age: 35
EOM
assertEquals "$expectedDoc1" "$doc1"
doc2=$(cat test_catherine.yml)
read -r -d '' expectedDoc2 << EOM
name: test_catherine
age: 37
EOM
assertEquals "$expectedDoc2" "$doc2"
}
testArraySplitWithNameNoSeparatorsEvalAll() {
cat >test.yml <<EOL
- name: test_fred
age: 35
- name: test_catherine
age: 37
EOL
cat >test2.yml <<EOL
- name: test_mike
age: 564
EOL
./yq ea --no-doc -s ".name" ".[]" test.yml test2.yml
doc1=$(cat test_fred.yml)
read -r -d '' expectedDoc1 << EOM
name: test_fred
age: 35
EOM
assertEquals "$expectedDoc1" "$doc1"
doc2=$(cat test_catherine.yml)
read -r -d '' expectedDoc2 << EOM
name: test_catherine
age: 37
EOM
assertEquals "$expectedDoc2" "$doc2"
doc3=$(cat test_mike.yml)
read -r -d '' expectedDoc3 << EOM
name: test_mike
age: 564
EOM
assertEquals "$expectedDoc3" "$doc3"
}
source ./scripts/shunit2
+83
View File
@@ -0,0 +1,83 @@
package cmd
// import (
// "strings"
// "testing"
// "github.com/mikefarah/yq/v3/test"
// "github.com/spf13/cobra"
// )
// func getRootCommand() *cobra.Command {
// return New()
// }
// func TestRootCmd(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !strings.Contains(result.Output, "Usage:") {
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
// }
// }
// func TestRootCmd_Help(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "--help")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !strings.Contains(result.Output, "yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.") {
// t.Error("Expected usage message to be printed out, but the usage message was not found.")
// }
// }
// func TestRootCmd_VerboseLong(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "--verbose")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !verbose {
// t.Error("Expected verbose to be true")
// }
// }
// func TestRootCmd_VerboseShort(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "-v")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !verbose {
// t.Error("Expected verbose to be true")
// }
// }
// func TestRootCmd_VersionShort(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "-V")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !strings.Contains(result.Output, "yq version") {
// t.Error("expected version message to be printed out, but the message was not found.")
// }
// }
// func TestRootCmd_VersionLong(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "--version")
// if result.Error != nil {
// t.Error(result.Error)
// }
// if !strings.Contains(result.Output, "yq version") {
// t.Error("expected version message to be printed out, but the message was not found.")
// }
// }
-14
View File
@@ -6,13 +6,6 @@ var unwrapScalar = true
var writeInplace = false
var outputToJSON = false
var outputFormat = "yaml"
var inputFormat = "yaml"
var xmlAttributePrefix = "+"
var xmlContentName = "+content"
var xmlStrictMode = false
var xmlKeepNamespace = true
var xmlUseRawToken = true
var exitStatus = false
var forceColor = false
@@ -28,11 +21,4 @@ var prettyPrint = false
// can be either "" (off), "extract" or "process"
var frontMatter = ""
var splitFileExp = ""
var splitFileExpFile = ""
var completedSuccessfully = false
var forceExpression = ""
var expressionFile = ""
+47 -32
View File
@@ -2,6 +2,8 @@ package cmd
import (
"errors"
"fmt"
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
@@ -22,8 +24,8 @@ yq ea -i 'select(fi == 0) * select(fi == 1)' f1.yml f2.yml
# Merge all given files
yq ea '. as $item ireduce ({}; . * $item )' file1.yml file2.yml ...
# Pipe from STDIN
## use '-' as a filename to pipe from STDIN
# Read from STDIN
## use '-' as a filename to read from STDIN
cat file2.yml | yq ea '.a.b' file1.yml - file3.yml
`,
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
@@ -38,36 +40,55 @@ Note that it consumes more memory than eval.
}
return cmdEvalAll
}
func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
func evaluateAll(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
// 0 args, read std in
// 1 arg, null input, process expression
// 1 arg, read file in sequence
// 2+ args, [0] = expression, file the rest
var err error
expression, args, err := initCommand(cmd, args)
if err != nil {
return err
}
stat, _ := os.Stdin.Stat()
pipingStdIn := (stat.Mode() & os.ModeCharDevice) == 0
out := cmd.OutOrStdout()
fileInfo, _ := os.Stdout.Stat()
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
firstFileIndex := -1
if !nullInput && len(args) == 1 {
firstFileIndex = 0
} else if len(args) > 1 {
firstFileIndex = 1
}
if writeInplace && (firstFileIndex == -1) {
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
}
if writeInplace {
// only use colors if its forced
colorsEnabled = forceColor
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[0])
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[firstFileIndex])
out, err = writeInPlaceHandler.CreateTempFile()
if err != nil {
return err
}
// need to indirectly call the function so that completedSuccessfully is
// passed when we finish execution as opposed to now
defer func() {
if cmdError == nil {
cmdError = writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully)
}
}()
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
}
if nullInput && len(args) > 1 {
return errors.New("Cannot pass files in when using null-input flag")
}
// backwards compatibilty
if outputToJSON {
outputFormat = "json"
}
format, err := yqlib.OutputFormatFromString(outputFormat)
@@ -75,26 +96,15 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
return err
}
decoder, err := configureDecoder()
if err != nil {
return err
}
printerWriter, err := configurePrinterWriter(format, out)
if err != nil {
return err
}
encoder := configureEncoder(format)
printer := yqlib.NewPrinter(encoder, printerWriter)
printer := yqlib.NewPrinter(out, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
if frontMatter != "" {
frontMatterHandler := yqlib.NewFrontMatterHandler(args[0])
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
err = frontMatterHandler.Split()
if err != nil {
return err
}
args[0] = frontMatterHandler.GetYamlFrontMatterFilename()
args[firstFileIndex] = frontMatterHandler.GetYamlFrontMatterFilename()
if frontMatter == "process" {
reader := frontMatterHandler.GetContentReader()
@@ -105,17 +115,22 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
}
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
switch len(args) {
case 0:
if nullInput {
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(expression), printer, "")
if pipingStdIn {
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing)
} else {
cmd.Println(cmd.UsageString())
return nil
}
case 1:
if nullInput {
err = yqlib.NewStreamEvaluator().EvaluateNew(processExpression(args[0]), printer, "")
} else {
err = allAtOnceEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing)
}
default:
err = allAtOnceEvaluator.EvaluateFiles(processExpression(expression), args, printer, leadingContentPreProcessing, decoder)
err = allAtOnceEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing)
}
completedSuccessfully = err == nil
+50 -34
View File
@@ -3,6 +3,7 @@ package cmd
import (
"errors"
"fmt"
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
@@ -12,7 +13,7 @@ func createEvaluateSequenceCommand() *cobra.Command {
var cmdEvalSequence = &cobra.Command{
Use: "eval [expression] [yaml_file1]...",
Aliases: []string{"e"},
Short: "(default) Apply the expression to each document in each yaml file in sequence",
Short: "Apply the expression to each document in each yaml file in sequence",
Example: `
# Reads field under the given path for each file
yq e '.a.b' f1.yml f2.yml
@@ -20,8 +21,8 @@ yq e '.a.b' f1.yml f2.yml
# Prints out the file
yq e sample.yaml
# Pipe from STDIN
## use '-' as a filename to pipe from STDIN
# Read from STDIN
## use '-' as a filename to read from STDIN
cat file2.yml | yq e '.a.b' file1.yml - file3.yml
# Creates a new yaml document
@@ -43,45 +44,61 @@ expression and prints the result in sequence.`,
}
func processExpression(expression string) string {
var prettyPrintExp = `(... | (select(tag != "!!str"), select(tag == "!!str") | select(test("(?i)^(y|yes|n|no|on|off)$") | not)) ) style=""`
if prettyPrint && expression == "" {
return yqlib.PrettyPrintExp
return prettyPrintExp
} else if prettyPrint {
return fmt.Sprintf("%v | %v", expression, yqlib.PrettyPrintExp)
return fmt.Sprintf("%v | %v", expression, prettyPrintExp)
}
return expression
}
func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
func evaluateSequence(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
// 0 args, read std in
// 1 arg, null input, process expression
// 1 arg, read file in sequence
// 2+ args, [0] = expression, file the rest
var err error
stat, _ := os.Stdin.Stat()
pipingStdIn := (stat.Mode() & os.ModeCharDevice) == 0
out := cmd.OutOrStdout()
var err error
fileInfo, _ := os.Stdout.Stat()
expression, args, err := initCommand(cmd, args)
if err != nil {
return err
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
firstFileIndex := -1
if !nullInput && len(args) == 1 {
firstFileIndex = 0
} else if len(args) > 1 {
firstFileIndex = 1
}
if writeInplace && (firstFileIndex == -1) {
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
}
if writeInplace {
// only use colors if its forced
colorsEnabled = forceColor
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[0])
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[firstFileIndex])
out, err = writeInPlaceHandler.CreateTempFile()
if err != nil {
return err
}
// need to indirectly call the function so that completedSuccessfully is
// passed when we finish execution as opposed to now
defer func() {
if cmdError == nil {
cmdError = writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully)
}
}()
defer func() { writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully) }()
}
// backwards compatibilty
if outputToJSON {
outputFormat = "json"
}
format, err := yqlib.OutputFormatFromString(outputFormat)
@@ -89,28 +106,21 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
return err
}
printerWriter, err := configurePrinterWriter(format, out)
if err != nil {
return err
}
encoder := configureEncoder(format)
printer := yqlib.NewPrinter(out, format, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
printer := yqlib.NewPrinter(encoder, printerWriter)
decoder, err := configureDecoder()
if err != nil {
return err
}
streamEvaluator := yqlib.NewStreamEvaluator()
if nullInput && len(args) > 1 {
return errors.New("Cannot pass files in when using null-input flag")
}
if frontMatter != "" {
yqlib.GetLogger().Debug("using front matter handler")
frontMatterHandler := yqlib.NewFrontMatterHandler(args[0])
frontMatterHandler := yqlib.NewFrontMatterHandler(args[firstFileIndex])
err = frontMatterHandler.Split()
if err != nil {
return err
}
args[0] = frontMatterHandler.GetYamlFrontMatterFilename()
args[firstFileIndex] = frontMatterHandler.GetYamlFrontMatterFilename()
if frontMatter == "process" {
reader := frontMatterHandler.GetContentReader()
@@ -122,14 +132,20 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
switch len(args) {
case 0:
if nullInput {
err = streamEvaluator.EvaluateNew(processExpression(expression), printer, "")
if pipingStdIn {
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{"-"}, printer, leadingContentPreProcessing)
} else {
cmd.Println(cmd.UsageString())
return nil
}
case 1:
if nullInput {
err = streamEvaluator.EvaluateNew(processExpression(args[0]), printer, "")
} else {
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer, leadingContentPreProcessing)
}
default:
err = streamEvaluator.EvaluateFiles(processExpression(expression), args, printer, leadingContentPreProcessing, decoder)
err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer, leadingContentPreProcessing)
}
completedSuccessfully = err == nil
+8 -41
View File
@@ -3,7 +3,6 @@ package cmd
import (
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
logging "gopkg.in/op/go-logging.v1"
)
@@ -14,30 +13,17 @@ func New() *cobra.Command {
Short: "yq is a lightweight and portable command-line YAML processor.",
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
Example: `
# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
# read the "stuff" node from "myfile.yml"
yq '.stuff' < myfile.yml
# update myfile.yml in place
yq -i '.stuff = "foo"' myfile.yml
# print contents of sample.json as idiomatic YAML
yq -P sample.json
`,
RunE: func(cmd *cobra.Command, args []string) error {
if version {
cmd.Print(GetVersionDisplay())
return nil
}
return evaluateSequence(cmd, args)
cmd.Println(cmd.UsageString())
return nil
},
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cmd.SetOut(cmd.OutOrStdout())
var format = logging.MustStringFormatter(
`%{color}%{time:15:04:05} %{shortfunc} [%{level:.4s}]%{color:reset} %{message}`,
)
@@ -51,51 +37,32 @@ yq -P sample.json
}
logging.SetBackend(backend)
yqlib.InitExpressionParser()
yqlib.XMLPreferences.AttributePrefix = xmlAttributePrefix
yqlib.XMLPreferences.ContentName = xmlContentName
yqlib.XMLPreferences.StrictMode = xmlStrictMode
},
}
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose mode")
rootCmd.PersistentFlags().BoolVarP(&outputToJSON, "tojson", "j", false, "(deprecated) output as json. Set indent to 0 to print json in one line.")
err := rootCmd.PersistentFlags().MarkDeprecated("tojson", "please use -o=json instead")
err := rootCmd.PersistentFlags().MarkDeprecated("tojson", "please use -t=json instead")
if err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "yaml", "[yaml|y|json|j|props|p|xml|x] output format type.")
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "yaml", "[yaml|y|props|p|xml|x] parse format for input. Note that json is a subset of yaml.")
rootCmd.PersistentFlags().StringVar(&xmlAttributePrefix, "xml-attribute-prefix", "+", "prefix for xml attributes")
rootCmd.PersistentFlags().StringVar(&xmlContentName, "xml-content-name", "+content", "name for xml content (if no attribute name is present).")
rootCmd.PersistentFlags().BoolVar(&xmlStrictMode, "xml-strict-mode", false, "enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.")
rootCmd.PersistentFlags().BoolVar(&xmlKeepNamespace, "xml-keep-namespace", true, "enables keeping namespace after parsing attributes")
rootCmd.PersistentFlags().BoolVar(&xmlUseRawToken, "xml-raw-token", true, "enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details.")
rootCmd.PersistentFlags().BoolVarP(&nullInput, "null-input", "n", false, "Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.")
rootCmd.PersistentFlags().StringVarP(&outputFormat, "to-type", "t", "yaml", "[yaml|json|props] output format type.")
rootCmd.PersistentFlags().BoolVarP(&nullInput, "null-input", "n", false, "Don't read input, simply evaluate the expression given. Useful for creating yaml docs from scratch.")
rootCmd.PersistentFlags().BoolVarP(&noDocSeparators, "no-doc", "N", false, "Don't print document separators (---)")
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.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the file inplace of first file given.")
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "r", true, "unwrap scalar, print the value with no quotes, colors or comments")
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
rootCmd.PersistentFlags().BoolVarP(&unwrapScalar, "unwrapScalar", "", true, "unwrap scalar, print the value with no quotes, colors or comments")
rootCmd.PersistentFlags().BoolVarP(&prettyPrint, "prettyPrint", "P", false, "pretty print, shorthand for '... style = \"\"'")
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
rootCmd.PersistentFlags().StringVarP(&frontMatter, "front-matter", "f", "", "(extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact")
rootCmd.PersistentFlags().StringVarP(&forceExpression, "expression", "", "", "forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.")
rootCmd.PersistentFlags().BoolVarP(&leadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and separators before processing expression.")
rootCmd.PersistentFlags().StringVarP(&splitFileExp, "split-exp", "s", "", "print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.")
rootCmd.PersistentFlags().StringVarP(&splitFileExpFile, "split-exp-file", "", "", "Use a file to specify the split-exp expression.")
rootCmd.PersistentFlags().StringVarP(&expressionFile, "from-file", "", "", "Load expression from specified file.")
rootCmd.PersistentFlags().BoolVarP(&leadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and seperators before processing expression. This is a workaround for go-yaml to persist header content. This flag will be removed once this feature has been out in the wild for a while.")
rootCmd.AddCommand(
createEvaluateSequenceCommand(),
createEvaluateAllCommand(),
-177
View File
@@ -1,177 +0,0 @@
package cmd
import (
"fmt"
"io"
"os"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
"gopkg.in/op/go-logging.v1"
)
func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
cmd.SilenceUsage = true
fileInfo, _ := os.Stdout.Stat()
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
expression, args, err := processArgs(args)
if err != nil {
return "", nil, err
}
if splitFileExpFile != "" {
splitExpressionBytes, err := os.ReadFile(splitFileExpFile)
if err != nil {
return "", nil, err
}
splitFileExp = string(splitExpressionBytes)
}
// backwards compatibility
if outputToJSON {
outputFormat = "json"
}
if writeInplace && (len(args) == 0 || args[0] == "-") {
return "", nil, fmt.Errorf("write inplace flag only applicable when giving an expression and at least one file")
}
if frontMatter != "" && len(args) == 0 {
return "", nil, fmt.Errorf("front matter flag only applicable when giving an expression and at least one file")
}
if writeInplace && splitFileExp != "" {
return "", nil, fmt.Errorf("write inplace cannot be used with split file")
}
if nullInput && len(args) > 0 {
return "", nil, fmt.Errorf("cannot pass files in when using null-input flag")
}
return expression, args, nil
}
func configureDecoder() (yqlib.Decoder, error) {
yqlibInputFormat, err := yqlib.InputFormatFromString(inputFormat)
if err != nil {
return nil, err
}
switch yqlibInputFormat {
case yqlib.XMLInputFormat:
return yqlib.NewXMLDecoder(xmlAttributePrefix, xmlContentName, xmlStrictMode, xmlKeepNamespace, xmlUseRawToken), nil
case yqlib.PropertiesInputFormat:
return yqlib.NewPropertiesDecoder(), nil
case yqlib.JsonInputFormat:
return yqlib.NewJSONDecoder(), nil
case yqlib.CSVObjectInputFormat:
return yqlib.NewCSVObjectDecoder(','), nil
case yqlib.TSVObjectInputFormat:
return yqlib.NewCSVObjectDecoder('\t'), nil
}
return yqlib.NewYamlDecoder(), nil
}
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) {
var printerWriter yqlib.PrinterWriter
if splitFileExp != "" {
colorsEnabled = forceColor
splitExp, err := yqlib.ExpressionParser.ParseExpression(splitFileExp)
if err != nil {
return nil, fmt.Errorf("bad split document expression: %w", err)
}
printerWriter = yqlib.NewMultiPrinterWriter(splitExp, format)
} else {
printerWriter = yqlib.NewSinglePrinterWriter(out)
}
return printerWriter, nil
}
func configureEncoder(format yqlib.PrinterOutputFormat) yqlib.Encoder {
switch format {
case yqlib.JSONOutputFormat:
return yqlib.NewJSONEncoder(indent, colorsEnabled)
case yqlib.PropsOutputFormat:
return yqlib.NewPropertiesEncoder(unwrapScalar)
case yqlib.CSVOutputFormat:
return yqlib.NewCsvEncoder(',')
case yqlib.TSVOutputFormat:
return yqlib.NewCsvEncoder('\t')
case yqlib.YamlOutputFormat:
return yqlib.NewYamlEncoder(indent, colorsEnabled, !noDocSeparators, unwrapScalar)
case yqlib.XMLOutputFormat:
return yqlib.NewXMLEncoder(indent, xmlAttributePrefix, xmlContentName)
}
panic("invalid encoder")
}
// this is a hack to enable backwards compatibility with githubactions (which pipe /dev/null into everything)
// and being able to call yq with the filename as a single parameter
//
// without this - yq detects there is stdin (thanks githubactions),
// then tries to parse the filename as an expression
func maybeFile(str string) bool {
yqlib.GetLogger().Debugf("checking '%v' is a file", str)
stat, err := os.Stat(str) // #nosec
result := err == nil && !stat.IsDir()
if yqlib.GetLogger().IsEnabledFor(logging.DEBUG) {
if err != nil {
yqlib.GetLogger().Debugf("error: %v", err)
} else {
yqlib.GetLogger().Debugf("error: %v, dir: %v", err, stat.IsDir())
}
yqlib.GetLogger().Debugf("result: %v", result)
}
return result
}
func processStdInArgs(args []string) []string {
stat, _ := os.Stdin.Stat()
pipingStdin := (stat.Mode() & os.ModeCharDevice) == 0
// if we've been given a file, don't automatically
// read from stdin.
// this happens if there is more than one argument
// or only one argument and its a file
if nullInput || !pipingStdin || len(args) > 1 || (len(args) > 0 && maybeFile(args[0])) {
return args
}
for _, arg := range args {
if arg == "-" {
return args
}
}
yqlib.GetLogger().Debugf("missing '-', adding it to the end")
// we're piping from stdin, but there's no '-' arg
// lets add one to the end
return append(args, "-")
}
func processArgs(originalArgs []string) (string, []string, error) {
expression := forceExpression
if expressionFile != "" {
expressionBytes, err := os.ReadFile(expressionFile)
if err != nil {
return "", nil, err
}
expression = string(expressionBytes)
}
args := processStdInArgs(originalArgs)
yqlib.GetLogger().Debugf("processed args: %v", args)
if expression == "" && len(args) > 0 && args[0] != "-" && !maybeFile(args[0]) {
yqlib.GetLogger().Debug("assuming expression is '%v'", args[0])
expression = args[0]
args = args[1:]
}
return expression, args, nil
}
+1 -1
View File
@@ -11,7 +11,7 @@ var (
GitDescribe string
// Version is main version number that is being run at the moment.
Version = "4.26.1"
Version = "4.11.2"
// 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
-125
View File
@@ -1,128 +1,3 @@
yq (4.16.2) focal; urgency=medium
* Fixed with semicolon space issue
* Updating with documentation
* Added STDIN example to the top
* minor readme cleanup
* Help text tweak
* Fixed docker timeout - simplify docker builds
* New release with docker build fixes
* Updating to go 1.17 to fix CVE #944
* Fix a typo in root.go
* Skip the tests if the nocheck Debian build option is specified
* Fixed select bug (#958)
* Sped up explode operator
* Slight performance improvement to context.ChildContext
* Speed up multiply
* Update README with recently added / changed options
* Make deepMatch report in linear time
* Removed leadingContentPreProcessing flag - header preprocessing is stable
* Revert "Removed leadingContentPreProcessing flag - header preprocessing is stable"
* Keep flag, it is needed in corner cases
* Updated Readme
* Man page
* Fixed expression parsing bug #970
* Bumping go-lang, docker versions
* Added test release flow
* Updated github action release to generate man page
* Bumping version
* Removing no longer needed github action
* Added decoder op
* Fixed newline handling when decoding/encoding
* Fixed newline handling in encoder/decoder
* Can specify indent in encode ops
* Added group_by operator
* Added flatten operator
* Fixed flatten error message
* Improving docs
* Split printer
* Refactored command logic
* Fix JSON encoding removing null #985
* Fixed acceptance tests
* gitbook
* Update document generation script
* Updating README
* Updating release instructions
* github action no longer uses data1.yml
* Create dependabot.yml
* Bump actions/create-release from 1.0.0 to 1.1.4
* Bump actions/setup-go from 1 to 2.1.4
* Bump github.com/goccy/go-yaml from 1.8.9 to 1.9.4
* Bump github.com/jinzhu/copier from 0.2.8 to 0.3.2
* Bump github.com/fatih/color from 1.10.0 to 1.13.0
* Bump github.com/spf13/cobra from 1.1.3 to 1.2.1
* Update dependabot.yml
* Update go.yml
* add build check to PRs
* Include secure as part of build process
* Fixing bad label in github action
* fixed printer test
* remove leading content indicator
* Fixed header preprocessing!
* lint : define golangci configuration file
* Update check.sh
* Load file acceptance test
* Minor improvement on handling front matter
* Improved load doc
* feature: detect MANPATh and install there
* Update install-man-page.sh
* simplify prod stage, move version label to action
* add labels, quote some values
* enable errorlint linter
* Added errorlint to devtools
* Added key operator
* Added more tests
* Fixing comments
* Attempt to fix golint problem
* Include version query for tools
* Clean up errored file?
* enable misspell linter
* updated readme
* update Golangci version to v1.43.0
* gci linter
* Better merge array by key example
* Added credit for merge by array example
* Better formatting of merge arrays example
* Better merge example
* Add accessor for the yq logger instance (#1013)
* Fixed collect op when working with multiple nodes
* Added map, map_values
* Add support for Podman as well as Docker (#1026)
* Bump github.com/jinzhu/copier from 0.3.2 to 0.3.4 (#1027)
* Added csv, tsv output formats
* Added encoder tests
* Cleanup test
* Fixed docker permission issue #1014
* Recording release notes for next release
* Assignment op no longer clobbers anchor (#1029)
* Added sort_by operator
* Improved error message
* Improved tips and tricks
* Report while filename failed to parse #1030
* Added script for extracting checksums
* Improved extract-checksum.sh
* Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#1039)
* enable more linters (#1043)
* Bump golang compiler #1037
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 21 Dec 2021 09:41:44 +0000
yq (4.13.0) focal; urgency=medium
* New `with` operator for making multiple changes to a given path
* New `contains` operator, works like the `jq` equivalent
* Subtract operator now supports subtracting elements from arrays!
* Fixed Swapping values using variables #934
* Github Action now properly supports multiline output #936, thanks @pjxiao
* Fixed missing closing bracket validation #932
* Fix processing of hex numbers #929
* Fixed alternative and union operator issues #930
* Can now convert yaml to properties properties format (`-o=props`), See [docs](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties) for more info.
* Fixed document header/footer comment handling when merging (https://github.com/mikefarah/yq/issues/919)
* pretty print yaml 1.1 compatibility (https://github.com/mikefarah/yq/issues/914)
-- Roberto Mier Escandon <rmescandon@gmail.com> Thu, 16 Sep 2021 20:58:30 +0200
yq (4.9.6) focal; urgency=medium
* Added darwin/arm64 build, thanks @alecthomas
+1 -2
View File
@@ -3,8 +3,7 @@ Section: devel
Priority: optional
Maintainer: Roberto Mier Escandón <rmescandon@gmail.com>
Build-Depends: debhelper (>=10),
golang-1.17-go,
pandoc,
golang-1.15,
rsync
Standards-Version: 4.1.4
Homepage: https://github.com/mikefarah/yq.git
+4 -21
View File
@@ -1,6 +1,6 @@
#!/usr/bin/make -f
#
# Copyright (C) 2018-2021 Roberto Mier Escandón <rmescandon@gmail.com>
# Copyright (C) 2018 Roberto Mier Escandón <rmescandon@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
@@ -17,21 +17,20 @@
PROJECT := yq
OWNER := mikefarah
REPO := github.com
GOVERSION := 1.15
export DH_OPTIONS
export DH_GOPKG := ${REPO}/${OWNER}/${PROJECT}
export GOROOT := /usr/local/go
export GOROOT := /usr/lib/go-${GOVERSION}
export GOPATH := ${CURDIR}/_build
export GOBIN := ${GOPATH}/bin
export PATH := ${GOROOT}/bin:${GOBIN}:${PATH}
export GOCACHE := /tmp/gocache
export GOFLAGS := -mod=vendor
export GO111MODULE := on
SRCDIR := ${GOPATH}/src/${DH_GOPKG}
DESTDIR := ${CURDIR}/debian/${PROJECT}
BINDIR := /usr/bin
MANDIR := /usr/share/man/man1/
ASSETSDIR := /usr/share/${PROJECT}
%:
@@ -43,32 +42,16 @@ override_dh_auto_build:
# copy project to local srcdir to build from there
rsync -avz --progress --exclude=_build --exclude=debian --exclude=tmp. --exclude=go.mod --exclude=docs . $(SRCDIR)
# build go code
( \
cd ${SRCDIR} && \
go install -buildmode=pie ./... \
)
# build man page
( \
cd ${SRCDIR} && \
./scripts/generate-man-page-md.sh && \
./scripts/generate-man-page.sh \
)
(cd ${SRCDIR} && go install -buildmode=pie ./...)
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
(cd ${SRCDIR} && go test -v ./...)
endif
override_dh_auto_install:
cp ${GOBIN}/yq ${DESTDIR}/${BINDIR}
cp -f ${SRCDIR}/LICENSE ${DESTDIR}/${ASSETSDIR}
chmod a+x ${DESTDIR}/${BINDIR}/yq
# man
mkdir -p "${DESTDIR}"/"${MANDIR}"
cp "${SRCDIR}"/yq.1 "${DESTDIR}"/"${MANDIR}" \
override_dh_auto_clean:
dh_clean
rm -rf ${CURDIR}/_build
-1
View File
@@ -1 +0,0 @@
bXkgc2VjcmV0IGNoaWxsaSByZWNpcGUgaXMuLi4u
+2 -12
View File
@@ -1,12 +1,2 @@
# --------------------------------------------------
# It's a test with comment
# --------------------------------------------------
test:
- name: a
- name: b
- name: c
groups:
- name: a
- name: b
- name: c
- name: c
- ["oy", "yo", "ohno", "nom", "y", "Y", "n", "yes", "no", "on", "off", "true", "false", "apples"]
- [y, n, yes, no, on, off, true, false]
+7 -5
View File
@@ -1,5 +1,7 @@
# --------------------------------------------------
# It's a test with comment
# --------------------------------------------------
groups:
- name: d
a: other # better than the original
b: [3, 4]
c:
toast: leave
test: 1
tell: 1
tasty.taco: cool
-6
View File
@@ -1,6 +0,0 @@
# comments on values appear
person.name = Mike
# comments on array values appear
person.pets.0 = cat
person.food.0 = pizza
-14
View File
@@ -1,14 +0,0 @@
<!-- before cat -->
<cat>
<!-- in cat before -->
<x>3<!-- multi
line comment
for x --></x>
<y>
<!-- in y before -->
<d><!-- in d before -->4<!-- in d after --></d>
<!-- in y after -->
</y>
<!-- in_cat_after -->
</cat>
<!-- after cat -->
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- osm-->
<osm version="0.6" generator="CGImap 0.0.2">
<!-- bounds-->
<bounds minlat="54.0889580" minlon="12.2487570" maxlat="54.0913900" maxlon="12.2524800">
<!-- great -->
cool
</bounds>
<foo>ba2234r</foo>
<foo>bar2234233</foo>
</osm>
-3
View File
@@ -1,3 +0,0 @@
name,numberOfCats,likesApples,height
Gary,1,true,168.8
Samantha's Rabbit,2,false,-188.8
1 name numberOfCats likesApples height
2 Gary 1 true 168.8
3 Samantha's Rabbit 2 false -188.8
-1
View File
@@ -1 +0,0 @@
this.is = a properties file
-1
View File
@@ -1 +0,0 @@
<this>is some xml</this>
-2
View File
@@ -1,2 +0,0 @@
a: apple is included
b: cool.
+1 -1
View File
@@ -1,4 +1,4 @@
FROM mikefarah/yq:4
FROM mikefarah/yq:4.11.2
COPY entrypoint.sh /entrypoint.sh
-3
View File
@@ -2,8 +2,5 @@
set -e
echo "::debug::\$cmd: $1"
RESULT=$(eval "$1")
RESULT="${RESULT//'%'/'%25'}"
RESULT="${RESULT//$'\n'/'%0A'}"
RESULT="${RESULT//$'\r'/'%0D'}"
echo "::debug::\$RESULT: $RESULT"
echo ::set-output name=result::"$RESULT"
+10 -23
View File
@@ -1,30 +1,17 @@
module github.com/mikefarah/yq/v4
require (
github.com/a8m/envsubst v1.3.0
github.com/alecthomas/participle/v2 v2.0.0-beta.4
github.com/alecthomas/repr v0.1.0
github.com/elliotchance/orderedmap v1.4.0
github.com/fatih/color v1.13.0
github.com/goccy/go-json v0.9.10
github.com/goccy/go-yaml v1.9.5
github.com/jinzhu/copier v0.3.5
github.com/magiconair/properties v1.8.6
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/spf13/cobra v1.5.0
golang.org/x/net v0.0.0-20220708220712-1185a9018129
github.com/fatih/color v1.10.0
github.com/goccy/go-yaml v1.8.9
github.com/jinzhu/copier v0.2.8
github.com/magiconair/properties v1.8.5
github.com/spf13/cobra v1.1.3
github.com/timtadh/data-structures v0.5.3 // indirect
github.com/timtadh/lexmachine v0.2.2
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
gopkg.in/yaml.v3 v3.0.1
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
)
go 1.18
go 1.15
+292 -43
View File
@@ -1,81 +1,330 @@
github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg=
github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg=
github.com/alecthomas/participle/v2 v2.0.0-beta.4 h1:ublfGBm+x+p2j7KotHhrUMbKtejT7M0Gv1Mt1u3absw=
github.com/alecthomas/participle/v2 v2.0.0-beta.4/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/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 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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
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/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A=
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-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-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/goccy/go-json v0.9.10 h1:hCeNmprSNLB8B8vQKWl6DpuH0t60oEs+TAk9a7CScKc=
github.com/goccy/go-json v0.9.10/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.9.5 h1:Eh/+3uk9kLxG4koCX6lRMAPS1OaMSAi+FJcya0INdB0=
github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-yaml v1.8.9 h1:4AEXg2qx+/w29jXnXpMY6mTckmYu1TMoHteKuMf0HFg=
github.com/goccy/go-yaml v1.8.9/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/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.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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
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-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/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/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/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/jinzhu/copier v0.2.8 h1:N8MbL5niMwE3P4dOwurJixz5rMkKfujmMRFmAanSzWE=
github.com/jinzhu/copier v0.2.8/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
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/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
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/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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
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.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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-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/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/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/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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
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.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/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/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/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/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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
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/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
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.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU=
github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4PHmY=
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/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-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-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-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-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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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-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-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-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-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-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-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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
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/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-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/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-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-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
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.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-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.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/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
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/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-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=
+13 -14
View File
@@ -8,7 +8,7 @@ import (
// A yaml expression evaluator that runs the expression once against all files/nodes in memory.
type Evaluator interface {
EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool, decoder Decoder) error
EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error
// EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes
EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error)
@@ -19,11 +19,11 @@ type Evaluator interface {
type allAtOnceEvaluator struct {
treeNavigator DataTreeNavigator
treeCreator ExpressionParser
}
func NewAllAtOnceEvaluator() Evaluator {
InitExpressionParser()
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator()}
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator(), treeCreator: NewExpressionParser()}
}
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
@@ -35,7 +35,7 @@ func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Nod
}
func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCandidates *list.List) (*list.List, error) {
node, err := ExpressionParser.ParseExpression(expression)
node, err := e.treeCreator.ParseExpression(expression)
if err != nil {
return nil, err
}
@@ -46,13 +46,13 @@ func (e *allAtOnceEvaluator) EvaluateCandidateNodes(expression string, inputCand
return context.MatchingNodes, nil
}
func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool, decoder Decoder) error {
func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string, printer Printer, leadingContentPreProcessing bool) error {
fileIndex := 0
firstFileLeadingContent := ""
var allDocuments = list.New()
var allDocuments *list.List = list.New()
for _, filename := range filenames {
reader, leadingContent, err := readStream(filename, fileIndex == 0 && leadingContentPreProcessing)
reader, leadingContent, err := readStream(filename, leadingContentPreProcessing)
if err != nil {
return err
}
@@ -61,7 +61,7 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string
firstFileLeadingContent = leadingContent
}
fileDocuments, err := readDocuments(reader, filename, fileIndex, decoder)
fileDocuments, err := readDocuments(reader, filename, fileIndex)
if err != nil {
return err
}
@@ -71,15 +71,14 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string
if allDocuments.Len() == 0 {
candidateNode := &CandidateNode{
Document: 0,
Filename: "",
Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}},
FileIndex: 0,
LeadingContent: firstFileLeadingContent,
Document: 0,
Filename: "",
Node: &yaml.Node{Kind: yaml.DocumentNode, HeadComment: firstFileLeadingContent, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}},
FileIndex: 0,
}
allDocuments.PushBack(candidateNode)
} else {
allDocuments.Front().Value.(*CandidateNode).LeadingContent = firstFileLeadingContent
allDocuments.Front().Value.(*CandidateNode).Node.HeadComment = firstFileLeadingContent
}
matches, err := e.EvaluateCandidateNodes(expression, allDocuments)
+1 -1
View File
@@ -35,6 +35,6 @@ func TestAllAtOnceEvaluateNodes(t *testing.T) {
for _, tt := range evaluateNodesScenario {
node := test.ParseData(tt.document)
list, _ := evaluator.EvaluateNodes(tt.expression, &node)
test.AssertResultComplex(t, tt.expected, resultsToString(t, list))
test.AssertResultComplex(t, tt.expected, resultsToString(list))
}
}
+13 -101
View File
@@ -1,28 +1,21 @@
package yqlib
import (
"container/list"
"fmt"
"strings"
"github.com/jinzhu/copier"
yaml "gopkg.in/yaml.v3"
)
type CandidateNode struct {
Node *yaml.Node // the actual node
Parent *CandidateNode // parent node
Key *yaml.Node // node key, if this is a value from a map (or index in an array)
LeadingContent string
TrailingContent string
Path []interface{} /// the path we took to get to this node
Document uint // the document index of this node
Node *yaml.Node // the actual node
Parent *CandidateNode // parent node
Path []interface{} /// the path we took to get to this node
Document uint // the document index of this node
Filename string
FileIndex int
// when performing op against all nodes given, this will treat all the nodes as one
// (e.g. top level cross document merge). This property does not propagate to child nodes.
// (e.g. top level cross document merge). This property does not propegate to child nodes.
EvaluateTogether bool
IsMapKey bool
}
@@ -35,75 +28,17 @@ func (n *CandidateNode) GetKey() string {
return fmt.Sprintf("%v%v - %v", keyPrefix, n.Document, n.Path)
}
func (n *CandidateNode) GetNiceTag() string {
return unwrapDoc(n.Node).Tag
}
func (n *CandidateNode) GetNicePath() string {
if n.Path != nil && len(n.Path) >= 0 {
pathStr := make([]string, len(n.Path))
for i, v := range n.Path {
pathStr[i] = fmt.Sprintf("%v", v)
}
return strings.Join(pathStr, ".")
}
return ""
}
func (n *CandidateNode) AsList() *list.List {
elMap := list.New()
elMap.PushBack(n)
return elMap
}
func (n *CandidateNode) CreateChildInMap(key *yaml.Node, node *yaml.Node) *CandidateNode {
var value interface{}
if key != nil {
value = key.Value
}
func (n *CandidateNode) CreateChild(path interface{}, node *yaml.Node) *CandidateNode {
return &CandidateNode{
Node: node,
Path: n.createChildPath(value),
Path: n.createChildPath(path),
Parent: n,
Key: key,
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
}
}
func (n *CandidateNode) CreateChildInArray(index int, node *yaml.Node) *CandidateNode {
return &CandidateNode{
Node: node,
Path: n.createChildPath(index),
Parent: n,
Key: &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", index), Tag: "!!int"},
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
}
}
func (n *CandidateNode) CreateReplacement(node *yaml.Node) *CandidateNode {
return &CandidateNode{
Node: node,
Path: n.createChildPath(nil),
Parent: n.Parent,
Key: n.Key,
IsMapKey: n.IsMapKey,
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
}
}
func (n *CandidateNode) CreateReplacementWithDocWrappers(node *yaml.Node) *CandidateNode {
replacement := n.CreateReplacement(node)
replacement.LeadingContent = n.LeadingContent
replacement.TrailingContent = n.TrailingContent
return replacement
}
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
if path == nil {
newPath := make([]interface{}, len(n.Path))
@@ -124,29 +59,18 @@ func (n *CandidateNode) Copy() (*CandidateNode, error) {
if err != nil {
return nil, err
}
clone.Node = deepClone(n.Node)
return clone, nil
}
// updates this candidate from the given candidate node
func (n *CandidateNode) UpdateFrom(other *CandidateNode, prefs assignPreferences) {
func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
// if this is an empty map or empty array, use the style of other node.
if (n.Node.Kind != yaml.ScalarNode && len(n.Node.Content) == 0) ||
// if the tag has changed (e.g. from str to bool)
(guessTagFromCustomType(n.Node) != guessTagFromCustomType(other.Node)) {
n.Node.Style = other.Node.Style
}
n.Node.Content = deepCloneContent(other.Node.Content)
n.Node.Kind = other.Node.Kind
n.UpdateAttributesFrom(other)
n.Node.Content = other.Node.Content
n.Node.Value = other.Node.Value
n.UpdateAttributesFrom(other, prefs)
}
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignPreferences) {
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
log.Debug("UpdateAttributesFrom: n: %v other: %v", n.GetKey(), other.GetKey())
if n.Node.Kind != other.Node.Kind {
// clear out the contents when switching to a different type
@@ -155,21 +79,12 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
n.Node.Value = ""
}
n.Node.Kind = other.Node.Kind
// don't clobber custom tags...
if strings.HasPrefix(n.Node.Tag, "!!") || n.Node.Tag == "" {
n.Node.Tag = other.Node.Tag
}
n.Node.Tag = other.Node.Tag
n.Node.Alias = other.Node.Alias
if !prefs.DontOverWriteAnchor {
n.Node.Anchor = other.Node.Anchor
}
n.Node.Anchor = other.Node.Anchor
// merge will pickup the style of the new thing
// when autocreating nodes
if n.Node.Style == 0 {
n.Node.Style = other.Node.Style
}
@@ -177,9 +92,6 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignP
if other.Node.FootComment != "" {
n.Node.FootComment = other.Node.FootComment
}
if other.TrailingContent != "" {
n.TrailingContent = other.TrailingContent
}
if other.Node.HeadComment != "" {
n.Node.HeadComment = other.Node.HeadComment
}
-133
View File
@@ -1,133 +0,0 @@
package yqlib
import (
"fmt"
"strconv"
"time"
yaml "gopkg.in/yaml.v3"
)
type compareTypePref struct {
OrEqual bool
Greater bool
}
func compareOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- compareOperator")
prefs := expressionNode.Operation.Preferences.(compareTypePref)
return crossFunction(d, context.ReadOnlyClone(), expressionNode, compare(prefs), true)
}
func compare(prefs compareTypePref) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
log.Debugf("-- compare cross function")
if lhs == nil && rhs == nil {
owner := &CandidateNode{}
return createBooleanCandidate(owner, prefs.OrEqual), nil
} else if lhs == nil {
log.Debugf("lhs nil, but rhs is not")
return createBooleanCandidate(rhs, false), nil
} else if rhs == nil {
log.Debugf("rhs nil, but rhs is not")
return createBooleanCandidate(lhs, false), nil
}
lhs.Node = unwrapDoc(lhs.Node)
rhs.Node = unwrapDoc(rhs.Node)
switch lhs.Node.Kind {
case yaml.MappingNode:
return nil, fmt.Errorf("maps not yet supported for comparison")
case yaml.SequenceNode:
return nil, fmt.Errorf("arrays not yet supported for comparison")
default:
if rhs.Node.Kind != yaml.ScalarNode {
return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Node.Tag, rhs.Path, lhs.Node.Tag)
}
target := lhs.CreateReplacement(&yaml.Node{})
boolV, err := compareScalars(context, prefs, lhs.Node, rhs.Node)
return createBooleanCandidate(target, boolV), err
}
}
}
func compareDateTime(layout string, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) {
lhsTime, err := time.Parse(layout, lhs.Value)
if err != nil {
return false, err
}
rhsTime, err := time.Parse(layout, rhs.Value)
if err != nil {
return false, err
}
if prefs.OrEqual && lhsTime.Equal(rhsTime) {
return true, nil
}
if prefs.Greater {
return lhsTime.After(rhsTime), nil
}
return lhsTime.Before(rhsTime), nil
}
func compareScalars(context Context, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) {
lhsTag := guessTagFromCustomType(lhs)
rhsTag := guessTagFromCustomType(rhs)
isDateTime := lhs.Tag == "!!timestamp"
// if the lhs is a string, it might be a timestamp in a custom format.
if lhsTag == "!!str" && context.GetDateTimeLayout() != time.RFC3339 {
_, err := time.Parse(context.GetDateTimeLayout(), lhs.Value)
isDateTime = err == nil
}
if isDateTime {
return compareDateTime(context.GetDateTimeLayout(), prefs, lhs, rhs)
} else if lhsTag == "!!int" && rhsTag == "!!int" {
_, lhsNum, err := parseInt64(lhs.Value)
if err != nil {
return false, err
}
_, rhsNum, err := parseInt64(rhs.Value)
if err != nil {
return false, err
}
if prefs.OrEqual && lhsNum == rhsNum {
return true, nil
}
if prefs.Greater {
return lhsNum > rhsNum, nil
}
return lhsNum < rhsNum, nil
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
if err != nil {
return false, err
}
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)
if err != nil {
return false, err
}
if prefs.OrEqual && lhsNum == rhsNum {
return true, nil
}
if prefs.Greater {
return lhsNum > rhsNum, nil
}
return lhsNum < rhsNum, nil
} else if lhsTag == "!!str" && rhsTag == "!!str" {
if prefs.OrEqual && lhs.Value == rhs.Value {
return true, nil
}
if prefs.Greater {
return lhs.Value > rhs.Value, nil
}
return lhs.Value < rhs.Value, nil
}
return false, fmt.Errorf("%v not yet supported for comparison", lhs.Tag)
}
-371
View File
@@ -1,371 +0,0 @@
package yqlib
import (
"testing"
)
var compareOperatorScenarios = []expressionScenario{
// ints, not equal
{
description: "Compare numbers (>)",
document: "a: 5\nb: 4",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5\nb: 4",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
description: "Compare integers (>=)",
document: "a: 5\nb: 4",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5\nb: 4",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
// ints, equal
{
skipDoc: true,
description: "Compare equal numbers (>)",
document: "a: 5\nb: 5",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 5\nb: 5",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
description: "Compare equal numbers (>=)",
document: "a: 5\nb: 5",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5\nb: 5",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
// floats, not equal
{
skipDoc: true,
document: "a: 5.2\nb: 4.1",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5.2\nb: 4.1",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 5.2\nb: 4.1",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5.5\nb: 4.1",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
// floats, equal
{
skipDoc: true,
document: "a: 5.5\nb: 5.5",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 5.5\nb: 5.5",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 5.1\nb: 5.1",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5.1\nb: 5.1",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
// strings, not equal
{
description: "Compare strings",
subdescription: "Compares strings by their bytecode.",
document: "a: zoo\nb: apple",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: zoo\nb: apple",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: zoo\nb: apple",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: zoo\nb: apple",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
// strings, equal
{
skipDoc: true,
document: "a: cat\nb: cat",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: cat\nb: cat",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: cat\nb: cat",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: cat\nb: cat",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
// datetime, not equal
{
description: "Compare date times",
subdescription: "You can compare date times. Assumes RFC3339 date time format, see [date-time operators](https://mikefarah.gitbook.io/yq/operators/date-time-operators) for more information.",
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2020-01-01T03:10:00Z",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
// datetime, equal
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 2021-01-01T03:10:00Z\nb: 2021-01-01T03:10:00Z",
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
},
},
// both null
{
description: "Both sides are null: > is false",
expression: ".a > .b",
expected: []string{
"D0, P[], (!!bool)::false\n",
},
},
{
skipDoc: true,
expression: ".a < .b",
expected: []string{
"D0, P[], (!!bool)::false\n",
},
},
{
description: "Both sides are null: >= is true",
expression: ".a >= .b",
expected: []string{
"D0, P[], (!!bool)::true\n",
},
},
{
skipDoc: true,
expression: ".a <= .b",
expected: []string{
"D0, P[], (!!bool)::true\n",
},
},
// one null
{
skipDoc: true,
description: "One side is null: > is false",
document: `a: 5`,
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: `a: 5`,
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
description: "One side is null: >= is false",
document: `a: 5`,
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: `a: 5`,
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: `a: 5`,
expression: ".b <= .a",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
{
skipDoc: true,
document: `a: 5`,
expression: ".b < .a",
expected: []string{
"D0, P[a], (!!bool)::false\n",
},
},
}
func TestCompareOperatorScenarios(t *testing.T) {
for _, tt := range compareOperatorScenarios {
testScenario(t, &tt)
}
documentOperatorScenarios(t, "compare", compareOperatorScenarios)
}
+1 -49
View File
@@ -2,18 +2,14 @@ package yqlib
import (
"container/list"
"fmt"
"time"
"github.com/jinzhu/copier"
logging "gopkg.in/op/go-logging.v1"
)
type Context struct {
MatchingNodes *list.List
Variables map[string]*list.List
DontAutoCreate bool
datetimeLayout string
}
func (n *Context) SingleReadonlyChildContext(candidate *CandidateNode) Context {
@@ -30,17 +26,6 @@ func (n *Context) SingleChildContext(candidate *CandidateNode) Context {
return n.ChildContext(list)
}
func (n *Context) SetDateTimeLayout(newDateTimeLayout string) {
n.datetimeLayout = newDateTimeLayout
}
func (n *Context) GetDateTimeLayout() string {
if n.datetimeLayout != "" {
return n.datetimeLayout
}
return time.RFC3339
}
func (n *Context) GetVariable(name string) *list.List {
if n.Variables == nil {
return nil
@@ -56,52 +41,19 @@ func (n *Context) SetVariable(name string, value *list.List) {
}
func (n *Context) ChildContext(results *list.List) Context {
clone := Context{DontAutoCreate: n.DontAutoCreate, datetimeLayout: n.datetimeLayout}
clone.Variables = make(map[string]*list.List)
if len(n.Variables) > 0 {
err := copier.Copy(&clone.Variables, n.Variables)
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
}
clone.MatchingNodes = results
return clone
}
func (n *Context) ToString() string {
if !log.IsEnabledFor(logging.DEBUG) {
return ""
}
result := fmt.Sprintf("Context\nDontAutoCreate: %v\n", n.DontAutoCreate)
return result + NodesToString(n.MatchingNodes)
}
func (n *Context) DeepClone() Context {
clone := Context{}
err := copier.Copy(&clone, n)
// copier doesn't do lists properly for some reason
clone.MatchingNodes = list.New()
for el := n.MatchingNodes.Front(); el != nil; el = el.Next() {
clonedNode, err := el.Value.(*CandidateNode).Copy()
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
clone.MatchingNodes.PushBack(clonedNode)
}
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
clone.MatchingNodes = results
return clone
}
func (n *Context) Clone() Context {
clone := Context{}
err := copier.Copy(&clone, n)
if err != nil {
log.Error("Error cloning context :(")
panic(err)
-273
View File
@@ -1,273 +0,0 @@
package yqlib
import (
"bufio"
"fmt"
"testing"
"github.com/mikefarah/yq/v4/test"
)
const csvSimple = `name,numberOfCats,likesApples,height
Gary,1,true,168.8
Samantha's Rabbit,2,false,-188.8
`
const expectedUpdatedSimpleCsv = `name,numberOfCats,likesApples,height
Gary,3,true,168.8
Samantha's Rabbit,2,false,-188.8
`
const csvSimpleShort = `Name,Number of Cats
Gary,1
Samantha's Rabbit,2
`
const tsvSimple = `name numberOfCats likesApples height
Gary 1 true 168.8
Samantha's Rabbit 2 false -188.8
`
const expectedYamlFromCSV = `- name: Gary
numberOfCats: 1
likesApples: true
height: 168.8
- name: Samantha's Rabbit
numberOfCats: 2
likesApples: false
height: -188.8
`
const expectedYamlFromCSVMissingData = `- name: Gary
numberOfCats: 1
height: 168.8
- name: Samantha's Rabbit
height: -188.8
likesApples: false
`
const csvSimpleMissingData = `name,numberOfCats,height
Gary,1,168.8
Samantha's Rabbit,,-188.8
`
const csvTestSimpleYaml = `- [i, like, csv]
- [because, excel, is, cool]`
const expectedSimpleCsv = `i,like,csv
because,excel,is,cool
`
const tsvTestExpectedSimpleCsv = `i like csv
because excel is cool
`
var csvScenarios = []formatScenario{
{
description: "Encode CSV simple",
input: csvTestSimpleYaml,
expected: expectedSimpleCsv,
scenarioType: "encode-csv",
},
{
description: "Encode TSV simple",
input: csvTestSimpleYaml,
expected: tsvTestExpectedSimpleCsv,
scenarioType: "encode-tsv",
},
{
description: "Encode Empty",
skipDoc: true,
input: `[]`,
expected: "",
scenarioType: "encode-csv",
},
{
description: "Comma in value",
skipDoc: true,
input: `["comma, in, value", things]`,
expected: "\"comma, in, value\",things\n",
scenarioType: "encode-csv",
},
{
description: "Encode array of objects to csv",
input: expectedYamlFromCSV,
expected: csvSimple,
scenarioType: "encode-csv",
},
{
description: "Encode array of objects to custom csv format",
subdescription: "Add the header row manually, then the we convert each object into an array of values - resulting in an array of arrays. Pick the columns and call the header whatever you like.",
input: expectedYamlFromCSV,
expected: csvSimpleShort,
expression: `[["Name", "Number of Cats"]] + [.[] | [.name, .numberOfCats ]]`,
scenarioType: "encode-csv",
},
{
description: "Encode array of objects to csv - missing fields behaviour",
subdescription: "First entry is used to determine the headers, and it is missing 'likesApples', so it is not included in the csv. Second entry does not have 'numberOfCats' so that is blank",
input: expectedYamlFromCSVMissingData,
expected: csvSimpleMissingData,
scenarioType: "encode-csv",
},
{
description: "Parse CSV into an array of objects",
subdescription: "First row is assumed to be the header row.",
input: csvSimple,
expected: expectedYamlFromCSV,
scenarioType: "decode-csv-object",
},
{
description: "Parse TSV into an array of objects",
subdescription: "First row is assumed to be the header row.",
input: tsvSimple,
expected: expectedYamlFromCSV,
scenarioType: "decode-tsv-object",
},
{
description: "Round trip",
input: csvSimple,
expected: expectedUpdatedSimpleCsv,
expression: `(.[] | select(.name == "Gary") | .numberOfCats) = 3`,
scenarioType: "roundtrip-csv",
},
}
func testCSVScenario(t *testing.T, s formatScenario) {
switch s.scenarioType {
case "encode-csv":
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewYamlDecoder(), NewCsvEncoder(',')), s.description)
case "encode-tsv":
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewYamlDecoder(), NewCsvEncoder('\t')), s.description)
case "decode-csv-object":
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder(','), NewYamlEncoder(2, false, true, true)), s.description)
case "decode-tsv-object":
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder('\t'), NewYamlEncoder(2, false, true, true)), s.description)
case "roundtrip-csv":
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder(','), NewCsvEncoder(',')), s.description)
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
}
}
func documentCSVDecodeObjectScenario(t *testing.T, w *bufio.Writer, s formatScenario, formatType string) {
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
if s.subdescription != "" {
writeOrPanic(w, s.subdescription)
writeOrPanic(w, "\n\n")
}
writeOrPanic(w, fmt.Sprintf("Given a sample.%v file of:\n", formatType))
writeOrPanic(w, fmt.Sprintf("```%v\n%v\n```\n", formatType, s.input))
writeOrPanic(w, "then\n")
writeOrPanic(w, fmt.Sprintf("```bash\nyq -p=%v sample.%v\n```\n", formatType, formatType))
writeOrPanic(w, "will output\n")
separator := ','
if formatType == "tsv" {
separator = '\t'
}
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n",
processFormatScenario(s, NewCSVObjectDecoder(separator), NewYamlEncoder(s.indent, false, true, true))),
)
}
func documentCSVEncodeScenario(w *bufio.Writer, s formatScenario, formatType string) {
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
if s.subdescription != "" {
writeOrPanic(w, s.subdescription)
writeOrPanic(w, "\n\n")
}
writeOrPanic(w, "Given a sample.yml file of:\n")
writeOrPanic(w, fmt.Sprintf("```yaml\n%v\n```\n", s.input))
writeOrPanic(w, "then\n")
expression := s.expression
if expression != "" {
writeOrPanic(w, fmt.Sprintf("```bash\nyq -o=%v '%v' sample.yml\n```\n", formatType, expression))
} else {
writeOrPanic(w, fmt.Sprintf("```bash\nyq -o=%v sample.yml\n```\n", formatType))
}
writeOrPanic(w, "will output\n")
separator := ','
if formatType == "tsv" {
separator = '\t'
}
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
processFormatScenario(s, NewYamlDecoder(), NewCsvEncoder(separator))),
)
}
func documentCSVRoundTripScenario(w *bufio.Writer, s formatScenario, formatType string) {
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
if s.subdescription != "" {
writeOrPanic(w, s.subdescription)
writeOrPanic(w, "\n\n")
}
writeOrPanic(w, fmt.Sprintf("Given a sample.%v file of:\n", formatType))
writeOrPanic(w, fmt.Sprintf("```%v\n%v\n```\n", formatType, s.input))
writeOrPanic(w, "then\n")
expression := s.expression
if expression != "" {
writeOrPanic(w, fmt.Sprintf("```bash\nyq -p=%v -o=%v '%v' sample.%v\n```\n", formatType, formatType, expression, formatType))
} else {
writeOrPanic(w, fmt.Sprintf("```bash\nyq -p=%v -o=%v sample.%v\n```\n", formatType, formatType, formatType))
}
writeOrPanic(w, "will output\n")
separator := ','
if formatType == "tsv" {
separator = '\t'
}
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
processFormatScenario(s, NewCSVObjectDecoder(separator), NewCsvEncoder(separator))),
)
}
func documentCSVScenario(t *testing.T, w *bufio.Writer, i interface{}) {
s := i.(formatScenario)
if s.skipDoc {
return
}
switch s.scenarioType {
case "encode-csv":
documentCSVEncodeScenario(w, s, "csv")
case "encode-tsv":
documentCSVEncodeScenario(w, s, "tsv")
case "decode-csv-object":
documentCSVDecodeObjectScenario(t, w, s, "csv")
case "decode-tsv-object":
documentCSVDecodeObjectScenario(t, w, s, "tsv")
case "roundtrip-csv":
documentCSVRoundTripScenario(w, s, "csv")
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
}
}
func TestCSVScenarios(t *testing.T) {
for _, tt := range csvScenarios {
testCSVScenario(t, tt)
}
genericScenarios := make([]interface{}, len(csvScenarios))
for i, s := range csvScenarios {
genericScenarios[i] = s
}
documentScenarios(t, "usage", "csv-tsv", genericScenarios, documentCSVScenario)
}
-44
View File
@@ -1,44 +0,0 @@
package yqlib
import (
"fmt"
"io"
yaml "gopkg.in/yaml.v3"
)
type InputFormat uint
const (
YamlInputFormat = 1 << iota
XMLInputFormat
PropertiesInputFormat
Base64InputFormat
JsonInputFormat
CSVObjectInputFormat
TSVObjectInputFormat
)
type Decoder interface {
Init(reader io.Reader)
Decode(node *yaml.Node) error
}
func InputFormatFromString(format string) (InputFormat, error) {
switch format {
case "yaml", "y":
return YamlInputFormat, nil
case "xml", "x":
return XMLInputFormat, nil
case "props", "p":
return PropertiesInputFormat, nil
case "json", "ndjson", "j":
return JsonInputFormat, nil
case "csv", "c":
return CSVObjectInputFormat, nil
case "tsv", "t":
return TSVObjectInputFormat, nil
default:
return 0, fmt.Errorf("unknown format '%v' please use [yaml|xml|props]", format)
}
}
-53
View File
@@ -1,53 +0,0 @@
package yqlib
import (
"bytes"
"encoding/base64"
"io"
yaml "gopkg.in/yaml.v3"
)
type base64Decoder struct {
reader io.Reader
finished bool
readAnything bool
encoding base64.Encoding
}
func NewBase64Decoder() Decoder {
return &base64Decoder{finished: false, encoding: *base64.StdEncoding}
}
func (dec *base64Decoder) Init(reader io.Reader) {
dec.reader = reader
dec.readAnything = false
dec.finished = false
}
func (dec *base64Decoder) Decode(rootYamlNode *yaml.Node) error {
if dec.finished {
return io.EOF
}
base64Reader := base64.NewDecoder(&dec.encoding, dec.reader)
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(base64Reader); err != nil {
return err
}
if buf.Len() == 0 {
dec.finished = true
// if we've read _only_ an empty string, lets return that
// otherwise if we've already read some bytes, and now we get
// an empty string, then we are done.
if dec.readAnything {
return io.EOF
}
}
dec.readAnything = true
rootYamlNode.Kind = yaml.ScalarNode
rootYamlNode.Tag = "!!str"
rootYamlNode.Value = buf.String()
return nil
}
-77
View File
@@ -1,77 +0,0 @@
package yqlib
import (
"encoding/csv"
"errors"
"io"
yaml "gopkg.in/yaml.v3"
)
type csvObjectDecoder struct {
separator rune
reader csv.Reader
finished bool
}
func NewCSVObjectDecoder(separator rune) Decoder {
return &csvObjectDecoder{separator: separator}
}
func (dec *csvObjectDecoder) Init(reader io.Reader) {
dec.reader = *csv.NewReader(reader)
dec.reader.Comma = dec.separator
dec.finished = false
}
func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node {
node, err := parseSnippet(content)
if err != nil {
return createScalarNode(content, content)
}
return node
}
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *yaml.Node {
objectNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
for i, header := range headerRow {
objectNode.Content = append(
objectNode.Content,
createScalarNode(header, header),
dec.convertToYamlNode(contentRow[i]))
}
return objectNode
}
func (dec *csvObjectDecoder) Decode(rootYamlNode *yaml.Node) error {
if dec.finished {
return io.EOF
}
headerRow, err := dec.reader.Read()
log.Debugf(": headerRow%v", headerRow)
if err != nil {
return err
}
rootArray := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
contentRow, err := dec.reader.Read()
for err == nil && len(contentRow) > 0 {
log.Debugf("Adding contentRow: %v", contentRow)
rootArray.Content = append(rootArray.Content, dec.createObject(headerRow, contentRow))
contentRow, err = dec.reader.Read()
log.Debugf("Read next contentRow: %v, %v", contentRow, err)
}
if !errors.Is(err, io.EOF) {
return err
}
log.Debugf("finished, contentRow%v", contentRow)
log.Debugf("err: %v", err)
rootYamlNode.Kind = yaml.DocumentNode
rootYamlNode.Content = []*yaml.Node{rootArray}
return nil
}
-85
View File
@@ -1,85 +0,0 @@
package yqlib
import (
"fmt"
"io"
"github.com/goccy/go-json"
yaml "gopkg.in/yaml.v3"
)
type jsonDecoder struct {
decoder json.Decoder
}
func NewJSONDecoder() Decoder {
return &jsonDecoder{}
}
func (dec *jsonDecoder) Init(reader io.Reader) {
dec.decoder = *json.NewDecoder(reader)
}
func (dec *jsonDecoder) Decode(rootYamlNode *yaml.Node) error {
var dataBucket interface{}
log.Debug("going to decode")
err := dec.decoder.Decode(&dataBucket)
if err != nil {
return err
}
node, err := dec.convertToYamlNode(dataBucket)
if err != nil {
return err
}
rootYamlNode.Kind = yaml.DocumentNode
rootYamlNode.Content = []*yaml.Node{node}
return nil
}
func (dec *jsonDecoder) convertToYamlNode(data interface{}) (*yaml.Node, error) {
switch data := data.(type) {
case nil:
return createScalarNode(nil, "null"), nil
case float64, float32:
// json decoder returns ints as float.
return parseSnippet(fmt.Sprintf("%v", data))
case int, int64, int32, string, bool:
return createScalarNode(data, fmt.Sprintf("%v", data)), nil
case map[string]interface{}:
return dec.parseMap(data)
case []interface{}:
return dec.parseArray(data)
default:
return nil, fmt.Errorf("unrecognised type :(")
}
}
func (dec *jsonDecoder) parseMap(dataMap map[string]interface{}) (*yaml.Node, error) {
var yamlMap = &yaml.Node{Kind: yaml.MappingNode}
for key, value := range dataMap {
yamlValue, err := dec.convertToYamlNode(value)
if err != nil {
return nil, err
}
yamlMap.Content = append(yamlMap.Content, createScalarNode(key, fmt.Sprintf("%v", key)), yamlValue)
}
return yamlMap, nil
}
func (dec *jsonDecoder) parseArray(dataArray []interface{}) (*yaml.Node, error) {
var yamlMap = &yaml.Node{Kind: yaml.SequenceNode}
for _, value := range dataArray {
yamlValue, err := dec.convertToYamlNode(value)
if err != nil {
return nil, err
}
yamlMap.Content = append(yamlMap.Content, yamlValue)
}
return yamlMap, nil
}
-122
View File
@@ -1,122 +0,0 @@
package yqlib
import (
"bytes"
"io"
"strconv"
"strings"
"github.com/magiconair/properties"
"gopkg.in/yaml.v3"
)
type propertiesDecoder struct {
reader io.Reader
finished bool
d DataTreeNavigator
}
func NewPropertiesDecoder() Decoder {
return &propertiesDecoder{d: NewDataTreeNavigator(), finished: false}
}
func (dec *propertiesDecoder) Init(reader io.Reader) {
dec.reader = reader
dec.finished = false
}
func parsePropKey(key string) []interface{} {
pathStrArray := strings.Split(key, ".")
path := make([]interface{}, len(pathStrArray))
for i, pathStr := range pathStrArray {
num, err := strconv.ParseInt(pathStr, 10, 32)
if err == nil {
path[i] = num
} else {
path[i] = pathStr
}
}
return path
}
func (dec *propertiesDecoder) processComment(c string) string {
if c == "" {
return ""
}
return "# " + c
}
func (dec *propertiesDecoder) applyProperty(properties *properties.Properties, context Context, key string) error {
value, _ := properties.Get(key)
path := parsePropKey(key)
rhsNode := &yaml.Node{
Value: value,
Tag: "!!str",
Kind: yaml.ScalarNode,
LineComment: dec.processComment(properties.GetComment(key)),
}
rhsNode.Tag = guessTagFromCustomType(rhsNode)
rhsCandidateNode := &CandidateNode{
Path: path,
Node: rhsNode,
}
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhsCandidateNode}
assignmentOpNode := &ExpressionNode{
Operation: assignmentOp,
LHS: createTraversalTree(path, traversePreferences{}, false),
RHS: &ExpressionNode{Operation: rhsOp},
}
_, err := dec.d.GetMatchingNodes(context, assignmentOpNode)
return err
}
func (dec *propertiesDecoder) Decode(rootYamlNode *yaml.Node) error {
if dec.finished {
return io.EOF
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(dec.reader); err != nil {
return err
}
if buf.Len() == 0 {
dec.finished = true
return io.EOF
}
properties, err := properties.LoadString(buf.String())
if err != nil {
return err
}
properties.DisableExpansion = true
rootMap := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
}
context := Context{}
context = context.SingleChildContext(rootMap)
for _, key := range properties.Keys() {
if err := dec.applyProperty(properties, context, key); err != nil {
return err
}
}
rootYamlNode.Kind = yaml.DocumentNode
rootYamlNode.Content = []*yaml.Node{rootMap.Node}
dec.finished = true
return nil
}
-60
View File
@@ -1,60 +0,0 @@
package yqlib
import (
"bufio"
"bytes"
"strings"
)
type formatScenario struct {
input string
indent int
expression string
expected string
description string
subdescription string
skipDoc bool
scenarioType string
}
func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) string {
var output bytes.Buffer
writer := bufio.NewWriter(&output)
if decoder == nil {
decoder = NewYamlDecoder()
}
inputs, err := readDocuments(strings.NewReader(s.input), "sample.yml", 0, decoder)
if err != nil {
panic(err)
}
expression := s.expression
if expression == "" {
expression = "."
}
exp, err := getExpressionParser().ParseExpression(expression)
if err != nil {
panic(err)
}
context, err := NewDataTreeNavigator().GetMatchingNodes(Context{MatchingNodes: inputs}, exp)
if err != nil {
panic(err)
}
printer := NewPrinter(encoder, NewSinglePrinterWriter(writer))
err = printer.PrintResults(context.MatchingNodes)
if err != nil {
panic(err)
}
writer.Flush()
return output.String()
}
-348
View File
@@ -1,348 +0,0 @@
package yqlib
import (
"encoding/xml"
"errors"
"io"
"strings"
"unicode"
"golang.org/x/net/html/charset"
yaml "gopkg.in/yaml.v3"
)
type xmlDecoder struct {
reader io.Reader
readAnything bool
attributePrefix string
contentName string
strictMode bool
keepNamespace bool
useRawToken bool
finished bool
}
func NewXMLDecoder(attributePrefix string, contentName string, strictMode bool, keepNamespace bool, useRawToken bool) Decoder {
if contentName == "" {
contentName = "content"
}
return &xmlDecoder{
attributePrefix: attributePrefix,
contentName: contentName,
finished: false,
strictMode: strictMode,
keepNamespace: keepNamespace,
useRawToken: useRawToken,
}
}
func (dec *xmlDecoder) Init(reader io.Reader) {
dec.reader = reader
dec.readAnything = false
dec.finished = false
}
func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*yaml.Node, error) {
yamlNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
for _, child := range nodes {
yamlChild, err := dec.convertToYamlNode(child)
if err != nil {
return nil, err
}
yamlNode.Content = append(yamlNode.Content, yamlChild)
}
return yamlNode, nil
}
func (dec *xmlDecoder) processComment(c string) string {
if c == "" {
return ""
}
return "#" + strings.TrimRight(c, " ")
}
func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
log.Debug("createMap: headC: %v, footC: %v", n.HeadComment, n.FootComment)
yamlNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
if len(n.Data) > 0 {
label := dec.contentName
labelNode := createScalarNode(label, label)
labelNode.HeadComment = dec.processComment(n.HeadComment)
labelNode.FootComment = dec.processComment(n.FootComment)
yamlNode.Content = append(yamlNode.Content, labelNode, createScalarNode(n.Data, n.Data))
}
for i, keyValuePair := range n.Children {
label := keyValuePair.K
children := keyValuePair.V
labelNode := createScalarNode(label, label)
var valueNode *yaml.Node
var err error
if i == 0 {
labelNode.HeadComment = dec.processComment(n.HeadComment)
}
// if i == len(n.Children)-1 {
labelNode.FootComment = dec.processComment(keyValuePair.FootComment)
// }
log.Debug("len of children in %v is %v", label, len(children))
if len(children) > 1 {
valueNode, err = dec.createSequence(children)
if err != nil {
return nil, err
}
} else {
// comment hack for maps of scalars
// if the value is a scalar, the head comment of the scalar needs to go on the key?
// add tests for <z/> as well as multiple <ds> of inputXmlWithComments > yaml
if len(children[0].Children) == 0 && children[0].HeadComment != "" {
labelNode.HeadComment = labelNode.HeadComment + "\n" + strings.TrimSpace(children[0].HeadComment)
children[0].HeadComment = ""
}
valueNode, err = dec.convertToYamlNode(children[0])
if err != nil {
return nil, err
}
}
yamlNode.Content = append(yamlNode.Content, labelNode, valueNode)
}
return yamlNode, nil
}
func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) {
if len(n.Children) > 0 {
return dec.createMap(n)
}
scalar := createScalarNode(n.Data, n.Data)
if n.Data == "" {
scalar = createScalarNode(nil, "")
}
log.Debug("scalar headC: %v, footC: %v", n.HeadComment, n.FootComment)
scalar.HeadComment = dec.processComment(n.HeadComment)
scalar.LineComment = dec.processComment(n.LineComment)
scalar.FootComment = dec.processComment(n.FootComment)
return scalar, nil
}
func (dec *xmlDecoder) Decode(rootYamlNode *yaml.Node) error {
if dec.finished {
return io.EOF
}
root := &xmlNode{}
// cant use xj - it doesn't keep map order.
err := dec.decodeXML(root)
if err != nil {
return err
}
firstNode, err := dec.convertToYamlNode(root)
if err != nil {
return err
} else if firstNode.Tag == "!!null" {
dec.finished = true
if dec.readAnything {
return io.EOF
}
}
dec.readAnything = true
rootYamlNode.Kind = yaml.DocumentNode
rootYamlNode.Content = []*yaml.Node{firstNode}
dec.finished = true
return nil
}
type xmlNode struct {
Children []*xmlChildrenKv
HeadComment string
FootComment string
LineComment string
Data string
}
type xmlChildrenKv struct {
K string
V []*xmlNode
FootComment string
}
// AddChild appends a node to the list of children
func (n *xmlNode) AddChild(s string, c *xmlNode) {
if n.Children == nil {
n.Children = make([]*xmlChildrenKv, 0)
}
log.Debug("looking for %s", s)
// see if we can find an existing entry to add to
for _, childEntry := range n.Children {
if childEntry.K == s {
log.Debug("found it, appending an entry%s", s)
childEntry.V = append(childEntry.V, c)
log.Debug("yay len of children in %v is %v", s, len(childEntry.V))
return
}
}
log.Debug("not there, making a new one %s", s)
n.Children = append(n.Children, &xmlChildrenKv{K: s, V: []*xmlNode{c}})
}
type element struct {
parent *element
n *xmlNode
label string
state string
}
// this code is heavily based on https://github.com/basgys/goxml2json
// main changes are to decode into a structure that preserves the original order
// of the map keys.
func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
xmlDec := xml.NewDecoder(dec.reader)
xmlDec.Strict = dec.strictMode
// That will convert the charset if the provided XML is non-UTF-8
xmlDec.CharsetReader = charset.NewReaderLabel
// Create first element from the root node
elem := &element{
parent: nil,
n: root,
}
getToken := func() (xml.Token, error) {
if dec.useRawToken {
return xmlDec.RawToken()
}
return xmlDec.Token()
}
for {
t, e := getToken()
if e != nil && !errors.Is(e, io.EOF) {
return e
}
if t == nil {
break
}
switch se := t.(type) {
case xml.StartElement:
log.Debug("start element %v", se.Name.Local)
elem.state = "started"
// Build new a new current element and link it to its parent
elem = &element{
parent: elem,
n: &xmlNode{},
label: se.Name.Local,
}
// Extract attributes as children
for _, a := range se.Attr {
if dec.keepNamespace {
if a.Name.Space != "" {
a.Name.Local = a.Name.Space + ":" + a.Name.Local
}
}
elem.n.AddChild(dec.attributePrefix+a.Name.Local, &xmlNode{Data: a.Value})
}
case xml.CharData:
// Extract XML data (if any)
elem.n.Data = trimNonGraphic(string(se))
if elem.n.Data != "" {
elem.state = "chardata"
log.Debug("chardata [%v] for %v", elem.n.Data, elem.label)
}
case xml.EndElement:
log.Debug("end element %v", elem.label)
elem.state = "finished"
// And add it to its parent list
if elem.parent != nil {
elem.parent.n.AddChild(elem.label, elem.n)
}
// Then change the current element to its parent
elem = elem.parent
case xml.Comment:
commentStr := string(xml.CharData(se))
if elem.state == "started" {
applyFootComment(elem, commentStr)
} else if elem.state == "chardata" {
log.Debug("got a line comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
elem.n.LineComment = joinFilter([]string{elem.n.LineComment, commentStr})
} else {
log.Debug("got a head comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
elem.n.HeadComment = joinFilter([]string{elem.n.HeadComment, commentStr})
}
}
}
return nil
}
func applyFootComment(elem *element, commentStr string) {
// first lets try to put the comment on the last child
if len(elem.n.Children) > 0 {
lastChildIndex := len(elem.n.Children) - 1
childKv := elem.n.Children[lastChildIndex]
log.Debug("got a foot comment for %v: [%v]", childKv.K, commentStr)
childKv.FootComment = joinFilter([]string{elem.n.FootComment, commentStr})
} else {
log.Debug("got a foot comment for %v: [%v]", elem.label, commentStr)
elem.n.FootComment = joinFilter([]string{elem.n.FootComment, commentStr})
}
}
func joinFilter(rawStrings []string) string {
stringsToJoin := make([]string, 0)
for _, str := range rawStrings {
if str != "" {
stringsToJoin = append(stringsToJoin, str)
}
}
return strings.Join(stringsToJoin, " ")
}
// trimNonGraphic returns a slice of the string s, with all leading and trailing
// non graphic characters and spaces removed.
//
// Graphic characters include letters, marks, numbers, punctuation, symbols,
// and spaces, from categories L, M, N, P, S, Zs.
// Spacing characters are set by category Z and property Pattern_White_Space.
func trimNonGraphic(s string) string {
if s == "" {
return s
}
var first *int
var last int
for i, r := range []rune(s) {
if !unicode.IsGraphic(r) || unicode.IsSpace(r) {
continue
}
if first == nil {
f := i // copy i
first = &f
last = i
} else {
last = i
}
}
// If first is nil, it means there are no graphic characters
if first == nil {
return ""
}
return string([]rune(s)[*first : last+1])
}
-23
View File
@@ -1,23 +0,0 @@
package yqlib
import (
"io"
yaml "gopkg.in/yaml.v3"
)
type yamlDecoder struct {
decoder yaml.Decoder
}
func NewYamlDecoder() Decoder {
return &yamlDecoder{}
}
func (dec *yamlDecoder) Init(reader io.Reader) {
dec.decoder = *yaml.NewDecoder(reader)
}
func (dec *yamlDecoder) Decode(rootYamlNode *yaml.Node) error {
return dec.decoder.Decode(rootYamlNode)
}
+265
View File
@@ -0,0 +1,265 @@
Add behaves differently according to the type of the LHS:
- arrays: concatenate
- number scalars: arithmetic addition
- string scalars: concatenate
Use `+=` as append assign for things like increment. Note that `.a += .x` is equivalent to running `.a = .a + .x`.
## Concatenate and assign arrays
Given a sample.yml file of:
```yaml
a:
val: thing
b:
- cat
- dog
```
then
```bash
yq eval '.a.b += ["cow"]' sample.yml
```
will output
```yaml
a:
val: thing
b:
- cat
- dog
- cow
```
## Concatenate arrays
Given a sample.yml file of:
```yaml
a:
- 1
- 2
b:
- 3
- 4
```
then
```bash
yq eval '.a + .b' sample.yml
```
will output
```yaml
- 1
- 2
- 3
- 4
```
## Concatenate null to array
Given a sample.yml file of:
```yaml
a:
- 1
- 2
```
then
```bash
yq eval '.a + null' sample.yml
```
will output
```yaml
- 1
- 2
```
## Add new object to array
Given a sample.yml file of:
```yaml
a:
- dog: woof
```
then
```bash
yq eval '.a + {"cat": "meow"}' sample.yml
```
will output
```yaml
- dog: woof
- cat: meow
```
## Add string to array
Given a sample.yml file of:
```yaml
a:
- 1
- 2
```
then
```bash
yq eval '.a + "hello"' sample.yml
```
will output
```yaml
- 1
- 2
- hello
```
## Append to array
Given a sample.yml file of:
```yaml
a:
- 1
- 2
b:
- 3
- 4
```
then
```bash
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
a:
- 1
- 2
- 3
- 4
b:
- 3
- 4
```
## Append another array using +=
Given a sample.yml file of:
```yaml
a:
- 1
- 2
b:
- 3
- 4
```
then
```bash
yq eval '.a += .b' sample.yml
```
will output
```yaml
a:
- 1
- 2
- 3
- 4
b:
- 3
- 4
```
## Relative append
Given a sample.yml file of:
```yaml
a:
a1:
b:
- cat
a2:
b:
- dog
a3: {}
```
then
```bash
yq eval '.a[].b += ["mouse"]' sample.yml
```
will output
```yaml
a:
a1:
b:
- cat
- mouse
a2:
b:
- dog
- mouse
a3: {b: [mouse]}
```
## String concatenation
Given a sample.yml file of:
```yaml
a: cat
b: meow
```
then
```bash
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
a: catmeow
b: meow
```
## Number addition - float
If the lhs or rhs are floats then the expression will be calculated with floats.
Given a sample.yml file of:
```yaml
a: 3
b: 4.9
```
then
```bash
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
a: 7.9
b: 4.9
```
## Number addition - int
If both the lhs and rhs are ints then the expression will be calculated with ints.
Given a sample.yml file of:
```yaml
a: 3
b: 4
```
then
```bash
yq eval '.a = .a + .b' sample.yml
```
will output
```yaml
a: 7
b: 4
```
## Increment numbers
Given a sample.yml file of:
```yaml
a: 3
b: 5
```
then
```bash
yq eval '.[] += 1' sample.yml
```
will output
```yaml
a: 4
b: 6
```
## Add to null
Adding to null simply returns the rhs
Running
```bash
yq eval --null-input 'null + "cat"'
```
will output
```yaml
cat
```
@@ -1,13 +1,5 @@
# Alternative (Default value)
This operator is used to provide alternative (or default) values when a particular expression is either null or false.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## LHS is defined
Given a sample.yml file of:
```yaml
@@ -15,7 +7,7 @@ a: bridge
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -29,7 +21,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -43,7 +35,7 @@ a: ~
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -57,7 +49,7 @@ a: false
```
then
```bash
yq '.a // "hello"' sample.yml
yq eval '.a // "hello"' sample.yml
```
will output
```yaml
@@ -72,7 +64,7 @@ b: cat
```
then
```bash
yq '.a // .b' sample.yml
yq eval '.a // .b' sample.yml
```
will output
```yaml
@@ -1,16 +1,8 @@
# Anchor and Alias Operators
Use the `alias` and `anchor` operators to read and write yaml aliases and anchors. The `explode` operator normalises a yaml file (dereference (or expands) 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.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Merge one map
see https://yaml.org/type/merge.html
@@ -31,7 +23,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -61,7 +53,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -93,7 +85,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[4] | explode(.)' sample.yml
yq eval '.[4] | explode(.)' sample.yml
```
will output
```yaml
@@ -109,7 +101,7 @@ a: &billyBob cat
```
then
```bash
yq '.a | anchor' sample.yml
yq eval '.a | anchor' sample.yml
```
will output
```yaml
@@ -123,7 +115,7 @@ a: cat
```
then
```bash
yq '.a anchor = "foobar"' sample.yml
yq eval '.a anchor = "foobar"' sample.yml
```
will output
```yaml
@@ -138,7 +130,7 @@ a:
```
then
```bash
yq '.a anchor |= .b' sample.yml
yq eval '.a anchor |= .b' sample.yml
```
will output
```yaml
@@ -154,7 +146,7 @@ a: *billyBob
```
then
```bash
yq '.a | alias' sample.yml
yq eval '.a | alias' sample.yml
```
will output
```yaml
@@ -169,7 +161,7 @@ a: cat
```
then
```bash
yq '.a alias = "meow"' sample.yml
yq eval '.a alias = "meow"' sample.yml
```
will output
```yaml
@@ -185,7 +177,7 @@ a: cat
```
then
```bash
yq '.a alias = ""' sample.yml
yq eval '.a alias = ""' sample.yml
```
will output
```yaml
@@ -202,7 +194,7 @@ a:
```
then
```bash
yq '.a alias |= .f' sample.yml
yq eval '.a alias |= .f' sample.yml
```
will output
```yaml
@@ -219,7 +211,7 @@ f:
```
then
```bash
yq 'explode(.f)' sample.yml
yq eval 'explode(.f)' sample.yml
```
will output
```yaml
@@ -235,7 +227,7 @@ a: mike
```
then
```bash
yq 'explode(.a)' sample.yml
yq eval 'explode(.a)' sample.yml
```
will output
```yaml
@@ -251,7 +243,7 @@ f:
```
then
```bash
yq 'explode(.f)' sample.yml
yq eval 'explode(.f)' sample.yml
```
will output
```yaml
@@ -284,7 +276,7 @@ foobar:
```
then
```bash
yq 'explode(.)' sample.yml
yq eval 'explode(.)' sample.yml
```
will output
```yaml
@@ -323,7 +315,7 @@ thingTwo:
```
then
```bash
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
yq eval '.thingOne |= explode(.) * {"value": false}' sample.yml
```
will output
```yaml
@@ -1,22 +1,8 @@
# Assign (Update)
This operator is used to update node values. It can be used in either the:
### plain form: `=`
Which will assign the LHS node values to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
### relative form: `|=`
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Create yaml file
Running
```bash
yq --null-input '.a.b = "cat" | .x = "frog"'
yq eval --null-input '.a.b = "cat" | .x = "frog"'
```
will output
```yaml
@@ -34,7 +20,7 @@ a:
```
then
```bash
yq '.a |= .b' sample.yml
yq eval '.a |= .b' sample.yml
```
will output
```yaml
@@ -51,7 +37,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] |= . * 2' sample.yml
yq eval '.[] |= . * 2' sample.yml
```
will output
```yaml
@@ -90,7 +76,7 @@ b: sibling
```
then
```bash
yq '.a = .b' sample.yml
yq eval '.a = .b' sample.yml
```
will output
```yaml
@@ -107,13 +93,13 @@ c: fieldC
```
then
```bash
yq '(.a, .c) = "potato"' sample.yml
yq eval '(.a, .c) = "potatoe"' sample.yml
```
will output
```yaml
a: potato
a: potatoe
b: fieldB
c: potato
c: potatoe
```
## Update string value
@@ -124,7 +110,7 @@ a:
```
then
```bash
yq '.a.b = "frog"' sample.yml
yq eval '.a.b = "frog"' sample.yml
```
will output
```yaml
@@ -142,7 +128,7 @@ a:
```
then
```bash
yq '.a.b |= "frog"' sample.yml
yq eval '.a.b |= "frog"' sample.yml
```
will output
```yaml
@@ -150,9 +136,7 @@ a:
b: frog
```
## Update deeply selected results
Note that the LHS is wrapped in brackets! This is to ensure we don't first filter out the yaml and then update the snippet.
## Update selected results
Given a sample.yml file of:
```yaml
a:
@@ -161,7 +145,7 @@ a:
```
then
```bash
yq '(.a[] | select(. == "apple")) = "frog"' sample.yml
yq eval '(.a[] | select(. == "apple")) = "frog"' sample.yml
```
will output
```yaml
@@ -179,7 +163,7 @@ Given a sample.yml file of:
```
then
```bash
yq '(.[] | select(. == "*andy")) = "bogs"' sample.yml
yq eval '(.[] | select(. == "*andy")) = "bogs"' sample.yml
```
will output
```yaml
@@ -195,28 +179,11 @@ Given a sample.yml file of:
```
then
```bash
yq '.a.b |= "bogs"' sample.yml
yq eval '.a.b |= "bogs"' sample.yml
```
will output
```yaml
a:
b: bogs
```
## Update node value that has an anchor
Anchor will remaple
Given a sample.yml file of:
```yaml
a: &cool cat
```
then
```bash
yq '.a = "dog"' sample.yml
```
will output
```yaml
a: &cool dog
{a: {b: bogs}}
```
## Update empty object and array
@@ -226,12 +193,10 @@ Given a sample.yml file of:
```
then
```bash
yq '.a.b.[0] |= "bogs"' sample.yml
yq eval '.a.b.[0] |= "bogs"' sample.yml
```
will output
```yaml
a:
b:
- bogs
{a: {b: [bogs]}}
```
@@ -1,5 +1,3 @@
# Boolean Operators
The `or` and `and` operators take two parameters and return a boolean result.
`not` flips a boolean from true to false, or vice versa.
@@ -10,22 +8,10 @@ The `or` and `and` operators take two parameters and return a boolean result.
These are most commonly used with the `select` operator to filter particular nodes.
## Related Operators
- equals / not equals (`==`, `!=`) operators [here](https://mikefarah.gitbook.io/yq/operators/equals)
- comparison (`>=`, `<` etc) operators [here](https://mikefarah.gitbook.io/yq/operators/compare)
- select operator [here](https://mikefarah.gitbook.io/yq/operators/select)
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## `or` example
Running
```bash
yq --null-input 'true or false'
yq eval --null-input 'true or false'
```
will output
```yaml
@@ -35,7 +21,7 @@ true
## `and` example
Running
```bash
yq --null-input 'true and false'
yq eval --null-input 'true and false'
```
will output
```yaml
@@ -54,7 +40,7 @@ Given a sample.yml file of:
```
then
```bash
yq '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
yq eval '[.[] | select(.a == "cat" or .b == "dog")]' sample.yml
```
will output
```yaml
@@ -72,7 +58,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'any' sample.yml
yq eval 'any' sample.yml
```
will output
```yaml
@@ -86,7 +72,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'any' sample.yml
yq eval 'any' sample.yml
```
will output
```yaml
@@ -105,7 +91,7 @@ b:
```
then
```bash
yq '.[] |= any_c(. == "awesome")' sample.yml
yq eval '.[] |= any_c(. == "awesome")' sample.yml
```
will output
```yaml
@@ -121,7 +107,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'all' sample.yml
yq eval 'all' sample.yml
```
will output
```yaml
@@ -135,7 +121,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'all' sample.yml
yq eval 'all' sample.yml
```
will output
```yaml
@@ -154,7 +140,7 @@ b:
```
then
```bash
yq '.[] |= all_c(tag == "!!str")' sample.yml
yq eval '.[] |= all_c(tag == "!!str")' sample.yml
```
will output
```yaml
@@ -165,7 +151,7 @@ b: false
## Not true is false
Running
```bash
yq --null-input 'true | not'
yq eval --null-input 'true | not'
```
will output
```yaml
@@ -175,7 +161,7 @@ false
## Not false is true
Running
```bash
yq --null-input 'false | not'
yq eval --null-input 'false | not'
```
will output
```yaml
@@ -185,7 +171,7 @@ true
## String values considered to be true
Running
```bash
yq --null-input '"cat" | not'
yq eval --null-input '"cat" | not'
```
will output
```yaml
@@ -195,7 +181,7 @@ false
## Empty string value considered to be true
Running
```bash
yq --null-input '"" | not'
yq eval --null-input '"" | not'
```
will output
```yaml
@@ -205,7 +191,7 @@ false
## Numbers are considered to be true
Running
```bash
yq --null-input '1 | not'
yq eval --null-input '1 | not'
```
will output
```yaml
@@ -215,7 +201,7 @@ false
## Zero is considered to be true
Running
```bash
yq --null-input '0 | not'
yq eval --null-input '0 | not'
```
will output
```yaml
@@ -225,7 +211,7 @@ false
## Null is considered to be false
Running
```bash
yq --null-input '~ | not'
yq eval --null-input '~ | not'
```
will output
```yaml
@@ -3,16 +3,10 @@
This creates an array using the expression between the square brackets.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Collect empty
Running
```bash
yq --null-input '[]'
yq eval --null-input '[]'
```
will output
```yaml
@@ -22,7 +16,7 @@ will output
## Collect single
Running
```bash
yq --null-input '["cat"]'
yq eval --null-input '["cat"]'
```
will output
```yaml
@@ -37,7 +31,7 @@ b: dog
```
then
```bash
yq '[.a, .b]' sample.yml
yq eval '[.a, .b]' sample.yml
```
will output
```yaml
@@ -1,20 +1,14 @@
# Comment Operators
Use these comment operators to set or retrieve comments.
Like the `=` and `|=` assign operators, the same syntax applies when updating comments:
### plain form: `=`
This will assign the LHS nodes comments to the expression on the RHS. The RHS is run against the matching nodes in the pipeline
### relative form: `|=`
Similar to the plain form, however the RHS evaluates against each matching LHS node! This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Set line comment
Given a sample.yml file of:
@@ -23,7 +17,7 @@ a: cat
```
then
```bash
yq '.a line_comment="single"' sample.yml
yq eval '.a lineComment="single"' sample.yml
```
will output
```yaml
@@ -38,7 +32,7 @@ b: dog
```
then
```bash
yq '.. line_comment |= .' sample.yml
yq eval '.. lineComment |= .' sample.yml
```
will output
```yaml
@@ -53,7 +47,7 @@ a: cat
```
then
```bash
yq '. head_comment="single"' sample.yml
yq eval '. headComment="single"' sample.yml
```
will output
```yaml
@@ -69,11 +63,12 @@ a: cat
```
then
```bash
yq '. foot_comment=.a' sample.yml
yq eval '. footComment=.a' sample.yml
```
will output
```yaml
a: cat
# cat
```
@@ -85,7 +80,7 @@ b: dog # leave this
```
then
```bash
yq '.a line_comment=""' sample.yml
yq eval '.a lineComment=""' sample.yml
```
will output
```yaml
@@ -104,7 +99,7 @@ b: # key comment
```
then
```bash
yq '... comments=""' sample.yml
yq eval '... comments=""' sample.yml
```
will output
```yaml
@@ -116,11 +111,10 @@ b:
Given a sample.yml file of:
```yaml
a: cat # meow
# have a great day
```
then
```bash
yq '.a | line_comment' sample.yml
yq eval '.a | lineComment' sample.yml
```
will output
```yaml
@@ -130,58 +124,28 @@ meow
## Get head comment
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
```
then
```bash
yq '. | head_comment' sample.yml
yq eval '. | headComment' sample.yml
```
will output
```yaml
welcome!
```
## Head comment with document split
Given a sample.yml file of:
```yaml
# welcome!
---
# bob
a: cat # meow
# have a great day
```
then
```bash
yq 'head_comment' sample.yml
```
will output
```yaml
welcome!
bob
```
## Get foot comment
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
# no really
```
then
```bash
yq '. | foot_comment' sample.yml
yq eval '. | footComment' sample.yml
```
will output
```yaml
have a great day
no really
```
@@ -1,17 +1,8 @@
# Create, Collect into Object
This is used to construct objects (or maps). This can be used against existing yaml, or to create fresh yaml documents.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Collect empty object
Running
```bash
yq --null-input '{}'
yq eval --null-input '{}'
```
will output
```yaml
@@ -25,7 +16,7 @@ name: Mike
```
then
```bash
yq '{"wrap": .}' sample.yml
yq eval '{"wrap": .}' sample.yml
```
will output
```yaml
@@ -43,7 +34,7 @@ pets:
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
yq eval '{.name: .pets.[]}' sample.yml
```
will output
```yaml
@@ -66,7 +57,7 @@ pets:
```
then
```bash
yq '{.name: .pets.[]}' sample.yml
yq eval '{.name: .pets.[]}' sample.yml
```
will output
```yaml
@@ -79,23 +70,10 @@ Rosey: sheep
## Creating yaml from scratch
Running
```bash
yq --null-input '{"wrap": "frog"}'
yq eval --null-input '{"wrap": "frog"}'
```
will output
```yaml
wrap: frog
```
## Creating yaml from scratch with multiple objects
Running
```bash
yq --null-input '(.a.b = "foo") | (.d.e = "bar")'
```
will output
```yaml
a:
b: foo
d:
e: bar
```
@@ -1,13 +1,4 @@
# Delete
Deletes matching entries in maps or arrays.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Delete entry in map
Given a sample.yml file of:
```yaml
@@ -16,7 +7,7 @@ b: dog
```
then
```bash
yq 'del(.b)' sample.yml
yq eval 'del(.b)' sample.yml
```
will output
```yaml
@@ -32,7 +23,7 @@ a:
```
then
```bash
yq 'del(.a.a1)' sample.yml
yq eval 'del(.a.a1)' sample.yml
```
will output
```yaml
@@ -49,7 +40,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'del(.[1])' sample.yml
yq eval 'del(.[1])' sample.yml
```
will output
```yaml
@@ -65,7 +56,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'del(.[0].a)' sample.yml
yq eval 'del(.[0].a)' sample.yml
```
will output
```yaml
@@ -80,7 +71,7 @@ b: dog
```
then
```bash
yq 'del(.c)' sample.yml
yq eval 'del(.c)' sample.yml
```
will output
```yaml
@@ -97,7 +88,7 @@ c: bat
```
then
```bash
yq 'del( .[] | select(. == "*at") )' sample.yml
yq eval 'del( .[] | select(. == "*at") )' sample.yml
```
will output
```yaml
@@ -115,7 +106,7 @@ a:
```
then
```bash
yq 'del(.. | select(has("name")).name)' sample.yml
yq eval 'del(.. | select(has("name")).name)' sample.yml
```
will output
```yaml
@@ -1,13 +1,4 @@
# Document Index
Use the `documentIndex` operator (or the `di` shorthand) to select nodes of a particular document.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Retrieve a document index
Given a sample.yml file of:
```yaml
@@ -17,7 +8,7 @@ a: frog
```
then
```bash
yq '.a | document_index' sample.yml
yq eval '.a | documentIndex' sample.yml
```
will output
```yaml
@@ -35,7 +26,7 @@ a: frog
```
then
```bash
yq '.a | di' sample.yml
yq eval '.a | di' sample.yml
```
will output
```yaml
@@ -53,7 +44,7 @@ a: frog
```
then
```bash
yq 'select(document_index == 1)' sample.yml
yq eval 'select(documentIndex == 1)' sample.yml
```
will output
```yaml
@@ -69,7 +60,7 @@ a: frog
```
then
```bash
yq 'select(di == 1)' sample.yml
yq eval 'select(di == 1)' sample.yml
```
will output
```yaml
@@ -85,7 +76,7 @@ a: frog
```
then
```bash
yq '.a | ({"match": ., "doc": document_index})' sample.yml
yq eval '.a | ({"match": ., "doc": documentIndex})' sample.yml
```
will output
```yaml
@@ -1,13 +1,4 @@
# Entries
Similar to the same named functions in `jq` these functions convert to/from an object and an array of key-value pairs. This is most useful for performing operations on keys of maps.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## to_entries Map
Given a sample.yml file of:
```yaml
@@ -16,7 +7,7 @@ b: 2
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -34,7 +25,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -51,7 +42,7 @@ null
```
then
```bash
yq 'to_entries' sample.yml
yq eval 'to_entries' sample.yml
```
will output
```yaml
@@ -65,7 +56,7 @@ b: 2
```
then
```bash
yq 'to_entries | from_entries' sample.yml
yq eval 'to_entries | from_entries' sample.yml
```
will output
```yaml
@@ -83,7 +74,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'to_entries | from_entries' sample.yml
yq eval 'to_entries | from_entries' sample.yml
```
will output
```yaml
@@ -99,7 +90,7 @@ b: 2
```
then
```bash
yq 'with_entries(.key |= "KEY_" + .)' sample.yml
yq eval 'with_entries(.key |= "KEY_" + .)' sample.yml
```
will output
```yaml
@@ -117,7 +108,7 @@ c:
```
then
```bash
yq 'with_entries(select(.value | has("b")))' sample.yml
yq eval 'with_entries(select(.value | has("b")))' sample.yml
```
will output
```yaml
+78
View File
@@ -0,0 +1,78 @@
This operator is used to handle environment variables usage in path expressions. While environment variables can, of course, be passed in via your CLI with string interpolation, this often comes with complex quote escaping and can be tricky to write and read. Note that there are two forms, `env` which will parse the environment variable as a yaml (be it a map, array, string, number of boolean) and `strenv` which will always parse the argument as a string.
## Read string environment variable
Running
```bash
myenv="cat meow" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
a: cat meow
```
## Read boolean environment variable
Running
```bash
myenv="true" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
a: true
```
## Read numeric environment variable
Running
```bash
myenv="12" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
a: 12
```
## Read yaml environment variable
Running
```bash
myenv="{b: fish}" yq eval --null-input '.a = env(myenv)'
```
will output
```yaml
a: {b: fish}
```
## Read boolean environment variable as a string
Running
```bash
myenv="true" yq eval --null-input '.a = strenv(myenv)'
```
will output
```yaml
a: "true"
```
## Read numeric environment variable as a string
Running
```bash
myenv="12" yq eval --null-input '.a = strenv(myenv)'
```
will output
```yaml
a: "12"
```
## Dynamic key lookup with environment variable
Given a sample.yml file of:
```yaml
cat: meow
dog: woof
```
then
```bash
myenv="cat" yq eval '.[env(myenv)]' sample.yml
```
will output
```yaml
meow
```
+123
View File
@@ -0,0 +1,123 @@
This is a boolean operator that will return ```true``` if the LHS is equal to the RHS and ``false`` otherwise.
```
.a == .b
```
It is most often used with the select operator to find particular nodes:
```
select(.a == .b)
```
## Match string
Given a sample.yml file of:
```yaml
- cat
- goat
- dog
```
then
```bash
yq eval '.[] | (. == "*at")' sample.yml
```
will output
```yaml
true
true
false
```
## Don't match string
Given a sample.yml file of:
```yaml
- cat
- goat
- dog
```
then
```bash
yq eval '.[] | (. != "*at")' sample.yml
```
will output
```yaml
false
false
true
```
## Match number
Given a sample.yml file of:
```yaml
- 3
- 4
- 5
```
then
```bash
yq eval '.[] | (. == 4)' sample.yml
```
will output
```yaml
false
true
false
```
## Dont match number
Given a sample.yml file of:
```yaml
- 3
- 4
- 5
```
then
```bash
yq eval '.[] | (. != 4)' sample.yml
```
will output
```yaml
true
false
true
```
## Match nulls
Running
```bash
yq eval --null-input 'null == ~'
```
will output
```yaml
true
```
## Non exisitant key doesn't equal a value
Given a sample.yml file of:
```yaml
a: frog
```
then
```bash
yq eval 'select(.b != "thing")' sample.yml
```
will output
```yaml
a: frog
```
## Two non existant keys are equal
Given a sample.yml file of:
```yaml
a: frog
```
then
```bash
yq eval 'select(.b == .c)' sample.yml
```
will output
```yaml
a: frog
```
@@ -1,5 +1,3 @@
# File Operators
File operators are most often used with merge when needing to merge specific files together. Note that when doing this, you will need to use `eval-all` to ensure all yaml documents are loaded into memory before performing the merge (as opposed to `eval` which runs the expression once per document).
Note that the `fileIndex` operator has a short alias of `fi`.
@@ -9,13 +7,6 @@ Note the use of eval-all to ensure all documents are loaded into memory.
```bash
yq eval-all 'select(fi == 0) * select(filename == "file2.yaml")' file1.yaml file2.yaml
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Get filename
Given a sample.yml file of:
```yaml
@@ -23,7 +14,7 @@ a: cat
```
then
```bash
yq 'filename' sample.yml
yq eval 'filename' sample.yml
```
will output
```yaml
@@ -37,7 +28,7 @@ a: cat
```
then
```bash
yq 'file_index' sample.yml
yq eval 'fileIndex' sample.yml
```
will output
```yaml
@@ -55,7 +46,7 @@ a: cat
```
then
```bash
yq eval-all 'file_index' sample.yml another.yml
yq eval-all 'fileIndex' sample.yml another.yml
```
will output
```yaml
@@ -71,7 +62,7 @@ a: cat
```
then
```bash
yq 'fi' sample.yml
yq eval 'fi' sample.yml
```
will output
```yaml
@@ -1,13 +1,4 @@
# Has
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Has map key
Given a sample.yml file of:
```yaml
@@ -18,7 +9,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | has("a")' sample.yml
yq eval '.[] | has("a")' sample.yml
```
will output
```yaml
@@ -42,7 +33,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | select(.a.b | has("c"))' sample.yml
yq eval '.[] | select(.a.b | has("c"))' sample.yml
```
will output
```yaml
@@ -63,7 +54,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | has(1)' sample.yml
yq eval '.[] | has(1)' sample.yml
```
will output
```yaml
+35
View File
@@ -0,0 +1,35 @@
# Keys
Use the `keys` operator to return map keys or array indices.
## Map keys
Given a sample.yml file of:
```yaml
dog: woof
cat: meow
```
then
```bash
yq eval 'keys' sample.yml
```
will output
```yaml
- dog
- cat
```
## Array keys
Given a sample.yml file of:
```yaml
- apple
- banana
```
then
```bash
yq eval 'keys' sample.yml
```
will output
```yaml
- 0
- 1
```
@@ -1,13 +1,5 @@
# Length
Returns the lengths of the nodes. Length is defined according to the type of the node.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## String length
returns length of string
@@ -17,7 +9,7 @@ a: cat
```
then
```bash
yq '.a | length' sample.yml
yq eval '.a | length' sample.yml
```
will output
```yaml
@@ -31,7 +23,7 @@ a: null
```
then
```bash
yq '.a | length' sample.yml
yq eval '.a | length' sample.yml
```
will output
```yaml
@@ -48,7 +40,7 @@ c: dog
```
then
```bash
yq 'length' sample.yml
yq eval 'length' sample.yml
```
will output
```yaml
@@ -67,7 +59,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'length' sample.yml
yq eval 'length' sample.yml
```
will output
```yaml
@@ -1,5 +1,3 @@
# Multiply (Merge)
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently numbers, arrays and objects are supported.
## Objects and arrays - merging
@@ -10,51 +8,25 @@ Note that when merging objects, this operator returns the merged object (not the
### Merge Flags
You can control how objects are merged by using one or more of the following flags. Multiple flags can be used together, e.g. `.a *+? .b`. See examples below
- `+` append arrays
- `d` deeply merge arrays
- `?` only merge _existing_ fields
- `n` only merge _new_ fields
- `+` to append arrays
- `?` to only merge existing fields
- `d` to deeply merge arrays
### Merge two files together
This uses the load operator to merge file2 into file1.
```bash
yq '. *= load("file2.yml")' file1.yml
```
### Merging all files
### Merging files
Note the use of `eval-all` to ensure all documents are loaded into memory.
```bash
yq eval-all '. as $item ireduce ({}; . * $item )' *.yml
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml
```
# Merging complex arrays together by a key field
By default - `yq` merge is naive. It merges maps when they match the key name, and arrays are merged either by appending them together, or merging the entries by their position in the array.
For more complex array merging (e.g. merging items that match on a certain key) please see the example [here](https://mikefarah.gitbook.io/yq/operators/multiply-merge#merge-arrays-of-objects-together-matching-on-a-key)
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Multiply integers
Given a sample.yml file of:
```yaml
a: 3
b: 4
```
then
Running
```bash
yq '.a *= .b' sample.yml
yq eval --null-input '3 * 4'
```
will output
```yaml
a: 12
b: 4
12
```
## Merge objects together, returning merged result only
@@ -70,7 +42,7 @@ b:
```
then
```bash
yq '.a * .b' sample.yml
yq eval '.a * .b' sample.yml
```
will output
```yaml
@@ -93,7 +65,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -117,7 +89,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -140,7 +112,7 @@ b:
```
then
```bash
yq '. * {"a":.b}' sample.yml
yq eval '. * {"a":.b}' sample.yml
```
will output
```yaml
@@ -166,7 +138,7 @@ b:
```
then
```bash
yq '.a *? .b' sample.yml
yq eval '.a *? .b' sample.yml
```
will output
```yaml
@@ -174,27 +146,6 @@ thing: two
cat: frog
```
## Merge, only new fields
Given a sample.yml file of:
```yaml
a:
thing: one
cat: frog
b:
missing: two
thing: two
```
then
```bash
yq '.a *n .b' sample.yml
```
will output
```yaml
thing: one
cat: frog
missing: two
```
## Merge, appending arrays
Given a sample.yml file of:
```yaml
@@ -213,7 +164,7 @@ b:
```
then
```bash
yq '.a *+ .b' sample.yml
yq eval '.a *+ .b' sample.yml
```
will output
```yaml
@@ -243,7 +194,7 @@ b:
```
then
```bash
yq '.a *?+ .b' sample.yml
yq eval '.a *?+ .b' sample.yml
```
will output
```yaml
@@ -270,7 +221,7 @@ b:
```
then
```bash
yq '.a *d .b' sample.yml
yq eval '.a *d .b' sample.yml
```
will output
```yaml
@@ -281,70 +232,43 @@ will output
```
## Merge arrays of objects together, matching on a key
This is a fairly complex expression - you can use it as is by providing the environment variables as seen in the example below.
It merges in the array provided in the second file into the first - matching on equal keys.
Explanation:
The approach, at a high level, is to reduce into a merged map (keyed by the unique key)
and then convert that back into an array.
First the expression will create a map from the arrays keyed by the idPath, the unique field we want to merge by.
The reduce operator is merging '({}; . * $item )', so array elements with the matching key will be merged together.
Next, we convert the map back to an array, using reduce again, concatenating all the map values together.
Finally, we set the result of the merged array back into the first doc.
Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223)
It's a complex command, the trickyness comes from needing to have the right context in the expressions.
First we save the second array into a variable '$two' which lets us reference it later.
We then need to update the first array. We will use the relative update (|=) because we need to update relative to the current element of the array in the LHS in the RHS expression.
We set the current element of the first array as $cur. Now we multiply (merge) $cur with the matching entry in $two, by passing $two through a select filter.
Given a sample.yml file of:
```yaml
myArray:
- a: apple
b: appleB
- a: kiwi
b: kiwiB
- a: banana
b: bananaB
something: else
- a: apple
b: appleB
- a: kiwi
b: kiwiB
- a: banana
b: bananaB
```
And another sample another.yml file of:
```yaml
newArray:
- a: banana
c: bananaC
- a: apple
b: appleB2
- a: dingo
c: dingoC
- a: banana
c: bananaC
- a: apple
b: appleB2
- a: dingo
c: dingoC
```
then
```bash
idPath=".a" originalPath=".myArray" otherPath=".newArray" yq eval-all '
(
(( (eval(strenv(originalPath)) + eval(strenv(otherPath))) | .[] | {(eval(strenv(idPath))): .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | (eval(strenv(originalPath))) = $mergedArray
' sample.yml another.yml
yq eval-all '(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))' sample.yml another.yml
```
will output
```yaml
myArray:
- a: apple
b: appleB2
- a: kiwi
b: kiwiB
- a: banana
b: bananaB
c: bananaC
- a: dingo
c: dingoC
something: else
- a: apple
b: appleB2
- a: kiwi
b: kiwiB
- a: banana
b: bananaB
c: bananaC
```
## Merge to prefix an element
@@ -355,7 +279,7 @@ b: dog
```
then
```bash
yq '. * {"a": {"c": .a}}' sample.yml
yq eval '. * {"a": {"c": .a}}' sample.yml
```
will output
```yaml
@@ -376,7 +300,7 @@ c:
```
then
```bash
yq '.c * .b' sample.yml
yq eval '.c * .b' sample.yml
```
will output
```yaml
@@ -396,7 +320,7 @@ c:
```
then
```bash
yq '.c * .a' sample.yml
yq eval '.c * .a' sample.yml
```
will output
```yaml
@@ -428,56 +352,15 @@ foobar:
```
then
```bash
yq '.foobar * .foobarList' sample.yml
yq eval '.foobar * .foobarList' sample.yml
```
will output
```yaml
c: foobarList_c
!!merge <<:
<<:
- *foo
- *bar
thing: foobar_thing
b: foobarList_b
```
## Custom types: that are really numbers
When custom tags are encountered, yq will try to decode the underlying type.
Given a sample.yml file of:
```yaml
a: !horse 2
b: !goat 3
```
then
```bash
yq '.a = .a * .b' sample.yml
```
will output
```yaml
a: !horse 6
b: !goat 3
```
## Custom types: that are really maps
Custom tags will be maintained.
Given a sample.yml file of:
```yaml
a: !horse
cat: meow
b: !goat
dog: woof
```
then
```bash
yq '.a = .a * .b' sample.yml
```
will output
```yaml
a: !horse
cat: meow
dog: woof
b: !goat
dog: woof
```
@@ -1,15 +1,7 @@
# Path
The path operator can be used to get the traversal paths of matching nodes in an expression. The path is returned as an array, which if traversed in order will lead to the matching node.
You can get the key/index of matching nodes by using the `path` operator to return the path array then piping that through `.[-1]` to get the last element of that array, the key.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Map path
Given a sample.yml file of:
```yaml
@@ -18,7 +10,7 @@ a:
```
then
```bash
yq '.a.b | path' sample.yml
yq eval '.a.b | path' sample.yml
```
will output
```yaml
@@ -34,7 +26,7 @@ a:
```
then
```bash
yq '.a.b | path | .[-1]' sample.yml
yq eval '.a.b | path | .[-1]' sample.yml
```
will output
```yaml
@@ -50,7 +42,7 @@ a:
```
then
```bash
yq '.a.[] | select(. == "dog") | path' sample.yml
yq eval '.a.[] | select(. == "dog") | path' sample.yml
```
will output
```yaml
@@ -67,7 +59,7 @@ a:
```
then
```bash
yq '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
yq eval '.a.[] | select(. == "dog") | path | .[-1]' sample.yml
```
will output
```yaml
@@ -84,7 +76,7 @@ a:
```
then
```bash
yq '.a[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
yq eval '.a.[] | select(. == "*og") | [{"path":path, "value":.}]' sample.yml
```
will output
```yaml
@@ -1,13 +1,5 @@
# Pipe
Pipe the results of an expression into another. Like the bash operator.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Simple Pipe
Given a sample.yml file of:
```yaml
@@ -16,7 +8,7 @@ a:
```
then
```bash
yq '.a | .b' sample.yml
yq eval '.a | .b' sample.yml
```
will output
```yaml
@@ -32,7 +24,7 @@ c: same
```
then
```bash
yq '.a = "cat" | .b = "dog"' sample.yml
yq eval '.a = "cat" | .b = "dog"' sample.yml
```
will output
```yaml
@@ -1,5 +1,3 @@
# Recursive Descent (Glob)
This operator recursively matches (or globs) all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
## match values form `..`
@@ -8,7 +6,7 @@ This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it
For instance to set the `style` of all _value_ nodes in a yaml doc, excluding map keys:
```bash
yq '.. style= "flow"' file.yaml
yq eval '.. style= "flow"' file.yaml
```
## match values and map keys form `...`
@@ -17,14 +15,8 @@ The also includes map keys in the results set. This is particularly useful in YA
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
```bash
yq '... style= "flow"' file.yaml
yq eval '... style= "flow"' file.yaml
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Recurse map (values only)
Given a sample.yml file of:
```yaml
@@ -32,7 +24,7 @@ a: frog
```
then
```bash
yq '..' sample.yml
yq eval '..' sample.yml
```
will output
```yaml
@@ -53,7 +45,7 @@ a:
```
then
```bash
yq '[.. | select(has("name"))]' sample.yml
yq eval '[.. | select(has("name"))]' sample.yml
```
will output
```yaml
@@ -76,7 +68,7 @@ a:
```
then
```bash
yq '.. | select(. == "frog")' sample.yml
yq eval '.. | select(. == "frog")' sample.yml
```
will output
```yaml
@@ -93,7 +85,7 @@ a: frog
```
then
```bash
yq '...' sample.yml
yq eval '...' sample.yml
```
will output
```yaml
@@ -111,7 +103,7 @@ b: *cat
```
then
```bash
yq '[..]' sample.yml
yq eval '[..]' sample.yml
```
will output
```yaml
@@ -148,7 +140,7 @@ foobar:
```
then
```bash
yq '.foobar | [..]' sample.yml
yq eval '.foobar | [..]' sample.yml
```
will output
```yaml
@@ -1,5 +1,3 @@
# Reduce
Reduce is a powerful way to process a collection of data into a new form.
```
@@ -19,13 +17,8 @@ On the RHS there is `<init>`, the starting value of the accumulator and `<block>
## yq vs jq syntax
Reduce syntax in `yq` is a little different from `jq` - as `yq` (currently) isn't as sophisticated as `jq` and its only supports infix notation (e.g. a + b, where the operator is in the middle of the two parameters) - where as `jq` uses a mix of infix notation with _prefix_ notation (e.g. `reduce a b` is like writing `+ a b`).
To that end, the reduce operator is called `ireduce` for backwards compatibility if a `jq` like prefix version of `reduce` is ever added.
To that end, the reduce operator is called `ireduce` for backwards compatability if a `jq` like prefix version of `reduce` is ever added.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Sum numbers
Given a sample.yml file of:
@@ -37,7 +30,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] as $item ireduce (0; . + $item)' sample.yml
yq eval '.[] as $item ireduce (0; . + $item)' sample.yml
```
will output
```yaml
@@ -73,7 +66,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
yq eval '.[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )' sample.yml
```
will output
```yaml
+38
View File
@@ -0,0 +1,38 @@
Select is used to filter arrays and maps by a boolean expression.
## Select elements from array
Given a sample.yml file of:
```yaml
- cat
- goat
- dog
```
then
```bash
yq eval '.[] | select(. == "*at")' sample.yml
```
will output
```yaml
cat
goat
```
## Select and update matching values in map
Given a sample.yml file of:
```yaml
a:
things: cat
bob: goat
horse: dog
```
then
```bash
yq eval '(.a.[] | select(. == "*at")) |= "rabbit"' sample.yml
```
will output
```yaml
a:
things: rabbit
bob: rabbit
horse: dog
```
@@ -1,23 +1,13 @@
# Sort Keys
The Sort Keys operator sorts maps by their keys (based on their string value). This operator does not do anything to arrays or scalars (so you can easily recursively apply it to all maps).
Sort is particularly useful for diffing two different yaml documents:
```bash
yq -i -P 'sort_keys(..)' file1.yml
yq -i -P 'sort_keys(..)' file2.yml
yq eval -i 'sortKeys(..)' file1.yml
yq eval -i 'sortKeys(..)' file2.yml
diff file1.yml file2.yml
```
Note that `yq` does not yet consider anchors when sorting by keys - this may result in invalid yaml documents if your are using merge anchors.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Sort keys of map
Given a sample.yml file of:
```yaml
@@ -27,7 +17,7 @@ b: bing
```
then
```bash
yq 'sort_keys(.)' sample.yml
yq eval 'sortKeys(.)' sample.yml
```
will output
```yaml
@@ -57,7 +47,7 @@ aParent:
```
then
```bash
yq 'sort_keys(..)' sample.yml
yq eval 'sortKeys(..)' sample.yml
```
will output
```yaml
@@ -2,16 +2,10 @@
This operator splits all matches into separate documents
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Split empty
Running
```bash
yq --null-input 'split_doc'
yq eval --null-input 'splitDoc'
```
will output
```yaml
@@ -26,7 +20,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | split_doc' sample.yml
yq eval '.[] | splitDoc' sample.yml
```
will output
```yaml
@@ -1,23 +1,10 @@
# String Operators
## RegEx
This uses golangs native regex functions under the hood - See their [docs](https://github.com/google/re2/wiki/Syntax) for the supported syntax.
This uses golangs native regex functions under the hood - See https://github.com/google/re2/wiki/Syntax for the supported syntax.
Case insensitive tip: prefix the regex with `(?i)` - e.g. `test("(?i)cats)"`.
### match(regEx)
This operator returns the substring match details of the given regEx.
### capture(regEx)
Capture returns named RegEx capture groups in a map. Can be more convenient than `match` depending on what you are doing.
## test(regEx)
Returns true if the string matches the RegEx, false otherwise.
## sub(regEx, replacement)
Substitutes matched substrings. The first parameter is the regEx to match substrings within the original string. The second is a what to replace those matches with. This can refer to capture groups from the first RegEx.
## String blocks, bash and newlines
# String blocks, bash and newlines
Bash is notorious for chomping on precious trailing newline characters, making it tricky to set strings with newlines properly. In particular, the `$( exp )` _will trim trailing newlines_.
For instance to get this yaml:
@@ -30,13 +17,13 @@ a: |
Using `$( exp )` wont work, as it will trim the trailing new line.
```
m=$(echo "cat\n") yq -n '.a = strenv(m)'
m=$(echo "cat\n") yq e -n '.a = strenv(m)'
a: cat
```
However, using printf works:
```
printf -v m "cat\n" ; m="$m" yq -n '.a = strenv(m)'
printf -v m "cat\n" ; m="$m" yq e -n '.a = strenv(m)'
a: |
cat
```
@@ -44,7 +31,7 @@ a: |
As well as having multiline expressions:
```
m="cat
" yq -n '.a = strenv(m)'
" yq e -n '.a = strenv(m)'
a: |
cat
```
@@ -53,47 +40,8 @@ Similarly, if you're trying to set the content from a file, and want a trailing
```
IFS= read -rd '' output < <(cat my_file)
output=$output ./yq '.data.values = strenv(output)' first.yml
output=$output ./yq e '.data.values = strenv(output)' first.yml
```
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## To up (upper) case
Works with unicode characters
Given a sample.yml file of:
```yaml
água
```
then
```bash
yq 'upcase' sample.yml
```
will output
```yaml
ÁGUA
```
## To down (lower) case
Works with unicode characters
Given a sample.yml file of:
```yaml
ÁgUA
```
then
```bash
yq 'downcase' sample.yml
```
will output
```yaml
água
```
## Join strings
Given a sample.yml file of:
```yaml
@@ -105,7 +53,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'join("; ")' sample.yml
yq eval 'join("; ")' sample.yml
```
will output
```yaml
@@ -119,7 +67,7 @@ foo bar foo
```
then
```bash
yq 'match("foo")' sample.yml
yq eval 'match("foo")' sample.yml
```
will output
```yaml
@@ -136,7 +84,7 @@ foo bar FOO
```
then
```bash
yq '[match("(?i)foo"; "g")]' sample.yml
yq eval '[match("(?i)foo"; "g")]' sample.yml
```
will output
```yaml
@@ -150,14 +98,14 @@ will output
captures: []
```
## Match with global capture group
## Match with capture groups
Given a sample.yml file of:
```yaml
abc abc
```
then
```bash
yq '[match("(ab)(c)"; "g")]' sample.yml
yq eval '[match("(abc)+"; "g")]' sample.yml
```
will output
```yaml
@@ -165,22 +113,16 @@ will output
offset: 0
length: 3
captures:
- string: ab
- string: abc
offset: 0
length: 2
- string: c
offset: 2
length: 1
length: 3
- string: abc
offset: 4
length: 3
captures:
- string: ab
- string: abc
offset: 4
length: 2
- string: c
offset: 6
length: 1
length: 3
```
## Match with named capture groups
@@ -190,7 +132,7 @@ foo bar foo foo foo
```
then
```bash
yq '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
yq eval '[match("foo (?P<bar123>bar)? foo"; "g")]' sample.yml
```
will output
```yaml
@@ -219,7 +161,7 @@ xyzzy-14
```
then
```bash
yq 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
yq eval 'capture("(?P<a>[a-z]+)-(?P<n>[0-9]+)")' sample.yml
```
will output
```yaml
@@ -234,7 +176,7 @@ cat cat
```
then
```bash
yq 'match("cat")' sample.yml
yq eval 'match("cat")' sample.yml
```
will output
```yaml
@@ -251,7 +193,7 @@ cat cat
```
then
```bash
yq '[match("cat"; "g")]' sample.yml
yq eval '[match("cat"; "g")]' sample.yml
```
will output
```yaml
@@ -266,7 +208,7 @@ will output
```
## Test using regex
Like jq's equivalent, this works like match but only returns true/false instead of full match details
Like jq'q equivalant, this works like match but only returns true/false instead of full match details
Given a sample.yml file of:
```yaml
@@ -275,7 +217,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[] | test("at")' sample.yml
yq eval '.[] | test("at")' sample.yml
```
will output
```yaml
@@ -293,7 +235,7 @@ a: dogs are great
```
then
```bash
yq '.a |= sub("dogs", "cats")' sample.yml
yq eval '.a |= sub("dogs", "cats")' sample.yml
```
will output
```yaml
@@ -311,7 +253,7 @@ b: heat
```
then
```bash
yq '.[] |= sub("(a)", "${1}r")' sample.yml
yq eval '.[] |= sub("(a)", "${1}r")' sample.yml
```
will output
```yaml
@@ -319,24 +261,6 @@ a: cart
b: heart
```
## Custom types: that are really strings
When custom tags are encountered, yq will try to decode the underlying type.
Given a sample.yml file of:
```yaml
a: !horse cat
b: !goat heat
```
then
```bash
yq '.[] |= sub("(a)", "${1}r")' sample.yml
```
will output
```yaml
a: !horse cart
b: !goat heart
```
## Split strings
Given a sample.yml file of:
```yaml
@@ -344,7 +268,7 @@ cat; meow; 1; ; true
```
then
```bash
yq 'split("; ")' sample.yml
yq eval 'split("; ")' sample.yml
```
will output
```yaml
@@ -362,7 +286,7 @@ word
```
then
```bash
yq 'split("; ")' sample.yml
yq eval 'split("; ")' sample.yml
```
will output
```yaml
@@ -1,13 +1,4 @@
# Style
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style)
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Update and set style of a particular node (simple)
Given a sample.yml file of:
```yaml
@@ -17,7 +8,7 @@ a:
```
then
```bash
yq '.a.b = "new" | .a.b style="double"' sample.yml
yq eval '.a.b = "new" | .a.b style="double"' sample.yml
```
will output
```yaml
@@ -27,6 +18,8 @@ a:
```
## Update and set style of a particular node using path variables
You can use a variable to re-use a path
Given a sample.yml file of:
```yaml
a:
@@ -35,7 +28,7 @@ a:
```
then
```bash
yq 'with(.a.b ; . = "new" | . style="double")' sample.yml
yq eval '.a.b as $x | $x = "new" | $x style="double"' sample.yml
```
will output
```yaml
@@ -54,7 +47,7 @@ e: true
```
then
```bash
yq '.. style="tagged"' sample.yml
yq eval '.. style="tagged"' sample.yml
```
will output
```yaml
@@ -75,7 +68,7 @@ e: true
```
then
```bash
yq '.. style="double"' sample.yml
yq eval '.. style="double"' sample.yml
```
will output
```yaml
@@ -95,7 +88,7 @@ e: true
```
then
```bash
yq '... style="double"' sample.yml
yq eval '... style="double"' sample.yml
```
will output
```yaml
@@ -115,7 +108,7 @@ e: true
```
then
```bash
yq '.. style="single"' sample.yml
yq eval '.. style="single"' sample.yml
```
will output
```yaml
@@ -135,7 +128,7 @@ e: true
```
then
```bash
yq '.. style="literal"' sample.yml
yq eval '.. style="literal"' sample.yml
```
will output
```yaml
@@ -159,7 +152,7 @@ e: true
```
then
```bash
yq '.. style="folded"' sample.yml
yq eval '.. style="folded"' sample.yml
```
will output
```yaml
@@ -183,7 +176,7 @@ e: true
```
then
```bash
yq '.. style="flow"' sample.yml
yq eval '.. style="flow"' sample.yml
```
will output
```yaml
@@ -202,7 +195,7 @@ a: cat
```
then
```bash
yq '... style=""' sample.yml
yq eval '... style=""' sample.yml
```
will output
```yaml
@@ -220,7 +213,7 @@ b: double
```
then
```bash
yq '.[] style |= .' sample.yml
yq eval '.[] style |= .' sample.yml
```
will output
```yaml
@@ -235,7 +228,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.. | style' sample.yml
yq eval '.. | style' sample.yml
```
will output
```yaml
+71
View File
@@ -0,0 +1,71 @@
## Number subtraction - float
If the lhs or rhs are floats then the expression will be calculated with floats.
Given a sample.yml file of:
```yaml
a: 3
b: 4.5
```
then
```bash
yq eval '.a = .a - .b' sample.yml
```
will output
```yaml
a: -1.5
b: 4.5
```
## Number subtraction - float
If the lhs or rhs are floats then the expression will be calculated with floats.
Given a sample.yml file of:
```yaml
a: 3
b: 4.5
```
then
```bash
yq eval '.a = .a - .b' sample.yml
```
will output
```yaml
a: -1.5
b: 4.5
```
## Number subtraction - int
If both the lhs and rhs are ints then the expression will be calculated with ints.
Given a sample.yml file of:
```yaml
a: 3
b: 4
```
then
```bash
yq eval '.a = .a - .b' sample.yml
```
will output
```yaml
a: -1
b: 4
```
## Decrement numbers
Given a sample.yml file of:
```yaml
a: 3
b: 5
```
then
```bash
yq eval '.[] -= 1' sample.yml
```
will output
```yaml
a: 2
b: 4
```
@@ -1,13 +1,4 @@
# Tag
The tag operator can be used to get or set the tag of nodes (e.g. `!!str`, `!!int`, `!!bool`).
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Get tag
Given a sample.yml file of:
```yaml
@@ -19,30 +10,7 @@ f: []
```
then
```bash
yq '.. | tag' sample.yml
```
will output
```yaml
!!map
!!str
!!int
!!float
!!bool
!!seq
```
## type is an alias for tag
Given a sample.yml file of:
```yaml
a: cat
b: 5
c: 3.2
e: true
f: []
```
then
```bash
yq '.. | type' sample.yml
yq eval '.. | tag' sample.yml
```
will output
```yaml
@@ -61,7 +29,7 @@ a: str
```
then
```bash
yq '.a tag = "!!mikefarah"' sample.yml
yq eval '.a tag = "!!mikefarah"' sample.yml
```
will output
```yaml
@@ -78,7 +46,7 @@ e: true
```
then
```bash
yq '(.. | select(tag == "!!int")) tag= "!!str"' sample.yml
yq eval '(.. | select(tag == "!!int")) tag= "!!str"' sample.yml
```
will output
```yaml
@@ -1,13 +1,4 @@
# Traverse (Read)
This is the simplest (and perhaps most used) operator, it is used to navigate deeply into yaml structures.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Simple map navigation
Given a sample.yml file of:
```yaml
@@ -16,7 +7,7 @@ a:
```
then
```bash
yq '.a' sample.yml
yq eval '.a' sample.yml
```
will output
```yaml
@@ -33,7 +24,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[]' sample.yml
yq eval '.[]' sample.yml
```
will output
```yaml
@@ -50,7 +41,7 @@ cat
```
then
```bash
yq '.[]' sample.yml
yq eval '.[]' sample.yml
```
will output
```yaml
@@ -65,7 +56,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.["{}"]' sample.yml
yq eval '.["{}"]' sample.yml
```
will output
```yaml
@@ -81,7 +72,7 @@ a:
```
then
```bash
yq '.a["key.withdots"]["another.key"]' sample.yml
yq eval '.a["key.withdots"]["another.key"]' sample.yml
```
will output
```yaml
@@ -97,7 +88,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.["red rabbit"]' sample.yml
yq eval '.["red rabbit"]' sample.yml
```
will output
```yaml
@@ -115,7 +106,7 @@ banana: soft yum
```
then
```bash
yq '.[.b]' sample.yml
yq eval '.[.b]' sample.yml
```
will output
```yaml
@@ -131,7 +122,7 @@ c: banana
```
then
```bash
yq '.a.b' sample.yml
yq eval '.a.b' sample.yml
```
will output
```yaml
@@ -149,7 +140,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.a?' sample.yml
yq eval '.a?' sample.yml
```
will output
```yaml
@@ -164,7 +155,7 @@ a:
```
then
```bash
yq '.a."*a*"' sample.yml
yq eval '.a."*a*"' sample.yml
```
will output
```yaml
@@ -181,7 +172,7 @@ b: *cat
```
then
```bash
yq '.b' sample.yml
yq eval '.b' sample.yml
```
will output
```yaml
@@ -197,7 +188,7 @@ b: *cat
```
then
```bash
yq '.b[]' sample.yml
yq eval '.b[]' sample.yml
```
will output
```yaml
@@ -213,7 +204,7 @@ b: *cat
```
then
```bash
yq '.b.c' sample.yml
yq eval '.b.c' sample.yml
```
will output
```yaml
@@ -229,7 +220,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[0]' sample.yml
yq eval '.[0]' sample.yml
```
will output
```yaml
@@ -243,7 +234,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[1][0]' sample.yml
yq eval '.[1][0]' sample.yml
```
will output
```yaml
@@ -257,7 +248,7 @@ Given a sample.yml file of:
```
then
```bash
yq '.[2]' sample.yml
yq eval '.[2]' sample.yml
```
will output
```yaml
@@ -271,7 +262,7 @@ a: b
```
then
```bash
yq '.[0]' sample.yml
yq eval '.[0]' sample.yml
```
will output
```yaml
@@ -302,7 +293,7 @@ foobar:
```
then
```bash
yq '.foobar.a' sample.yml
yq eval '.foobar.a' sample.yml
```
will output
```yaml
@@ -333,7 +324,7 @@ foobar:
```
then
```bash
yq '.foobar.c' sample.yml
yq eval '.foobar.c' sample.yml
```
will output
```yaml
@@ -364,7 +355,7 @@ foobar:
```
then
```bash
yq '.foobar.thing' sample.yml
yq eval '.foobar.thing' sample.yml
```
will output
```yaml
@@ -395,7 +386,7 @@ foobar:
```
then
```bash
yq '.foobar[]' sample.yml
yq eval '.foobar[]' sample.yml
```
will output
```yaml
@@ -430,7 +421,7 @@ foobar:
```
then
```bash
yq '.foobarList.thing' sample.yml
yq eval '.foobarList.thing' sample.yml
```
will output
```yaml
@@ -461,7 +452,7 @@ foobar:
```
then
```bash
yq '.foobarList[]' sample.yml
yq eval '.foobarList[]' sample.yml
```
will output
```yaml
@@ -481,7 +472,7 @@ a:
```
then
```bash
yq '.a[0, 2]' sample.yml
yq eval '.a[0, 2]' sample.yml
```
will output
```yaml
@@ -1,17 +1,8 @@
# Union
This operator is used to combine different results together.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
## Combine scalars
Running
```bash
yq --null-input '1, true, "cat"'
yq eval --null-input '1, true, "cat"'
```
will output
```yaml
@@ -29,7 +20,7 @@ c: fieldC
```
then
```bash
yq '.a, .c' sample.yml
yq eval '.a, .c' sample.yml
```
will output
```yaml
@@ -1,32 +1,21 @@
# Unique
This is used to filter out duplicated items in an array. Note that the original order of the array is maintained.
{% hint style="warning" %}
Note that versions prior to 4.18 require the 'eval/e' command to be specified.&#x20;
`yq e <exp> <file>`
{% endhint %}
This is used to filter out duplicated items in an array.
## Unique array of scalars (string/numbers)
Note that unique maintains the original order of the array.
Given a sample.yml file of:
```yaml
- 2
- 1
- 2
- 3
- 2
```
then
```bash
yq 'unique' sample.yml
yq eval 'unique' sample.yml
```
will output
```yaml
- 2
- 1
- 2
- 3
```
@@ -42,7 +31,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'unique' sample.yml
yq eval 'unique' sample.yml
```
will output
```yaml
@@ -62,7 +51,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'unique_by(tag)' sample.yml
yq eval 'unique_by(tag)' sample.yml
```
will output
```yaml
@@ -81,7 +70,7 @@ Given a sample.yml file of:
```
then
```bash
yq 'unique_by(.name)' sample.yml
yq eval 'unique_by(.name)' sample.yml
```
will output
```yaml
+58
View File
@@ -0,0 +1,58 @@
For more complex scenarios, variables can be used to hold values of expression to be used in other expressions.
## Single value variable
Given a sample.yml file of:
```yaml
a: cat
```
then
```bash
yq eval '.a as $foo | $foo' sample.yml
```
will output
```yaml
cat
```
## Multi value variable
Given a sample.yml file of:
```yaml
- cat
- dog
```
then
```bash
yq eval '.[] as $foo | $foo' sample.yml
```
will output
```yaml
cat
dog
```
## Using variables as a lookup
Example taken from [jq](https://stedolan.github.io/jq/manual/#Variable/SymbolicBindingOperator:...as$identifier|...)
Given a sample.yml file of:
```yaml
"posts":
- "title": Frist psot
"author": anon
- "title": A well-written article
"author": person1
"realnames":
"anon": Anonymous Coward
"person1": Person McPherson
```
then
```bash
yq eval '.realnames as $names | .posts[] | {"title":.title, "author": $names[.author]}' sample.yml
```
will output
```yaml
title: Frist psot
author: Anonymous Coward
title: A well-written article
author: Person McPherson
```

Some files were not shown because too many files have changed in this diff Show More