Compare commits

..
Author SHA1 Message Date
Mike Farah e918bec740 fixed leading content logic 2022-10-28 13:50:22 +11:00
Mike Farah b87c1503f4 wip 2022-10-27 16:16:00 +11:00
Mike Farah fd79ac8603 put comments on key node instead 2022-10-27 15:27:37 +11:00
Mike Farah 7eccbe5902 put comments on key node instead 2022-10-26 13:24:36 +11:00
Mike Farah fe27ddedc0 fixing property comment handling 2022-10-26 13:12:30 +11:00
Mike Farah 23b2aa5668 fixing property comment handling 2022-10-26 13:12:30 +11:00
Mike Farah 2e588a11a0 moving leading content processing logic into yaml decoder 2022-10-26 13:12:30 +11:00
Mike Farah 4138c3b005 wip 2022-10-26 13:12:30 +11:00
227 changed files with 975 additions and 7847 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+3 -3
View File
@@ -14,16 +14,16 @@ jobs:
IMAGE_NAME: mikefarah/yq
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v2
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v2
with:
version: latest
+4 -4
View File
@@ -10,14 +10,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v4
- name: Set up Go 1.19
uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: 1.19
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Get dependencies
run: |
+6 -5
View File
@@ -9,19 +9,20 @@ jobs:
publishGitRelease:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: '^1.20'
go-version: '^1.19'
check-latest: true
- 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 "VERSION=${GITHUB_REF##*/}" >> "${GITHUB_OUTPUT}"
run: echo ::set-output name=VERSION::${GITHUB_REF##*/}
- name: Generate man page
uses: docker://pandoc/core:2.14.2
@@ -35,7 +36,7 @@ jobs:
--variable=header:"yq (https://github.com/mikefarah/yq/) version ${{ steps.get_version.outputs.VERSION }}"
--variable=author:"Mike Farah"
--output=yq.1
man.md
${{ steps.gen-man-page-md.outputs.man-page-md }}
- name: Cross compile
run: |
-23
View File
@@ -1,23 +0,0 @@
name: Release Snap
on:
release:
types: [released]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
buildSnap:
environment: snap
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: snapcore/action-build@v1
id: build
- uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.STORE_LOGIN }}
with:
snap: ${{ steps.build.outputs.snap }}
release: stable
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Get test
id: get_value
uses: mikefarah/yq@master
-2
View File
@@ -41,8 +41,6 @@ yq*.snap
test.yml
test*.yml
test*.xml
test*.toml
test*.yaml
0.yml
1.yml
+2 -2
View File
@@ -1,6 +1,6 @@
# Development
1. Install (Golang)[https://golang.org/]
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
2. Run `make [local] test` to ensure you can run the existing tests
@@ -12,7 +12,7 @@
# Documentation
The documentation is a bit of a mixed bag (sorry in advance, I do plan on simplifying it...) - with some parts automatically generated and stiched together and some statically defined.
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.
+2 -2
View File
@@ -1,10 +1,10 @@
FROM golang:1.21.1 as builder
FROM golang:1.19.2 as builder
WORKDIR /go/src/mikefarah/yq
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-s -w" .
RUN CGO_ENABLED=0 go build .
# RUN ./scripts/test.sh -- this too often times out in the github pipeline.
RUN ./scripts/acceptance.sh
+1 -1
View File
@@ -1,4 +1,4 @@
FROM golang:1.21.1
FROM golang:1.19.2
COPY scripts/devtools.sh /opt/devtools.sh
+1 -5
View File
@@ -84,12 +84,8 @@ format: vendor
${ENGINERUN} bash ./scripts/format.sh
.PHONY: spelling
spelling: format
${ENGINERUN} bash ./scripts/spelling.sh
.PHONY: secure
secure: spelling
secure: format
${ENGINERUN} bash ./scripts/secure.sh
.PHONY: check
-1
View File
@@ -7,7 +7,6 @@ export GIT_DESCRIBE = $(shell git describe --tags --always)
LDFLAGS :=
LDFLAGS += -X main.GitCommit=${GIT_COMMIT}${GIT_DIRTY}
LDFLAGS += -X main.GitDescribe=${GIT_DESCRIBE}
LDFLAGS += -w -s
GITHUB_TOKEN ?=
+23 -29
View File
@@ -19,7 +19,7 @@ Pipe from STDIN:
yq '.a.b[0].c' < file.yaml
```
Update a yaml file, in place
Update a yaml file, inplace
```bash
yq -i '.a.b[0].c = "cool"' file.yaml
```
@@ -45,17 +45,12 @@ yq -i '
' file.yaml
```
Find and update an item in an array:
```bash
yq '(.[] | select(.name == "foo") | .address) = "12 cat st"'
```
Convert JSON to YAML
```bash
yq -Poy sample.json
yq -P sample.json
```
See [recipes](https://mikefarah.gitbook.io/yq/recipes) for more examples and the [documentation](https://mikefarah.gitbook.io/yq/) for more information.
See the [documentation](https://mikefarah.gitbook.io/yq/) for more examples.
Take a look at the discussions for [common questions](https://github.com/mikefarah/yq/discussions/categories/q-a), and [cool ideas](https://github.com/mikefarah/yq/discussions/categories/show-and-tell)
@@ -66,9 +61,6 @@ Take a look at the discussions for [common questions](https://github.com/mikefar
### wget
Use wget to download, gzipped pre-compiled binaries:
For instance, VERSION=v4.2.0 and BINARY=yq_linux_amd64
#### Compressed via tar.gz
```bash
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\
@@ -82,7 +74,9 @@ wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /
chmod +x /usr/bin/yq
```
#### Latest version
For instance, VERSION=v4.2.0 and BINARY=yq_linux_amd64
Use VERSION=latest to always get the latest version:
```bash
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq &&\
@@ -234,8 +228,6 @@ go install github.com/mikefarah/yq/v4@latest
## Community Supported Installation methods
As these are supported by the community :heart: - however, they may be out of date with the officially supported releases.
_Please note that the Debian package (previously supported by @rmescandon) is no longer maintained. Please use an alternative installation method._
### Nix
@@ -262,9 +254,6 @@ pacman -S go-yq
```
### Windows:
Using [Chocolatey](https://chocolatey.org)
[![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)
```
@@ -272,15 +261,12 @@ choco install yq
```
Supported by @chillum (https://chocolatey.org/packages/yq)
Using [scoop](https://scoop.sh/)
```
scoop install main/yq
```
and
Using [winget](https://learn.microsoft.com/en-us/windows/package-manager/)
```
winget install --id MikeFarah.yq
```
### Winget
winget install yq
https://winget.run/pkg/MikeFarah/yq
### Mac:
Using [MacPorts](https://www.macports.org/)
@@ -299,6 +285,15 @@ Supported by Tuan Hoang
https://pkgs.alpinelinux.org/package/edge/community/x86/yq
### On Ubuntu 16.04 or higher from Debian package:
```sh
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CC86BB64
sudo add-apt-repository ppa:rmescandon/yq
sudo apt update
sudo apt install yq -y
```
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
@@ -310,7 +305,7 @@ https://pkgs.alpinelinux.org/package/edge/community/x86/yq
- [Deeply data structures](https://mikefarah.gitbook.io/yq/operators/traverse-read)
- [Sort 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 in place](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
- [Update 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)
@@ -337,7 +332,7 @@ 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 in place
yq -i '.stuff = "foo"' myfile.yml # update myfile.yml inplace
Available Commands:
@@ -354,7 +349,7 @@ Flags:
--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 in place of first file given.
-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 (---)
@@ -373,6 +368,5 @@ 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)
- "yes", "no" were dropped as boolean values in the yaml 1.2 standard - which is the standard yq assumes.
See [tips and tricks](https://mikefarah.gitbook.io/yq/usage/tips-and-tricks) for more common problems and solutions.
+4 -4
View File
@@ -3,25 +3,25 @@
testWriteInPlacePipeIn() {
result=$(./yq e -i -n '.a' 2>&1)
assertEquals 1 $?
assertEquals "Error: write in place flag only applicable when giving an expression and at least one file" "$result"
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 in place flag only applicable when giving an expression and at least one file" "$result"
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 in place cannot be used with split file" "$result"
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 in place cannot be used with split file" "$result"
assertEquals "Error: write inplace cannot be used with split file" "$result"
}
testNullWithFiles() {
+3 -3
View File
@@ -143,7 +143,7 @@ testBasicCatWithFilesNoDash() {
}
# when the nullinput flag is used
# don't automatically read STDIN (this breaks github actions)
# dont automatically read STDIN (this breaks github actions)
testBasicCreateFileGithubAction() {
cat /dev/null | ./yq -n ".a = 123" > test.yml
}
@@ -302,7 +302,7 @@ testBasicExitStatusNoEval() {
assertEquals 1 "$?"
}
testBasicExtractFieldWithSeparator() {
testBasicExtractFieldWithSeperator() {
cat >test.yml <<EOL
---
name: chart-name
@@ -312,7 +312,7 @@ EOL
assertEquals "chart-name" "$X"
}
testBasicExtractMultipleFieldWithSeparator() {
testBasicExtractMultipleFieldWithSeperator() {
cat >test.yml <<EOL
---
name: chart-name
-249
View File
@@ -1,249 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml 2>/dev/null || true
rm test*.toml 2>/dev/null || true
rm test*.tfstate 2>/dev/null || true
rm test*.json 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
}
testInputJson() {
cat >test.json <<EOL
{ "mike" : { "things": "cool" } }
EOL
read -r -d '' expected << EOM
{
"mike": {
"things": "cool"
}
}
EOM
X=$(./yq test.json)
assertEquals "$expected" "$X"
X=$(./yq ea test.json)
assertEquals "$expected" "$X"
}
testInputToml() {
cat >test.toml <<EOL
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
EOL
read -r -d '' expected << EOM
owner:
name: Tom Preston-Werner
dob: 1979-05-27T07:32:00-08:00
EOM
X=$(./yq -oy test.toml)
assertEquals "$expected" "$X"
X=$(./yq ea -oy test.toml)
assertEquals "$expected" "$X"
}
testInputTfstate() {
cat >test.tfstate <<EOL
{ "mike" : { "things": "cool" } }
EOL
read -r -d '' expected << EOM
{"mike": {"things": "cool"}}
EOM
X=$(./yq test.tfstate)
assertEquals "$expected" "$X"
X=$(./yq ea test.tfstate)
assertEquals "$expected" "$X"
}
testInputJsonOutputYaml() {
cat >test.json <<EOL
{ "mike" : { "things": "cool" } }
EOL
read -r -d '' expected << EOM
mike:
things: cool
EOM
X=$(./yq test.json -oy)
assertEquals "$expected" "$X"
X=$(./yq ea test.json -oy)
assertEquals "$expected" "$X"
}
testInputProperties() {
cat >test.properties <<EOL
mike.things = hello
EOL
read -r -d '' expected << EOM
mike.things = hello
EOM
X=$(./yq e test.properties)
assertEquals "$expected" "$X"
X=$(./yq test.properties)
assertEquals "$expected" "$X"
X=$(./yq ea 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 test.properties)
assertEquals "$expected" "$X"
X=$(cat /dev/null | ./yq ea test.properties)
assertEquals "$expected" "$X"
}
testInputCSV() {
cat >test.csv <<EOL
fruit,yumLevel
apple,5
banana,4
EOL
read -r -d '' expected << EOM
fruit,yumLevel
apple,5
banana,4
EOM
X=$(./yq e test.csv)
assertEquals "$expected" "$X"
X=$(./yq ea test.csv)
assertEquals "$expected" "$X"
}
testInputCSVUTF8() {
read -r -d '' expected << EOM
id,first,last
1,john,smith
1,jane,smith
EOM
X=$(./yq utf8.csv)
assertEquals "$expected" "$X"
}
testInputTSV() {
cat >test.tsv <<EOL
fruit yumLevel
apple 5
banana 4
EOL
read -r -d '' expected << EOM
fruit yumLevel
apple 5
banana 4
EOM
X=$(./yq e test.tsv)
assertEquals "$expected" "$X"
X=$(./yq ea test.tsv)
assertEquals "$expected" "$X"
}
testInputXml() {
cat >test.xml <<EOL
<cat legs="4">BiBi</cat>
EOL
read -r -d '' expected << EOM
<cat legs="4">BiBi</cat>
EOM
X=$(./yq e test.xml)
assertEquals "$expected" "$X"
X=$(./yq ea test.xml)
assertEquals "$expected" "$X"
}
testInputXmlNamespaces() {
cat >test.xml <<EOL
<?xml version="1.0"?>
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
</map>
EOL
read -r -d '' expected << EOM
<?xml version="1.0"?>
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url"></map>
EOM
X=$(./yq e test.xml)
assertEquals "$expected" "$X"
X=$(./yq ea test.xml)
assertEquals "$expected" "$X"
}
testInputXmlStrict() {
cat >test.xml <<EOL
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY writer "Catherine.">
<!ENTITY copyright "(r) Great">
]>
<root>
<item>&writer;&copyright;</item>
</root>
EOL
X=$(./yq --xml-strict-mode test.xml 2>&1)
assertEquals 1 $?
assertEquals "Error: bad file 'test.xml': XML syntax error on line 7: invalid character entity &writer;" "$X"
X=$(./yq ea --xml-strict-mode test.xml 2>&1)
assertEquals "Error: bad file 'test.xml': XML syntax error on line 7: invalid character entity &writer;" "$X"
}
testInputXmlGithubAction() {
cat >test.xml <<EOL
<cat legs="4">BiBi</cat>
EOL
read -r -d '' expected << EOM
<cat legs="4">BiBi</cat>
EOM
X=$(cat /dev/null | ./yq e test.xml)
assertEquals "$expected" "$X"
X=$(cat /dev/null | ./yq ea test.xml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2
+8 -8
View File
@@ -109,7 +109,7 @@ EOL
read -r -d '' expected << EOM
cat:
+content: BiBi
+@legs: "4"
+legs: "4"
EOM
X=$(./yq e -p=xml test.yml)
@@ -120,7 +120,7 @@ EOM
}
testInputXmlNamespaces() {
cat >test.xml <<EOL
cat >test.yml <<EOL
<?xml version="1.0"?>
<map xmlns="some-namespace" xmlns:xsi="some-instance" xsi:schemaLocation="some-url">
</map>
@@ -129,15 +129,15 @@ EOL
read -r -d '' expected << EOM
+p_xml: version="1.0"
map:
+@xmlns: some-namespace
+@xmlns:xsi: some-instance
+@xsi:schemaLocation: some-url
+xmlns: some-namespace
+xmlns:xsi: some-instance
+xsi:schemaLocation: some-url
EOM
X=$(./yq e -p=xml test.xml)
X=$(./yq e -p=xml test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -p=xml test.xml)
X=$(./yq ea -p=xml test.yml)
assertEquals "$expected" "$X"
}
@@ -190,7 +190,7 @@ EOL
read -r -d '' expected << EOM
cat:
+content: BiBi
+@legs: "4"
+legs: "4"
EOM
X=$(cat /dev/null | ./yq e -p=xml test.yml)
@@ -11,7 +11,7 @@ a: test
EOL
}
testLeadingSeparatorWithDoc() {
testLeadingSeperatorWithDoc() {
cat >test.yml <<EOL
# hi peeps
# cool
@@ -34,94 +34,18 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorWithNewlinesNewDoc() {
cat >test.yml <<EOL
# hi peeps
# cool
---
a: test
---
b: cool
EOL
read -r -d '' expected << EOM
# hi peeps
# cool
---
a: thing
---
b: cool
EOM
X=$(./yq e '(select(di == 0) | .a) = "thing"' - < test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorWithNewlinesMoreComments() {
cat >test.yml <<EOL
# hi peeps
# cool
---
# great
a: test
---
b: cool
EOL
read -r -d '' expected << EOM
# hi peeps
# cool
---
# great
a: thing
---
b: cool
EOM
X=$(./yq e '(select(di == 0) | .a) = "thing"' - < test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorWithDirective() {
cat >test.yml <<EOL
%YAML 1.1
---
this: should really work
EOL
read -r -d '' expected << EOM
%YAML 1.1
---
this: should really work
EOM
X=$(./yq < test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorPipeIntoEvalSeq() {
testLeadingSeperatorPipeIntoEvalSeq() {
X=$(./yq e - < test.yml)
expected=$(cat test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorExtractField() {
testLeadingSeperatorExtractField() {
X=$(./yq e '.a' - < test.yml)
assertEquals "test" "$X"
}
testLeadingSeparatorExtractFieldWithCommentsAfterSep() {
testLeadingSeperatorExtractFieldWithCommentsAfterSep() {
cat >test.yml <<EOL
---
# hi peeps
@@ -132,7 +56,7 @@ EOL
assertEquals "test" "$X"
}
testLeadingSeparatorExtractFieldWithCommentsBeforeSep() {
testLeadingSeperatorExtractFieldWithCommentsBeforeSep() {
cat >test.yml <<EOL
# hi peeps
# cool
@@ -144,7 +68,7 @@ EOL
}
testLeadingSeparatorExtractFieldMultiDoc() {
testLeadingSeperatorExtractFieldMultiDoc() {
cat >test.yml <<EOL
---
a: test
@@ -161,13 +85,13 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorExtractFieldMultiDocWithComments() {
testLeadingSeperatorExtractFieldMultiDocWithComments() {
cat >test.yml <<EOL
# here
---
# there
a: test
# wherever
# whereever
---
# you are
a: test2
@@ -184,26 +108,26 @@ EOM
}
testLeadingSeparatorEvalSeq() {
testLeadingSeperatorEvalSeq() {
X=$(./yq e test.yml)
expected=$(cat test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorPipeIntoEvalAll() {
testLeadingSeperatorPipeIntoEvalAll() {
X=$(./yq ea - < test.yml)
expected=$(cat test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorEvalAll() {
testLeadingSeperatorEvalAll() {
X=$(./yq ea test.yml)
expected=$(cat test.yml)
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalSimple() {
testLeadingSeperatorMultiDocEvalSimple() {
read -r -d '' expected << EOM
---
a: test
@@ -217,7 +141,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocInOneFile() {
testLeadingSeperatorMultiDocInOneFile() {
cat >test.yml <<EOL
---
# hi peeps
@@ -231,7 +155,7 @@ EOL
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocInOneFileEvalAll() {
testLeadingSeperatorMultiDocInOneFileEvalAll() {
cat >test.yml <<EOL
---
# hi peeps
@@ -245,7 +169,7 @@ EOL
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalComments() {
testLeadingSeperatorMultiDocEvalComments() {
cat >test.yml <<EOL
# hi peeps
# cool
@@ -273,7 +197,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalCommentsTrailingSep() {
testLeadingSeperatorMultiDocEvalCommentsTrailingSep() {
cat >test.yml <<EOL
# hi peeps
# cool
@@ -305,7 +229,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiMultiDocEvalCommentsTrailingSep() {
testLeadingSeperatorMultiMultiDocEvalCommentsTrailingSep() {
cat >test.yml <<EOL
# hi peeps
# cool
@@ -345,7 +269,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalCommentsLeadingSep() {
testLeadingSeperatorMultiDocEvalCommentsLeadingSep() {
cat >test.yml <<EOL
---
# hi peeps
@@ -405,7 +329,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalCommentsStripComments() {
testLeadingSeperatorMultiDocEvalCommentsStripComments() {
cat >test.yml <<EOL
---
# hi peeps
@@ -428,7 +352,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalCommentsLeadingSepNoDocFlag() {
testLeadingSeperatorMultiDocEvalCommentsLeadingSepNoDocFlag() {
cat >test.yml <<EOL
---
# hi peeps
@@ -454,7 +378,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalJsonFlag() {
testLeadingSeperatorMultiDocEvalJsonFlag() {
cat >test.yml <<EOL
---
# hi peeps
@@ -483,7 +407,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalAllJsonFlag() {
testLeadingSeperatorMultiDocEvalAllJsonFlag() {
cat >test.yml <<EOL
---
# hi peeps
@@ -512,7 +436,7 @@ EOM
assertEquals "$expected" "$X"
}
testLeadingSeparatorMultiDocEvalAll() {
testLeadingSeperatorMultiDocEvalAll() {
read -r -d '' expected << EOM
---
a: test
-286
View File
@@ -1,286 +0,0 @@
#!/bin/bash
setUp() {
rm test*.yml || true
}
## Convenient bash shortcut to read records of NUL separated values
## from stdin the safe way. See example usage in the next tests.
read-0() {
local eof="" IFS=''
while [ "$1" ]; do
## - The `-r` avoids bad surprise with '\n' and other interpreted
## sequences that can be read.
## - The `-d ''` is the (strange?) way to refer to NUL delimiter.
## - The `--` is how to avoid unpleasant surprises if your
## "$1" starts with "-" (minus) sign. This protection also
## will produce a readable error if you want to try to start
## your variable names with a "-".
read -r -d '' -- "$1" || eof=1
shift
done
[ -z "$eof" ] ## fail on EOF
}
## Convenient bash shortcut to be used with the next function `p-err`
## to read NUL separated values the safe way AND catch any errors from
## the process creating the stream of NUL separated data. See example
## usage in the tests.
read-0-err() {
local ret="$1" eof="" idx=0 last=
read -r -- "${ret?}" <<<"0"
shift
while [ "$1" ]; do
last=$idx
read -r -d '' -- "$1" || {
## Put this last value in ${!ret}
eof="$1"
read -r -- "$ret" <<<"${!eof}"
break
}
((idx++))
shift
done
[ -z "$eof" ] || {
if [ "$last" != 0 ]; then
## Uhoh, we have no idea if the errorlevel of the internal
## command was properly delimited with a NUL char, and
## anyway something went really wrong at least about the
## number of fields separated by NUL char and the one
## expected.
echo "Error: read-0-err couldn't fill all value $ret = '${!ret}', '$eof', '${!eof}'" >&2
read -r -- "$ret" <<<"not-enough-values"
else
if ! [[ "${!ret}" =~ ^[0-9]+$ && "${!ret}" -ge 0 && "${!ret}" -le 127 ]]; then
## This could happen if you don't use `p-err` wrapper,
## or used stdout in unexpected ways in your inner
## command.
echo "Error: last value is not a number, did you finish with an errorlevel ?" >&2
read -r -- "$ret" <<<"last-value-not-a-number"
fi
fi
false
}
}
## Simply runs command given as argument and adds errorlevel in the
## standard output. Is expected to be used in tandem with
## `read-0-err`.
p-err() {
local exp="$1"
"$@"
printf "%s" "$?"
}
wyq-r() {
local exp="$1"
./yq e -0 -r=false "$1"
printf "%s" "$?"
}
testBasicUsageRaw() {
cat >test.yml <<EOL
a: foo
b: bar
EOL
printf "foo\0bar\0" > expected.out
## We need to compare binary content here. We have to filter the compared
## content through a representation that gets rid of NUL chars but accurately
## transcribe the content.
## Also as it would be nice to have a pretty output in case the test fails,
## we use here 'hd': a widely available shortcut to 'hexdump' that will
## pretty-print any binary to it's hexadecimal representation.
##
## Note that the standard `assertEquals` compare its arguments
## value, but they can't hold NUL characters (this comes from the
## limitation of the C API of `exec*(..)` functions that requires
## `const char *arv[]`). And these are NUL terminated strings. As a
## consequence, the NUL characters gets removed in bash arguments.
assertEquals "$(hd expected.out)" \
"$(./yq e -0 '.a, .b' test.yml | hd)"
rm expected.out
}
testBasicUsage() {
local a b
cat >test.yml <<EOL
a: foo
b: bar
EOL
## We provide 2 values, and ask to fill 2 variables.
read-0 a b < <(./yq e -0 '.a, .b' test.yml)
assertEquals "$?" "0" ## Everything is fine
assertEquals "foo" "$a" ## Values are correctly parsed
assertEquals "bar" "$b"
a=YYY ; b=XXX
## Not enough values provided to fill `a` and `b`.
read-0 a b < <(./yq e -0 '.a' test.yml)
assertEquals "$?" "1" ## An error was emitted
assertEquals "foo" "$a" ## First value was correctly parsed
assertEquals "" "$b" ## Second was still reset
## Error from inner command are not catchable !. Use
## `read-0-err`/`p-err` for that.
read-0 a < <(printf "\0"; ./yq e -0 'xxx' test.yml; )
assertEquals "$?" "0"
}
testBasicUsageJson() {
cat >test.yml <<EOL
a:
x: foo
b: bar
EOL
read-0 a b < <(./yq e -0 -o=json '.a, .b' test.yml)
assertEquals '{
"x": "foo"
}' "$a"
assertEquals '"bar"' "$b"
}
testFailWithValueContainingNUL() {
local a b c
## Note that value of field 'a' actually contains a NUL char !
cat >test.yml <<EOL
a: "foo\u0000bar"
b: 1
c: |
wiz
boom
EOL
## We are looking for trouble with asking to separated fields with NUL
## char and requested value `.a` actually contains itself a NUL char !
read-0 a b c < <(./yq e -0 '.a, .b, .c' test.yml)
assertNotEquals "0" "$?" ## read-0 failed to fill all values
## But here, we can request for one value, even if `./yq` fails
read-0 b < <(./yq e -0 '.b, .a' test.yml)
assertEquals "0" "$?" ## read-0 succeeds at feeding the first value
## Note: to catch the failure of `yq`, see in the next tests the usage
## of `read-0-err`.
## using -r=false solves any NUL containing value issues, but keeps
## all in YAML representation:
read-0 a b c < <(./yq e -0 -r=false '.a, .b, .c' test.yml)
assertEquals "0" "$?" ## All goes well despite asking for `a` value
assertEquals '"foo\0bar"' "$a" ## This is a YAML string representation
assertEquals '1' "$b"
assertEquals '|
wiz
boom' "$c"
}
testStandardLoop() {
local E a b res
## Here everything is normal: 4 values, that will be paired
## in key/values.
cat >test.yml <<EOL
- yay
- wiz
- hop
- pow
EOL
res=""
while read-0-err E a b; do
res+="$a: $b;"
done < <(p-err ./yq -0 '.[]' test.yml)
assertEquals "0" "$E" ## errorlevel of internal command
assertEquals "yay: wiz;hop: pow;" "$res" ## expected result
}
testStandardLoopWithoutEnoughValues() {
local E a b res
## Here 5 values, there will be a missing value when reading
## pairs of value.
cat >test.yml <<EOL
- yay
- wiz
- hop
- pow
- kwak
EOL
res=""
## The loop will succeed 2 times then fail
while read-0-err E a b; do
res+="$a: $b;"
done < <(p-err ./yq -0 '.[]' test.yml)
assertEquals "not-enough-values" "$E" ## Not enough value error
assertEquals "yay: wiz;hop: pow;" "$res" ## the 2 full key/value pairs
}
testStandardLoopWithInternalCmdError() {
local E a b res
## Note the third value contains a NUL char !
cat >test.yml <<EOL
- yay
- wiz
- "foo\0bar"
- hop
- pow
EOL
res=""
## It should be only upon the second pass in the loop that
## read-0-err will catch the fact that there is an error !
while read-0-err E a b; do
res+="$a: $b;"
done < <(p-err ./yq -0 '.[]' test.yml)
assertEquals "1" "$E" ## Internal command errorlevel (from `./yq`)
assertEquals "yay: wiz;" "$res" ## first 2 values were ok at least
}
testStandardLoopNotEnoughErrorEatsCmdError() {
local E a b res
## Because of possible edge cases where the internal errorlevel
## reported by `p-err` in the standard output might be mangled
## with the unfinished record, `read-0-err E ...` will NOT report
## the internal command error in the variable E and instead will
## store the value 'not-enough-values'. In real world, anyway, you
## will want to react the same if the internal command failed
## and/or you didn't get as much values as expected while
## reading. Keep in mind also that standard error is not
## swallowed, so you can read reports from the inner command AND
## from `read-0-err`.
## Here, note that the fourth value contains a NUL char !
cat >test.yml <<EOL
- yay
- wiz
- hop
- "foo\0bar"
- pow
EOL
res=""
## It should be only upon the second loop that read-0-err will catch
## the fact that there are not enough data to fill the requested variables
while read-0-err E a b; do
res+="$a: $b;"
done < <(p-err ./yq -0 '.[]' test.yml)
assertEquals "not-enough-values" "$E" ## Not enough values error eats internal error !
assertEquals "yay: wiz;" "$res" ## first 2 values were ok at least
}
source ./scripts/shunit2
+5 -71
View File
@@ -48,55 +48,6 @@ EOM
assertEquals "$expected" "$X"
}
testOutputYamlRawDefault() {
cat >test.yml <<EOL
a: "cat"
EOL
X=$(./yq e '.a' test.yml)
assertEquals "cat" "$X"
X=$(./yq ea '.a' test.yml)
assertEquals "cat" "$X"
}
testOutputYamlRawOff() {
cat >test.yml <<EOL
a: "cat"
EOL
X=$(./yq e -r=false '.a' test.yml)
assertEquals "\"cat\"" "$X"
X=$(./yq ea -r=false '.a' test.yml)
assertEquals "\"cat\"" "$X"
}
testOutputJsonRaw() {
cat >test.yml <<EOL
a: cat
EOL
X=$(./yq e -r --output-format=json '.a' test.yml)
assertEquals "cat" "$X"
X=$(./yq ea -r --output-format=json '.a' test.yml)
assertEquals "cat" "$X"
}
testOutputJsonDefault() {
cat >test.yml <<EOL
a: cat
EOL
X=$(./yq e --output-format=json '.a' test.yml)
assertEquals "\"cat\"" "$X"
X=$(./yq ea --output-format=json '.a' test.yml)
assertEquals "\"cat\"" "$X"
}
testOutputJsonShort() {
cat >test.yml <<EOL
a: {b: ["cat"]}
@@ -121,11 +72,11 @@ EOM
testOutputProperties() {
cat >test.yml <<EOL
a: {b: {c: ["cat cat"]}}
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
a.b.c.0 = cat cat
a.b.c.0 = cat
EOM
X=$(./yq e --output-format=props test.yml)
@@ -135,30 +86,13 @@ EOM
assertEquals "$expected" "$X"
}
testOutputPropertiesDontUnwrap() {
cat >test.yml <<EOL
a: {b: {c: ["cat cat"]}}
EOL
read -r -d '' expected << EOM
a.b.c.0 = "cat cat"
EOM
X=$(./yq e -r=false --output-format=props test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -r=false --output-format=props test.yml)
assertEquals "$expected" "$X"
}
testOutputPropertiesShort() {
cat >test.yml <<EOL
a: {b: {c: ["cat cat"]}}
a: {b: {c: ["cat"]}}
EOL
read -r -d '' expected << EOM
a.b.c.0 = cat cat
a.b.c.0 = cat
EOM
X=$(./yq e -o=p test.yml)
@@ -252,7 +186,7 @@ EOM
testOutputXmComplex() {
cat >test.yml <<EOL
a: {b: {c: ["cat", "dog"], +@f: meow}}
a: {b: {c: ["cat", "dog"], +f: meow}}
EOL
read -r -d '' expected << EOM
+3 -8
View File
@@ -1,15 +1,11 @@
package cmd
var unwrapScalarFlag = newUnwrapFlag()
var unwrapScalar = false
var unwrapScalar = true
var writeInplace = false
var outputToJSON = false
var outputFormat = ""
var inputFormat = ""
var outputFormat = "yaml"
var inputFormat = "yaml"
var exitStatus = false
var forceColor = false
@@ -18,7 +14,6 @@ var colorsEnabled = false
var indent = 2
var noDocSeparators = false
var nullInput = false
var nulSepOutput = false
var verbose = false
var version = false
var prettyPrint = false
+2 -8
View File
@@ -13,7 +13,7 @@ func createEvaluateAllCommand() *cobra.Command {
Aliases: []string{"ea"},
Short: "Loads _all_ yaml documents of _all_ yaml files and runs expression once",
Example: `
# Merge f2.yml into f1.yml (in place)
# Merge f2.yml into f1.yml (inplace)
yq eval-all --inplace 'select(fileIndex == 0) * select(fileIndex == 1)' f1.yml f2.yml
## the same command and expression using shortened names:
yq ea -i 'select(fi == 0) * select(fi == 1)' f1.yml f2.yml
@@ -84,15 +84,9 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
if err != nil {
return err
}
encoder, err := configureEncoder()
if err != nil {
return err
}
encoder := configureEncoder(format)
printer := yqlib.NewPrinter(encoder, printerWriter)
if nulSepOutput {
printer.SetNulSepOutput(true)
}
if frontMatter != "" {
frontMatterHandler := yqlib.NewFrontMatterHandler(args[0])
@@ -28,7 +28,7 @@ cat file2.yml | yq e '.a.b' file1.yml - file3.yml
## Note that editing an empty file does not work.
yq e -n '.a.b.c = "cat"'
# Update a file in place
# Update a file inplace
yq e '.a.b = "cool"' -i file.yaml
`,
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
@@ -93,15 +93,9 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
if err != nil {
return err
}
encoder, err := configureEncoder()
if err != nil {
return err
}
encoder := configureEncoder(format)
printer := yqlib.NewPrinter(encoder, printerWriter)
if nulSepOutput {
printer.SetNulSepOutput(true)
}
decoder, err := configureDecoder(false)
if err != nil {
+25 -23
View File
@@ -35,7 +35,7 @@ yq -P sample.json
return evaluateSequence(cmd, args)
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
PersistentPreRun: func(cmd *cobra.Command, args []string) {
cmd.SetOut(cmd.OutOrStdout())
var format = logging.MustStringFormatter(
@@ -52,8 +52,18 @@ yq -P sample.json
logging.SetBackend(backend)
yqlib.InitExpressionParser()
if (inputFormat == "x" || inputFormat == "xml") &&
outputFormat != "x" && outputFormat != "xml" &&
yqlib.ConfiguredXMLPreferences.AttributePrefix == "+" {
yqlib.GetLogger().Warning("The default xml-attribute-prefix will change in the v4.30 to `+@` to avoid " +
"naming conflicts with the default content name, directive name and proc inst prefix. If you need to keep " +
"`+` please set that value explicityly with --xml-attribute-prefix.")
}
return nil
//copy preference form global setting
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
},
}
@@ -65,34 +75,26 @@ yq -P sample.json
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&outputFormat, "output-format", "o", "auto", "[auto|a|yaml|y|json|j|props|p|xml|x|tsv|t|csv|c] output format type.")
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "auto", "[auto|a|yaml|y|props|p|xml|x|tsv|t|csv|c|toml] parse format for input. Note that json is a subset of yaml.")
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(&yqlib.ConfiguredXMLPreferences.AttributePrefix, "xml-attribute-prefix", yqlib.ConfiguredXMLPreferences.AttributePrefix, "prefix for xml attributes")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.ContentName, "xml-content-name", yqlib.ConfiguredXMLPreferences.ContentName, "name for xml content (if no attribute name is present).")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.StrictMode, "xml-strict-mode", yqlib.ConfiguredXMLPreferences.StrictMode, "enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.KeepNamespace, "xml-keep-namespace", yqlib.ConfiguredXMLPreferences.KeepNamespace, "enables keeping namespace after parsing attributes")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.UseRawToken, "xml-raw-token", yqlib.ConfiguredXMLPreferences.UseRawToken, "enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details.")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.ProcInstPrefix, "xml-proc-inst-prefix", yqlib.ConfiguredXMLPreferences.ProcInstPrefix, "prefix for xml processing instructions (e.g. <?xml version=\"1\"?>)")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.DirectiveName, "xml-directive-name", yqlib.ConfiguredXMLPreferences.DirectiveName, "name for xml directives (e.g. <!DOCTYPE thing cat>)")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.SkipProcInst, "xml-skip-proc-inst", yqlib.ConfiguredXMLPreferences.SkipProcInst, "skip over process instructions (e.g. <?xml version=\"1\"?>)")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.SkipDirectives, "xml-skip-directives", yqlib.ConfiguredXMLPreferences.SkipDirectives, "skip over directives (e.g. <!DOCTYPE thing cat>)")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocPrefix, "lua-prefix", yqlib.ConfiguredLuaPreferences.DocPrefix, "prefix")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocSuffix, "lua-suffix", yqlib.ConfiguredLuaPreferences.DocSuffix, "suffix")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredLuaPreferences.UnquotedKeys, "lua-unquoted", yqlib.ConfiguredLuaPreferences.UnquotedKeys, "output unquoted string keys (e.g. {foo=\"bar\"})")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredLuaPreferences.Globals, "lua-globals", yqlib.ConfiguredLuaPreferences.Globals, "output keys as top-level global variables")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.AttributePrefix, "xml-attribute-prefix", "+", "prefix for xml attributes")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.ContentName, "xml-content-name", "+content", "name for xml content (if no attribute name is present).")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.StrictMode, "xml-strict-mode", false, "enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.KeepNamespace, "xml-keep-namespace", true, "enables keeping namespace after parsing attributes")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.UseRawToken, "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().StringVar(&yqlib.ConfiguredXMLPreferences.ProcInstPrefix, "xml-proc-inst-prefix", "+p_", "prefix for xml processing instructions (e.g. <?xml version=\"1\"?>)")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.DirectiveName, "xml-directive-name", "+directive", "name for xml directives (e.g. <!DOCTYPE thing cat>)")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.SkipProcInst, "xml-skip-proc-inst", false, "skip over process instructions (e.g. <?xml version=\"1\"?>)")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredXMLPreferences.SkipDirectives, "xml-skip-directives", false, "skip over directives (e.g. <!DOCTYPE thing cat>)")
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().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 in place of first file given.")
rootCmd.PersistentFlags().VarP(unwrapScalarFlag, "unwrapScalar", "r", "unwrap scalar, print the value with no quotes, colors or comments. Defaults to true for yaml")
rootCmd.PersistentFlags().Lookup("unwrapScalar").NoOptDefVal = "true"
rootCmd.PersistentFlags().BoolVarP(&nulSepOutput, "nul-output", "0", false, "Use NUL char to separate values. If unwrap scalar is also set, fail if unwrapped scalar contains NUL char.")
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(&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")
-46
View File
@@ -1,46 +0,0 @@
package cmd
import (
"strconv"
"github.com/spf13/pflag"
)
type boolFlag interface {
pflag.Value
IsExplicitlySet() bool
IsSet() bool
}
type unwrapScalarFlagStrc struct {
explicitlySet bool
value bool
}
func newUnwrapFlag() boolFlag {
return &unwrapScalarFlagStrc{value: true}
}
func (f *unwrapScalarFlagStrc) IsExplicitlySet() bool {
return f.explicitlySet
}
func (f *unwrapScalarFlagStrc) IsSet() bool {
return f.value
}
func (f *unwrapScalarFlagStrc) String() string {
return strconv.FormatBool(f.value)
}
func (f *unwrapScalarFlagStrc) Set(value string) error {
v, err := strconv.ParseBool(value)
f.value = v
f.explicitlySet = true
return err
}
func (*unwrapScalarFlagStrc) Type() string {
return "bool"
}
+14 -104
View File
@@ -10,10 +10,6 @@ import (
"gopkg.in/op/go-logging.v1"
)
func isAutomaticOutputFormat() bool {
return outputFormat == "" || outputFormat == "auto" || outputFormat == "a"
}
func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
cmd.SilenceUsage = true
@@ -42,7 +38,7 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
}
if writeInplace && (len(args) == 0 || args[0] == "-") {
return "", nil, fmt.Errorf("write in place flag only applicable when giving an expression and at least one file")
return "", nil, fmt.Errorf("write inplace flag only applicable when giving an expression and at least one file")
}
if frontMatter != "" && len(args) == 0 {
@@ -50,69 +46,13 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
}
if writeInplace && splitFileExp != "" {
return "", nil, fmt.Errorf("write in place cannot be used with split file")
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")
}
inputFilename := ""
if len(args) > 0 {
inputFilename = args[0]
}
if inputFormat == "" || inputFormat == "auto" || inputFormat == "a" {
inputFormat = yqlib.FormatFromFilename(inputFilename)
_, err := yqlib.InputFormatFromString(inputFormat)
if err != nil {
// unknown file type, default to yaml
yqlib.GetLogger().Debug("Unknown file format extension '%v', defaulting to yaml", inputFormat)
inputFormat = "yaml"
if isAutomaticOutputFormat() {
outputFormat = "yaml"
}
} else if isAutomaticOutputFormat() {
// automatic input worked, we can do it for output too unless specified
if inputFormat == "json" {
yqlib.GetLogger().Warning("JSON file output is now JSON by default (instead of yaml). Use '-oy' or '--output-format=yaml' for yaml output")
}
outputFormat = inputFormat
}
} else if isAutomaticOutputFormat() {
// backwards compatibility -
// before this was introduced, `yq -pcsv things.csv`
// would produce *yaml* output.
//
outputFormat = yqlib.FormatFromFilename(inputFilename)
if inputFilename != "-" {
yqlib.GetLogger().Warning("yq default output is now 'auto' (based on the filename extension). Normally yq would output '%v', but for backwards compatibility 'yaml' has been set. Please use -oy to specify yaml, or drop the -p flag.", outputFormat)
}
outputFormat = "yaml"
}
outputFormatType, err := yqlib.OutputFormatFromString(outputFormat)
if err != nil {
return "", nil, err
}
yqlib.GetLogger().Debug("Using input format %v", inputFormat)
yqlib.GetLogger().Debug("Using output format %v", outputFormat)
if outputFormatType == yqlib.YamlOutputFormat ||
outputFormatType == yqlib.PropsOutputFormat {
unwrapScalar = true
}
if unwrapScalarFlag.IsExplicitlySet() {
unwrapScalar = unwrapScalarFlag.IsSet()
}
//copy preference form global setting
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
return expression, args, nil
}
@@ -121,15 +61,7 @@ func configureDecoder(evaluateTogether bool) (yqlib.Decoder, error) {
if err != nil {
return nil, err
}
yqlibDecoder, err := createDecoder(yqlibInputFormat, evaluateTogether)
if yqlibDecoder == nil {
return nil, fmt.Errorf("no support for %s input format", inputFormat)
}
return yqlibDecoder, err
}
func createDecoder(format yqlib.InputFormat, evaluateTogether bool) (yqlib.Decoder, error) {
switch format {
switch yqlibInputFormat {
case yqlib.XMLInputFormat:
return yqlib.NewXMLDecoder(yqlib.ConfiguredXMLPreferences), nil
case yqlib.PropertiesInputFormat:
@@ -140,14 +72,10 @@ func createDecoder(format yqlib.InputFormat, evaluateTogether bool) (yqlib.Decod
return yqlib.NewCSVObjectDecoder(','), nil
case yqlib.TSVObjectInputFormat:
return yqlib.NewCSVObjectDecoder('\t'), nil
case yqlib.TomlInputFormat:
return yqlib.NewTomlDecoder(), nil
case yqlib.YamlInputFormat:
prefs := yqlib.ConfiguredYamlPreferences
prefs.EvaluateTogether = evaluateTogether
return yqlib.NewYamlDecoder(prefs), nil
}
return nil, fmt.Errorf("invalid decoder: %v", format)
prefs := yqlib.ConfiguredYamlPreferences
prefs.EvaluateTogether = evaluateTogether
return yqlib.NewYamlDecoder(prefs), nil
}
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) {
@@ -167,40 +95,22 @@ func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yq
return printerWriter, nil
}
func configureEncoder() (yqlib.Encoder, error) {
yqlibOutputFormat, err := yqlib.OutputFormatFromString(outputFormat)
if err != nil {
return nil, err
}
yqlibEncoder, err := createEncoder(yqlibOutputFormat)
if yqlibEncoder == nil {
return nil, fmt.Errorf("no support for %s output format", outputFormat)
}
return yqlibEncoder, err
}
func createEncoder(format yqlib.PrinterOutputFormat) (yqlib.Encoder, error) {
func configureEncoder(format yqlib.PrinterOutputFormat) yqlib.Encoder {
switch format {
case yqlib.JSONOutputFormat:
return yqlib.NewJSONEncoder(indent, colorsEnabled, unwrapScalar), nil
return yqlib.NewJSONEncoder(indent, colorsEnabled)
case yqlib.PropsOutputFormat:
return yqlib.NewPropertiesEncoder(unwrapScalar), nil
return yqlib.NewPropertiesEncoder(unwrapScalar)
case yqlib.CSVOutputFormat:
return yqlib.NewCsvEncoder(','), nil
return yqlib.NewCsvEncoder(',')
case yqlib.TSVOutputFormat:
return yqlib.NewCsvEncoder('\t'), nil
return yqlib.NewCsvEncoder('\t')
case yqlib.YamlOutputFormat:
return yqlib.NewYamlEncoder(indent, colorsEnabled, yqlib.ConfiguredYamlPreferences), nil
return yqlib.NewYamlEncoder(indent, colorsEnabled, yqlib.ConfiguredYamlPreferences)
case yqlib.XMLOutputFormat:
return yqlib.NewXMLEncoder(indent, yqlib.ConfiguredXMLPreferences), nil
case yqlib.TomlOutputFormat:
return yqlib.NewTomlEncoder(), nil
case yqlib.ShellVariablesOutputFormat:
return yqlib.NewShellVariablesEncoder(), nil
case yqlib.LuaOutputFormat:
return yqlib.NewLuaEncoder(yqlib.ConfiguredLuaPreferences), nil
return yqlib.NewXMLEncoder(indent, yqlib.ConfiguredXMLPreferences)
}
return nil, fmt.Errorf("invalid encoder: %v", format)
panic("invalid encoder")
}
// this is a hack to enable backwards compatibility with githubactions (which pipe /dev/null into everything)
+1 -1
View File
@@ -11,7 +11,7 @@ var (
GitDescribe string
// Version is main version number that is being run at the moment.
Version = "v4.35.2"
Version = "4.28.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
-14
View File
@@ -1,14 +0,0 @@
---
$schema: https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json
version: '0.2'
language: en-GB
dictionaryDefinitions:
- name: project-words
path: './project-words.txt'
addWords: true
dictionaries:
- project-words
ignorePaths:
- 'vendor'
- 'bin'
- '/project-words.txt'
+2 -2
View File
@@ -103,7 +103,7 @@ yq (4.16.2) focal; urgency=medium
* 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
* Bump golang compiler #1037
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 21 Dec 2021 09:41:44 +0000
@@ -127,7 +127,7 @@ yq (4.9.6) focal; urgency=medium
* Added darwin/arm64 build, thanks @alecthomas
* Incremented docker alpine base version, thanks @da6d6i7-bronga
* Bug fix: multiline expression
* Bug fix: multine expression
* Bug fix: special character
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 29 Jun 2021 21:32:14 +0200
+11 -2
View File
@@ -1,2 +1,11 @@
- [cat, dog, frog, cow]
- [apple, banana, grape, mango]
---
- become: true
gather_facts: false
hosts: lalaland
name: "Apply smth"
roles:
- lala
- land
serial: 1
- become: false
gather_facts: true
+5 -1
View File
@@ -1 +1,5 @@
["foobar", "foobaz", "blarp"]
volumes:
beehive-conf:
driver: local
services:
- beehive
+7 -1
View File
@@ -1 +1,7 @@
<cat>3</cat>
<?xml version="1.0"?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<apple>
<?coolioo version="1.0"?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<b>things</b>
</apple>
-26
View File
@@ -1,26 +0,0 @@
# This is a TOML document
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend"
+1 -1
View File
@@ -1,3 +1,3 @@
name,numberOfCats,likesApples,height
,1,true,168.8
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
-4
View File
@@ -1,4 +0,0 @@
---
# comment
# about things
a: cat
+17 -18
View File
@@ -1,32 +1,31 @@
module github.com/mikefarah/yq/v4
require (
github.com/a8m/envsubst v1.4.2
github.com/alecthomas/participle/v2 v2.1.0
github.com/alecthomas/repr v0.2.0
github.com/a8m/envsubst v1.3.0
github.com/alecthomas/participle/v2 v2.0.0-beta.5
github.com/alecthomas/repr v0.1.1
github.com/dimchansky/utfbom v1.1.1
github.com/elliotchance/orderedmap v1.5.0
github.com/fatih/color v1.15.0
github.com/goccy/go-json v0.10.2
github.com/goccy/go-yaml v1.11.2
github.com/jinzhu/copier v0.4.0
github.com/magiconair/properties v1.8.7
github.com/pelletier/go-toml/v2 v2.1.0
github.com/fatih/color v1.13.0
github.com/goccy/go-json v0.9.11
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.7.0
github.com/spf13/pflag v1.0.5
golang.org/x/net v0.15.0
golang.org/x/text v0.13.0
github.com/spf13/cobra v1.6.0
golang.org/x/net v0.0.0-20220708220712-1185a9018129
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
golang.org/x/sys v0.12.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // 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.20
go 1.19
+57 -43
View File
@@ -1,68 +1,82 @@
github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg=
github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0=
github.com/alecthomas/participle/v2 v2.1.0 h1:z7dElHRrOEEq45F2TG5cbQihMtNTv8vwldytDj7Wrz4=
github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
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.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
github.com/alecthomas/repr v0.1.1 h1:87P60cSmareLAxMc4Hro0r2RBY4ROm0dYwkJNpS4pPs=
github.com/alecthomas/repr v0.1.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/elliotchance/orderedmap v1.5.0 h1:1IsExUsjv5XNBD3ZdC7jkAAqLWOOKdbPTmkHx63OsBg=
github.com/elliotchance/orderedmap v1.5.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
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/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.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/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/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
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/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.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/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.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
+1 -1
View File
@@ -29,7 +29,7 @@ It pipes the current, lets call it 'root' context through the `lhs` expression o
cat
```
Side note: this node holds not only its value 'cat', but comments and metadata too, including path and parent information.
Sidenote: this node holds not only its value 'cat', but comments and metadata too, including path and parent information.
The `=` operator then pipes the 'root' context through the `rhs` expression of `.b` to return the node
+1 -1
View File
@@ -111,7 +111,7 @@ func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
return newPath
}
//don't use append as they may actually modify the path of the original node!
//don't use append as they may actually modify the path of the orignal node!
newPath := make([]interface{}, len(n.Path)+1)
copy(newPath, n.Path)
newPath[len(n.Path)] = path
-25
View File
@@ -1,25 +0,0 @@
//go:build linux
package yqlib
import (
"io/fs"
"os"
"syscall"
)
func changeOwner(info fs.FileInfo, file *os.File) error {
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
uid := int(stat.Uid)
gid := int(stat.Gid)
err := os.Chown(file.Name(), uid, gid)
if err != nil {
// this happens with snap confinement
// not really a big issue as users can chown
// the file themselves if required.
log.Info("Skipping chown: %v", err)
}
}
return nil
}
-12
View File
@@ -1,12 +0,0 @@
//go:build !linux
package yqlib
import (
"io/fs"
"os"
)
func changeOwner(info fs.FileInfo, file *os.File) error {
return nil
}
@@ -3,6 +3,7 @@ package yqlib
import (
"fmt"
"strconv"
"time"
yaml "gopkg.in/yaml.v3"
)
@@ -15,7 +16,7 @@ type compareTypePref struct {
func compareOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
log.Debugf("-- compareOperator")
prefs := expressionNode.Operation.Preferences.(compareTypePref)
return crossFunction(d, context, expressionNode, compare(prefs), true)
return crossFunction(d, context.ReadOnlyClone(), expressionNode, compare(prefs), true)
}
func compare(prefs compareTypePref) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
@@ -53,12 +54,12 @@ func compare(prefs compareTypePref) func(d *dataTreeNavigator, context Context,
}
func compareDateTime(layout string, prefs compareTypePref, lhs *yaml.Node, rhs *yaml.Node) (bool, error) {
lhsTime, err := parseDateTime(layout, lhs.Value)
lhsTime, err := time.Parse(layout, lhs.Value)
if err != nil {
return false, err
}
rhsTime, err := parseDateTime(layout, rhs.Value)
rhsTime, err := time.Parse(layout, rhs.Value)
if err != nil {
return false, err
}
@@ -79,8 +80,8 @@ func compareScalars(context Context, prefs compareTypePref, lhs *yaml.Node, rhs
isDateTime := lhs.Tag == "!!timestamp"
// if the lhs is a string, it might be a timestamp in a custom format.
if lhsTag == "!!str" {
_, err := parseDateTime(context.GetDateTimeLayout(), lhs.Value)
if lhsTag == "!!str" && context.GetDateTimeLayout() != time.RFC3339 {
_, err := time.Parse(context.GetDateTimeLayout(), lhs.Value)
isDateTime = err == nil
}
if isDateTime {
@@ -126,10 +127,6 @@ func compareScalars(context Context, prefs compareTypePref, lhs *yaml.Node, rhs
return lhs.Value > rhs.Value, nil
}
return lhs.Value < rhs.Value, nil
} else if lhsTag == "!!null" && rhsTag == "!!null" && prefs.OrEqual {
return true, nil
} else if lhsTag == "!!null" || rhsTag == "!!null" {
return false, nil
}
return false, fmt.Errorf("%v not yet supported for comparison", lhs.Tag)
@@ -14,20 +14,6 @@ var compareOperatorScenarios = []expressionScenario{
"D0, P[a], (!!bool)::true\n",
},
},
{
skipDoc: true,
expression: "(.k | length) >= 0",
expected: []string{
"D0, P[k], (!!bool)::true\n",
},
},
{
skipDoc: true,
expression: `"2022-01-30T15:53:09Z" > "2020-01-30T15:53:09Z"`,
expected: []string{
"D0, P[], (!!bool)::true\n",
},
},
{
skipDoc: true,
document: "a: 5\nb: 4",
@@ -299,28 +285,28 @@ var compareOperatorScenarios = []expressionScenario{
description: "Both sides are null: > is false",
expression: ".a > .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
"D0, P[], (!!bool)::false\n",
},
},
{
skipDoc: true,
expression: ".a < .b",
expected: []string{
"D0, P[a], (!!bool)::false\n",
"D0, P[], (!!bool)::false\n",
},
},
{
description: "Both sides are null: >= is true",
expression: ".a >= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
"D0, P[], (!!bool)::true\n",
},
},
{
skipDoc: true,
expression: ".a <= .b",
expected: []string{
"D0, P[a], (!!bool)::true\n",
"D0, P[], (!!bool)::true\n",
},
},
@@ -364,7 +350,7 @@ var compareOperatorScenarios = []expressionScenario{
document: `a: 5`,
expression: ".b <= .a",
expected: []string{
"D0, P[b], (!!bool)::false\n",
"D0, P[a], (!!bool)::false\n",
},
},
{
@@ -372,7 +358,7 @@ var compareOperatorScenarios = []expressionScenario{
document: `a: 5`,
expression: ".b < .a",
expected: []string{
"D0, P[b], (!!bool)::false\n",
"D0, P[a], (!!bool)::false\n",
},
},
}
+9 -26
View File
@@ -12,9 +12,7 @@ const csvSimple = `name,numberOfCats,likesApples,height
Gary,1,true,168.8
Samantha's Rabbit,2,false,-188.8
`
const csvMissing = `name,numberOfCats,likesApples,height
,null,,168.8
`
const expectedUpdatedSimpleCsv = `name,numberOfCats,likesApples,height
Gary,3,true,168.8
Samantha's Rabbit,2,false,-188.8
@@ -112,13 +110,6 @@ var csvScenarios = []formatScenario{
expected: csvSimpleMissingData,
scenarioType: "encode-csv",
},
{
description: "decode csv missing",
skipDoc: true,
input: csvMissing,
expected: csvMissing,
scenarioType: "roundtrip-csv",
},
{
description: "Parse CSV into an array of objects",
subdescription: "First row is assumed to be the header row.",
@@ -126,14 +117,6 @@ var csvScenarios = []formatScenario{
expected: expectedYamlFromCSV,
scenarioType: "decode-csv-object",
},
{
description: "Scalar roundtrip",
skipDoc: true,
input: "mike\ncat",
expression: ".[0].mike",
expected: "cat\n",
scenarioType: "roundtrip-csv",
},
{
description: "Parse TSV into an array of objects",
subdescription: "First row is assumed to be the header row.",
@@ -153,15 +136,15 @@ var csvScenarios = []formatScenario{
func testCSVScenario(t *testing.T, s formatScenario) {
switch s.scenarioType {
case "encode-csv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(',')), s.description)
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(',')), s.description)
case "encode-tsv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder('\t')), s.description)
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder('\t')), s.description)
case "decode-csv-object":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(','), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder(','), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
case "decode-tsv-object":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder('\t'), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder('\t'), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
case "roundtrip-csv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(','), NewCsvEncoder(',')), s.description)
test.AssertResultWithContext(t, s.expected, processFormatScenario(s, NewCSVObjectDecoder(','), NewCsvEncoder(',')), s.description)
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
}
@@ -188,7 +171,7 @@ func documentCSVDecodeObjectScenario(w *bufio.Writer, s formatScenario, formatTy
}
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n",
mustProcessFormatScenario(s, NewCSVObjectDecoder(separator), NewYamlEncoder(s.indent, false, ConfiguredYamlPreferences))),
processFormatScenario(s, NewCSVObjectDecoder(separator), NewYamlEncoder(s.indent, false, ConfiguredYamlPreferences))),
)
}
@@ -220,7 +203,7 @@ func documentCSVEncodeScenario(w *bufio.Writer, s formatScenario, formatType str
}
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(separator))),
processFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(separator))),
)
}
@@ -252,7 +235,7 @@ func documentCSVRoundTripScenario(w *bufio.Writer, s formatScenario, formatType
}
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
mustProcessFormatScenario(s, NewCSVObjectDecoder(separator), NewCsvEncoder(separator))),
processFormatScenario(s, NewCSVObjectDecoder(separator), NewCsvEncoder(separator))),
)
}
-24
View File
@@ -4,7 +4,6 @@ import (
"fmt"
logging "gopkg.in/op/go-logging.v1"
yaml "gopkg.in/yaml.v3"
)
type DataTreeNavigator interface {
@@ -12,8 +11,6 @@ type DataTreeNavigator interface {
// this will process the against the given expressionNode and return
// a new context of matching candidates
GetMatchingNodes(context Context, expressionNode *ExpressionNode) (Context, error)
DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error
}
type dataTreeNavigator struct {
@@ -23,27 +20,6 @@ func NewDataTreeNavigator() DataTreeNavigator {
return &dataTreeNavigator{}
}
func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error {
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 := d.GetMatchingNodes(context, assignmentOpNode)
return err
}
func (d *dataTreeNavigator) GetMatchingNodes(context Context, expressionNode *ExpressionNode) (Context, error) {
if expressionNode == nil {
log.Debugf("getMatchingNodes - nothing to do")
+3 -24
View File
@@ -3,7 +3,6 @@ package yqlib
import (
"fmt"
"io"
"strings"
)
type InputFormat uint
@@ -16,8 +15,6 @@ const (
JsonInputFormat
CSVObjectInputFormat
TSVObjectInputFormat
TomlInputFormat
UriInputFormat
)
type Decoder interface {
@@ -27,11 +24,11 @@ type Decoder interface {
func InputFormatFromString(format string) (InputFormat, error) {
switch format {
case "yaml", "yml", "y":
case "yaml", "y":
return YamlInputFormat, nil
case "xml", "x":
return XMLInputFormat, nil
case "properties", "props", "p":
case "props", "p":
return PropertiesInputFormat, nil
case "json", "ndjson", "j":
return JsonInputFormat, nil
@@ -39,25 +36,7 @@ func InputFormatFromString(format string) (InputFormat, error) {
return CSVObjectInputFormat, nil
case "tsv", "t":
return TSVObjectInputFormat, nil
case "toml":
return TomlInputFormat, nil
default:
return 0, fmt.Errorf("unknown format '%v' please use [yaml|json|props|csv|tsv|xml|toml]", format)
return 0, fmt.Errorf("unknown format '%v' please use [yaml|xml|props]", format)
}
}
func FormatFromFilename(filename string) string {
if filename != "" {
GetLogger().Debugf("checking file extension '%s' for auto format detection", filename)
nPos := strings.LastIndex(filename, ".")
if nPos > -1 {
format := filename[nPos+1:]
GetLogger().Debugf("detected format '%s'", format)
return format
}
}
GetLogger().Debugf("using default inputFormat 'yaml'")
return "yaml"
}
+1 -24
View File
@@ -4,33 +4,10 @@ import (
"bytes"
"encoding/base64"
"io"
"strings"
yaml "gopkg.in/yaml.v3"
)
type base64Padder struct {
count uint64
io.Reader
}
func (c *base64Padder) pad(buf []byte) (int, error) {
pad := strings.Repeat("=", int(4-c.count%4))
n, err := strings.NewReader(pad).Read(buf)
c.count += uint64(n)
return n, err
}
func (c *base64Padder) Read(buf []byte) (int, error) {
n, err := c.Reader.Read(buf)
c.count += uint64(n)
if err == io.EOF && c.count%4 != 0 {
return c.pad(buf)
}
return n, err
}
type base64Decoder struct {
reader io.Reader
finished bool
@@ -43,7 +20,7 @@ func NewBase64Decoder() Decoder {
}
func (dec *base64Decoder) Init(reader io.Reader) error {
dec.reader = &base64Padder{Reader: reader}
dec.reader = reader
dec.readAnything = false
dec.finished = false
return nil
+6 -19
View File
@@ -1,5 +1,3 @@
//go:build !yq_nojson
package yqlib
import (
@@ -46,24 +44,13 @@ func (dec *jsonDecoder) Decode() (*CandidateNode, error) {
}
func (dec *jsonDecoder) convertToYamlNode(data *orderedMap) (*yaml.Node, error) {
if data == nil {
return createScalarNode(nil, "null"), nil
}
if data.kv == nil {
switch rawData := data.altVal.(type) {
case nil:
return createScalarNode(nil, "null"), nil
case float64, float32:
// json decoder returns ints as float.'
intNum := int(rawData.(float64))
// if the integer representation is the same as the original
// then its an int.
if float64(intNum) == rawData.(float64) {
return createScalarNode(intNum, fmt.Sprintf("%v", intNum)), nil
}
return createScalarNode(rawData, fmt.Sprintf("%v", rawData)), nil
// json decoder returns ints as float.
return parseSnippet(fmt.Sprintf("%v", rawData))
case int, int64, int32, string, bool:
return createScalarNode(rawData, fmt.Sprintf("%v", rawData)), nil
case []*orderedMap:
@@ -73,9 +60,9 @@ func (dec *jsonDecoder) convertToYamlNode(data *orderedMap) (*yaml.Node, error)
}
}
var yamlMap = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
for i, keyValuePair := range data.kv {
yamlValue, err := dec.convertToYamlNode(&data.kv[i].V)
var yamlMap = &yaml.Node{Kind: yaml.MappingNode}
for _, keyValuePair := range data.kv {
yamlValue, err := dec.convertToYamlNode(&keyValuePair.V)
if err != nil {
return nil, err
}
@@ -87,7 +74,7 @@ func (dec *jsonDecoder) convertToYamlNode(data *orderedMap) (*yaml.Node, error)
func (dec *jsonDecoder) parseArray(dataArray []*orderedMap) (*yaml.Node, error) {
var yamlMap = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
var yamlMap = &yaml.Node{Kind: yaml.SequenceNode}
for _, value := range dataArray {
yamlValue, err := dec.convertToYamlNode(value)
+18 -2
View File
@@ -63,7 +63,7 @@ func (dec *propertiesDecoder) applyPropertyComments(context Context, path []inte
rhsCandidateNode.Node.Tag = guessTagFromCustomType(rhsCandidateNode.Node)
rhsOp := &Operation{OperationType: referenceOpType, CandidateNode: rhsCandidateNode}
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhsCandidateNode}
assignmentOpNode := &ExpressionNode{
Operation: assignmentOp,
@@ -95,7 +95,23 @@ func (dec *propertiesDecoder) applyProperty(context Context, properties *propert
rhsNode.Tag = guessTagFromCustomType(rhsNode)
return dec.d.DeeplyAssign(context, path, 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() (*CandidateNode, error) {
+7 -17
View File
@@ -3,7 +3,6 @@ package yqlib
import (
"bufio"
"bytes"
"fmt"
"strings"
)
@@ -16,10 +15,10 @@ type formatScenario struct {
subdescription string
skipDoc bool
scenarioType string
expectedError string
}
func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) (string, error) {
func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) string {
var output bytes.Buffer
writer := bufio.NewWriter(&output)
@@ -29,7 +28,7 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) (
inputs, err := readDocuments(strings.NewReader(s.input), "sample.yml", 0, decoder)
if err != nil {
return "", err
panic(err)
}
expression := s.expression
@@ -40,31 +39,22 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) (
exp, err := getExpressionParser().ParseExpression(expression)
if err != nil {
return "", err
panic(err)
}
context, err := NewDataTreeNavigator().GetMatchingNodes(Context{MatchingNodes: inputs}, exp)
if err != nil {
return "", err
panic(err)
}
printer := NewPrinter(encoder, NewSinglePrinterWriter(writer))
err = printer.PrintResults(context.MatchingNodes)
if err != nil {
return "", err
panic(err)
}
writer.Flush()
return output.String(), nil
}
func mustProcessFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) string {
result, err := processFormatScenario(s, decoder, encoder)
if err != nil {
panic(fmt.Errorf("Bad scenario %v: %w", s.description, err))
}
return result
return output.String()
}
-369
View File
@@ -1,369 +0,0 @@
//go:build !yq_notoml
package yqlib
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"time"
toml "github.com/pelletier/go-toml/v2/unstable"
yaml "gopkg.in/yaml.v3"
)
type tomlDecoder struct {
parser toml.Parser
finished bool
d DataTreeNavigator
rootMap *CandidateNode
}
func NewTomlDecoder() Decoder {
return &tomlDecoder{
finished: false,
d: NewDataTreeNavigator(),
}
}
func (dec *tomlDecoder) Init(reader io.Reader) error {
dec.parser = toml.Parser{}
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(reader)
if err != nil {
return err
}
dec.parser.Reset(buf.Bytes())
dec.rootMap = &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
}}
return nil
}
func (dec *tomlDecoder) getFullPath(tomlNode *toml.Node) []interface{} {
path := make([]interface{}, 0)
for {
path = append(path, string(tomlNode.Data))
tomlNode = tomlNode.Next()
if tomlNode == nil {
return path
}
}
}
func (dec *tomlDecoder) processKeyValueIntoMap(rootMap *CandidateNode, tomlNode *toml.Node) error {
value := tomlNode.Value()
path := dec.getFullPath(value.Next())
log.Debug("!!!processKeyValueIntoMap: %v", path)
valueNode, err := dec.decodeNode(value)
if err != nil {
return err
}
context := Context{}
context = context.SingleChildContext(rootMap)
return dec.d.DeeplyAssign(context, path, valueNode)
}
func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode *toml.Node) (bool, error) {
log.Debug("!! DECODE_KV_INTO_MAP -- processing first (current) entry")
if err := dec.processKeyValueIntoMap(rootMap, tomlNode); err != nil {
return false, err
}
for dec.parser.NextExpression() {
nextItem := dec.parser.Expression()
log.Debug("!! DECODE_KV_INTO_MAP -- next exp, its a %v", nextItem.Kind)
if nextItem.Kind == toml.KeyValue {
if err := dec.processKeyValueIntoMap(rootMap, nextItem); err != nil {
return false, err
}
} else {
// run out of key values
log.Debug("! DECODE_KV_INTO_MAP - ok we are done in decodeKeyValuesIntoMap, gota a %v", nextItem.Kind)
log.Debug("! DECODE_KV_INTO_MAP - processAgainstCurrentExp = true!")
return true, nil
}
}
log.Debug("! DECODE_KV_INTO_MAP - no more things to read in")
return false, nil
}
func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, error) {
content := make([]*yaml.Node, 0)
log.Debug("!! createInlineTableMap")
iterator := tomlNode.Children()
for iterator.Next() {
child := iterator.Node()
if child.Kind != toml.KeyValue {
return nil, fmt.Errorf("only keyvalue pairs are supported in inlinetables, got %v instead", child.Kind)
}
keyValues := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
}
if err := dec.processKeyValueIntoMap(keyValues, child); err != nil {
return nil, err
}
content = append(content, keyValues.Node.Content...)
}
return &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
Content: content,
}, nil
}
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) {
content := make([]*yaml.Node, 0)
iterator := tomlNode.Children()
for iterator.Next() {
child := iterator.Node()
yamlNode, err := dec.decodeNode(child)
if err != nil {
return nil, err
}
content = append(content, yamlNode)
}
return &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: content,
}, nil
}
func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*yaml.Node, error) {
content := string(tomlNode.Data)
return createScalarNode(content, content), nil
}
func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*yaml.Node, error) {
content := string(tomlNode.Data)
return createScalarNode(content == "true", content), nil
}
func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*yaml.Node, error) {
content := string(tomlNode.Data)
_, num, err := parseInt64(content)
return createScalarNode(num, content), err
}
func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*yaml.Node, error) {
content := string(tomlNode.Data)
val, err := parseDateTime(time.RFC3339, content)
return createScalarNode(val, content), err
}
func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*yaml.Node, error) {
content := string(tomlNode.Data)
num, err := strconv.ParseFloat(content, 64)
return createScalarNode(num, content), err
}
func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*yaml.Node, error) {
switch tomlNode.Kind {
case toml.Key, toml.String:
return dec.createStringScalar(tomlNode)
case toml.Bool:
return dec.createBoolScalar(tomlNode)
case toml.Integer:
return dec.createIntegerScalar(tomlNode)
case toml.DateTime:
return dec.createDateTimeScalar(tomlNode)
case toml.Float:
return dec.createFloatScalar(tomlNode)
case toml.Array:
return dec.createArray(tomlNode)
case toml.InlineTable:
return dec.createInlineTableMap(tomlNode)
default:
return nil, fmt.Errorf("unsupported type %v", tomlNode.Kind)
}
}
func (dec *tomlDecoder) Decode() (*CandidateNode, error) {
if dec.finished {
return nil, io.EOF
}
//
// toml library likes to panic
var deferredError error
defer func() { //catch or finally
if r := recover(); r != nil {
var ok bool
deferredError, ok = r.(error)
if !ok {
deferredError = fmt.Errorf("pkg: %v", r)
}
}
}()
log.Debug("ok here we go")
var runAgainstCurrentExp = false
var err error
for runAgainstCurrentExp || dec.parser.NextExpression() {
if runAgainstCurrentExp {
log.Debug("running against current exp")
}
currentNode := dec.parser.Expression()
log.Debug("currentNode: %v ", currentNode.Kind)
runAgainstCurrentExp, err = dec.processTopLevelNode(currentNode)
if err != nil {
return dec.rootMap, err
}
}
err = dec.parser.Error()
if err != nil {
return nil, err
}
// must have finished
dec.finished = true
if len(dec.rootMap.Node.Content) == 0 {
return nil, io.EOF
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{dec.rootMap.Node},
},
}, deferredError
}
func (dec *tomlDecoder) processTopLevelNode(currentNode *toml.Node) (bool, error) {
var runAgainstCurrentExp bool
var err error
log.Debug("!!!!!!!!!!!!Going to process %v state is current %v", currentNode.Kind, NodeToString(dec.rootMap))
if currentNode.Kind == toml.Table {
runAgainstCurrentExp, err = dec.processTable((currentNode))
} else if currentNode.Kind == toml.ArrayTable {
runAgainstCurrentExp, err = dec.processArrayTable((currentNode))
} else {
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(dec.rootMap, currentNode)
}
log.Debug("!!!!!!!!!!!!DONE Processing state is now %v", NodeToString(dec.rootMap))
return runAgainstCurrentExp, err
}
func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) {
log.Debug("!!! processing table")
fullPath := dec.getFullPath(currentNode.Child())
log.Debug("!!!fullpath: %v", fullPath)
hasValue := dec.parser.NextExpression()
if !hasValue {
return false, fmt.Errorf("error retrieving table %v value: %w", fullPath, dec.parser.Error())
}
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
}
tableValue := dec.parser.Expression()
if tableValue.Kind != toml.KeyValue {
log.Debug("got an empty table, returning")
return true, nil
}
runAgainstCurrentExp, err := dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
log.Debugf("table node err: %w", err)
if err != nil && !errors.Is(io.EOF, err) {
return false, err
}
c := Context{}
c = c.SingleChildContext(dec.rootMap)
err = dec.d.DeeplyAssign(c, fullPath, tableNodeValue.Node)
if err != nil {
return false, err
}
return runAgainstCurrentExp, nil
}
func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *yaml.Node) error {
rhsCandidateNode := &CandidateNode{
Path: path,
Node: &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: []*yaml.Node{rhsNode},
},
}
assignmentOp := &Operation{OperationType: addAssignOpType}
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 *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) {
log.Debug("!!! processing table")
fullPath := dec.getFullPath(currentNode.Child())
log.Debug("!!!fullpath: %v", fullPath)
// need to use the array append exp to add another entry to
// this array: fullpath += [ thing ]
hasValue := dec.parser.NextExpression()
if !hasValue {
return false, fmt.Errorf("error retrieving table %v value: %w", fullPath, dec.parser.Error())
}
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
}
tableValue := dec.parser.Expression()
runAgainstCurrentExp, err := dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
log.Debugf("table node err: %w", err)
if err != nil && !errors.Is(io.EOF, err) {
return false, err
}
c := Context{}
c = c.SingleChildContext(dec.rootMap)
// += function
err = dec.arrayAppend(c, fullPath, tableNodeValue.Node)
return runAgainstCurrentExp, err
}
-60
View File
@@ -1,60 +0,0 @@
package yqlib
import (
"bytes"
"io"
"net/url"
yaml "gopkg.in/yaml.v3"
)
type uriDecoder struct {
reader io.Reader
finished bool
readAnything bool
}
func NewUriDecoder() Decoder {
return &uriDecoder{finished: false}
}
func (dec *uriDecoder) Init(reader io.Reader) error {
dec.reader = reader
dec.readAnything = false
dec.finished = false
return nil
}
func (dec *uriDecoder) Decode() (*CandidateNode, error) {
if dec.finished {
return nil, io.EOF
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(dec.reader); err != nil {
return nil, 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 nil, io.EOF
}
}
newValue, err := url.QueryUnescape(buf.String())
if err != nil {
return nil, err
}
dec.readAnything = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: newValue,
},
}, nil
}
+24 -85
View File
@@ -1,13 +1,9 @@
//go:build !yq_noxml
package yqlib
import (
"encoding/xml"
"errors"
"fmt"
"io"
"regexp"
"strings"
"unicode"
@@ -49,33 +45,23 @@ func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*yaml.Node, error) {
return yamlNode, nil
}
var decoderCommentPrefix = regexp.MustCompile(`(^|\n)([[:alpha:]])`)
func (dec *xmlDecoder) processComment(c string) string {
if c == "" {
return ""
}
//need to replace "cat " with "# cat"
// "\ncat\n" with "\n cat\n"
// ensure non-empty comments starting with newline have a space in front
replacement := decoderCommentPrefix.ReplaceAllString(c, "$1 $2")
replacement = "#" + strings.ReplaceAll(strings.TrimRight(replacement, " "), "\n", "\n#")
return replacement
return "#" + strings.TrimRight(c, " ")
}
func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
log.Debug("createMap: headC: %v, lineC: %v, footC: %v", n.HeadComment, n.LineComment, n.FootComment)
log.Debug("createMap: headC: %v, footC: %v", n.HeadComment, n.FootComment)
yamlNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
if len(n.Data) > 0 {
log.Debugf("creating content node for map: %v", dec.prefs.ContentName)
label := dec.prefs.ContentName
labelNode := createScalarNode(label, label)
labelNode.HeadComment = dec.processComment(n.HeadComment)
labelNode.LineComment = dec.processComment(n.LineComment)
labelNode.FootComment = dec.processComment(n.FootComment)
yamlNode.Content = append(yamlNode.Content, labelNode, dec.createValueNodeFromData(n.Data))
yamlNode.Content = append(yamlNode.Content, labelNode, createScalarNode(n.Data, n.Data))
}
for i, keyValuePair := range n.Children {
@@ -86,11 +72,10 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
var err error
if i == 0 {
log.Debugf("head comment here")
labelNode.HeadComment = dec.processComment(n.HeadComment)
}
log.Debugf("label=%v, i=%v, keyValuePair.FootComment: %v", label, i, keyValuePair.FootComment)
labelNode.FootComment = dec.processComment(keyValuePair.FootComment)
log.Debug("len of children in %v is %v", label, len(children))
@@ -104,16 +89,8 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
// 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 != "" {
if len(children[0].Data) > 0 {
log.Debug("scalar comment hack, currentlabel [%v]", labelNode.HeadComment)
labelNode.HeadComment = joinComments([]string{labelNode.HeadComment, strings.TrimSpace(children[0].HeadComment)}, "\n")
children[0].HeadComment = ""
} else {
// child is null, put the headComment as a linecomment for reasons
children[0].LineComment = children[0].HeadComment
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 {
@@ -126,40 +103,17 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
return yamlNode, nil
}
func (dec *xmlDecoder) createValueNodeFromData(values []string) *yaml.Node {
switch len(values) {
case 0:
return createScalarNode(nil, "")
case 1:
return createScalarNode(values[0], values[0])
default:
content := make([]*yaml.Node, 0)
for _, value := range values {
content = append(content, createScalarNode(value, value))
}
return &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: content,
}
}
}
func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) {
if len(n.Children) > 0 {
return dec.createMap(n)
}
scalar := dec.createValueNodeFromData(n.Data)
log.Debug("scalar (%v), headC: %v, lineC: %v, footC: %v", scalar.Tag, n.HeadComment, n.LineComment, n.FootComment)
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)
if scalar.Tag == "!!seq" {
scalar.Content[0].HeadComment = scalar.LineComment
scalar.LineComment = ""
}
scalar.FootComment = dec.processComment(n.FootComment)
return scalar, nil
@@ -202,7 +156,7 @@ type xmlNode struct {
HeadComment string
FootComment string
LineComment string
Data []string
Data string
}
type xmlChildrenKv struct {
@@ -247,8 +201,6 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
// That will convert the charset if the provided XML is non-UTF-8
xmlDec.CharsetReader = charset.NewReaderLabel
started := false
// Create first element from the root node
elem := &element{
parent: nil,
@@ -289,18 +241,12 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
a.Name.Local = a.Name.Space + ":" + a.Name.Local
}
}
elem.n.AddChild(dec.prefs.AttributePrefix+a.Name.Local, &xmlNode{Data: []string{a.Value}})
elem.n.AddChild(dec.prefs.AttributePrefix+a.Name.Local, &xmlNode{Data: a.Value})
}
case xml.CharData:
// Extract XML data (if any)
newBit := trimNonGraphic(string(se))
if !started && len(newBit) > 0 {
return fmt.Errorf("invalid XML: Encountered chardata [%v] outside of XML node", newBit)
}
if len(newBit) > 0 {
elem.n.Data = append(elem.n.Data, newBit)
elem.n.Data = trimNonGraphic(string(se))
if elem.n.Data != "" {
elem.state = "chardata"
log.Debug("chardata [%v] for %v", elem.n.Data, elem.label)
}
@@ -322,22 +268,21 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
} else if elem.state == "chardata" {
log.Debug("got a line comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
elem.n.LineComment = joinComments([]string{elem.n.LineComment, 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 = joinComments([]string{elem.n.HeadComment, commentStr}, " ")
elem.n.HeadComment = joinFilter([]string{elem.n.HeadComment, commentStr})
}
case xml.ProcInst:
if !dec.prefs.SkipProcInst {
elem.n.AddChild(dec.prefs.ProcInstPrefix+se.Target, &xmlNode{Data: []string{string(se.Inst)}})
elem.n.AddChild(dec.prefs.ProcInstPrefix+se.Target, &xmlNode{Data: string(se.Inst)})
}
case xml.Directive:
if !dec.prefs.SkipDirectives {
elem.n.AddChild(dec.prefs.DirectiveName, &xmlNode{Data: []string{string(se)}})
elem.n.AddChild(dec.prefs.DirectiveName, &xmlNode{Data: string(se)})
}
}
started = true
}
return nil
@@ -349,28 +294,22 @@ func applyFootComment(elem *element, commentStr string) {
if len(elem.n.Children) > 0 {
lastChildIndex := len(elem.n.Children) - 1
childKv := elem.n.Children[lastChildIndex]
log.Debug("got a foot comment, putting on last child for %v: [%v]", childKv.K, commentStr)
// if it's an array of scalars, put the foot comment on the scalar itself
if len(childKv.V) > 0 && len(childKv.V[0].Children) == 0 {
nodeToUpdate := childKv.V[len(childKv.V)-1]
nodeToUpdate.FootComment = joinComments([]string{nodeToUpdate.FootComment, commentStr}, " ")
} else {
childKv.FootComment = joinComments([]string{elem.n.FootComment, commentStr}, " ")
}
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 = joinComments([]string{elem.n.FootComment, commentStr}, " ")
elem.n.FootComment = joinFilter([]string{elem.n.FootComment, commentStr})
}
}
func joinComments(rawStrings []string, joinStr string) string {
func joinFilter(rawStrings []string) string {
stringsToJoin := make([]string, 0)
for _, str := range rawStrings {
if str != "" {
stringsToJoin = append(stringsToJoin, str)
}
}
return strings.Join(stringsToJoin, joinStr)
return strings.Join(stringsToJoin, " ")
}
// trimNonGraphic returns a slice of the string s, with all leading and trailing
+7 -36
View File
@@ -2,7 +2,6 @@ package yqlib
import (
"bufio"
"bytes"
"errors"
"io"
"regexp"
@@ -13,15 +12,11 @@ import (
type yamlDecoder struct {
decoder yaml.Decoder
prefs YamlPreferences
// work around of various parsing issues by yaml.v3 with document headers
prefs YamlPreferences
leadingContent string
bufferRead bytes.Buffer
readAnything bool
firstFile bool
readAnything bool
firstFile bool
}
func NewYamlDecoder(prefs YamlPreferences) Decoder {
@@ -30,7 +25,6 @@ func NewYamlDecoder(prefs YamlPreferences) Decoder {
func (dec *yamlDecoder) processReadStream(reader *bufio.Reader) (io.Reader, string, error) {
var commentLineRegEx = regexp.MustCompile(`^\s*#`)
var yamlDirectiveLineRegEx = regexp.MustCompile(`^\s*%YA`)
var sb strings.Builder
for {
peekBytes, err := reader.Peek(3)
@@ -39,23 +33,15 @@ func (dec *yamlDecoder) processReadStream(reader *bufio.Reader) (io.Reader, stri
return reader, sb.String(), nil
} else if err != nil {
return reader, sb.String(), err
} else if string(peekBytes[0]) == "\n" {
_, err := reader.ReadString('\n')
sb.WriteString("\n")
if errors.Is(err, io.EOF) {
return reader, sb.String(), nil
} else if err != nil {
return reader, sb.String(), err
}
} else if string(peekBytes) == "---" {
_, err := reader.ReadString('\n')
sb.WriteString("$yqDocSeparator$\n")
sb.WriteString("$yqDocSeperator$\n")
if errors.Is(err, io.EOF) {
return reader, sb.String(), nil
} else if err != nil {
return reader, sb.String(), err
}
} else if commentLineRegEx.MatchString(string(peekBytes)) || yamlDirectiveLineRegEx.MatchString(string(peekBytes)) {
} else if commentLineRegEx.MatchString(string(peekBytes)) {
line, err := reader.ReadString('\n')
sb.WriteString(line)
if errors.Is(err, io.EOF) {
@@ -72,7 +58,6 @@ func (dec *yamlDecoder) processReadStream(reader *bufio.Reader) (io.Reader, stri
func (dec *yamlDecoder) Init(reader io.Reader) error {
readerToUse := reader
leadingContent := ""
dec.bufferRead = bytes.Buffer{}
var err error
// if we 'evaluating together' - we only process the leading content
// of the first file - this ensures comments from subsequent files are
@@ -82,12 +67,6 @@ func (dec *yamlDecoder) Init(reader io.Reader) error {
if err != nil {
return err
}
} else if !dec.prefs.LeadingContentPreProcessing {
// if we're not process the leading content
// keep a copy of what we've read. This is incase its a
// doc with only comments - the decoder will return nothing
// then we can read the comments from bufferRead
readerToUse = io.TeeReader(reader, &dec.bufferRead)
}
dec.leadingContent = leadingContent
dec.readAnything = false
@@ -98,20 +77,13 @@ func (dec *yamlDecoder) Init(reader io.Reader) error {
func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
var dataBucket yaml.Node
err := dec.decoder.Decode(&dataBucket)
if errors.Is(err, io.EOF) && dec.leadingContent != "" && !dec.readAnything {
// force returning an empty node with a comment.
dec.readAnything = true
return dec.blankNodeWithComment(), nil
} else if errors.Is(err, io.EOF) && !dec.prefs.LeadingContentPreProcessing && !dec.readAnything {
// didn't find any yaml,
// check the tee buffer, maybe there were comments
dec.readAnything = true
dec.leadingContent = dec.bufferRead.String()
if dec.leadingContent != "" {
return dec.blankNodeWithComment(), nil
}
return nil, err
} else if err != nil {
return nil, err
}
@@ -124,7 +96,6 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
candidateNode.LeadingContent = dec.leadingContent
dec.leadingContent = ""
}
dec.readAnything = true
// move document comments into candidate node
// otherwise unwrap drops them.
candidateNode.TrailingContent = dataBucket.FootComment
-17
View File
@@ -86,23 +86,6 @@ will output
a: ['dog', 'cat']
```
## Prepend to existing array
Given a sample.yml file of:
```yaml
a:
- dog
```
then
```bash
yq '.a = ["cat"] + .a' sample.yml
```
will output
```yaml
a:
- cat
- dog
```
## Add new object to array
Given a sample.yml file of:
```yaml
@@ -302,7 +302,7 @@ foobar:
```
## Dereference and update a field
Use explode with multiply to dereference an object
`Use explode with multiply to dereference an object
Given a sample.yml file of:
```yaml
-28
View File
@@ -1,28 +0,0 @@
# Array to Map
Use this operator to convert an array to..a map. The indices are used as map keys, null values in the array are skipped over.
Behind the scenes, this is implemented using reduce:
```
(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)
```
## Simple example
Given a sample.yml file of:
```yaml
cool:
- null
- null
- hello
```
then
```bash
yq '.cool |= array_to_map' sample.yml
```
will output
```yaml
cool:
2: hello
```
+4 -4
View File
@@ -3,10 +3,10 @@
This operator is used to update node values. It can be used in either the:
### plain form: `=`
Which will set the LHS node values equal to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
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, but the RHS expression is run with _each LHS node as context_. This is useful for updating values based on old values, e.g. increment.
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
### Flags
@@ -203,7 +203,7 @@ a:
```
## Update node value that has an anchor
Anchor will remain
Anchor will remaple
Given a sample.yml file of:
```yaml
@@ -250,7 +250,7 @@ a: !cat woof
b: !dog woof
```
## Custom types: clobber
## Custom types: clovver
Use the `c` option to clobber custom tags
Given a sample.yml file of:
@@ -26,24 +26,6 @@ will output
true
```
## "yes" and "no" are strings
In the yaml 1.2 standard, support for yes/no as booleans was dropped - they are now considered strings. See '10.2.1.2. Boolean' in https://yaml.org/spec/1.2.2/
Given a sample.yml file of:
```yaml
- yes
- no
```
then
```bash
yq '.[] | tag' sample.yml
```
will output
```yaml
!!str
!!str
```
## `and` example
Running
```bash
+2 -5
View File
@@ -5,10 +5,10 @@ Use these comment operators to set or retrieve comments. Note that line comments
Like the `=` and `|=` assign operators, the same syntax applies when updating comments:
### plain form: `=`
This will set the LHS nodes' comments equal to the expression on the RHS. The RHS is run against the matching nodes in the pipeline
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: `|=`
This is similar to the plain form, but it evaluates the RHS with _each matching LHS node as context_. This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
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.
## Set line comment
Set the comment on the key node for more reliability (see below).
@@ -247,7 +247,6 @@ Note the use of `...` to ensure key nodes are included.
Given a sample.yml file of:
```yaml
# hi
a: cat # comment
# great
b: # key comment
@@ -266,7 +265,6 @@ b:
Given a sample.yml file of:
```yaml
# welcome!
a: cat # meow
# have a great day
```
@@ -295,7 +293,6 @@ yq '. | head_comment' sample.yml
will output
```yaml
welcome!
```
## Head comment with document split
+1 -27
View File
@@ -1,14 +1,6 @@
# Contains
This returns `true` if the context contains the passed in parameter, and false otherwise. For arrays, this will return true if the passed in array is contained within the array. For strings, it will return true if the string is a substring.
{% hint style="warning" %}
_Note_ that, just like jq, when checking if an array of strings `contains` another, this will use `contains` and _not_ equals to check each string. This means an expression like `contains(["cat"])` will return true for an array `["cats"]`.
See the "Array has a subset array" example below on how to check for a subset.
{% endhint %}
This returns `true` if the context contains the passed in parameter, and false otherwise.
## Array contains array
Array is equal or subset of
@@ -28,24 +20,6 @@ will output
true
```
## Array has a subset array
Subtract the superset array from the subset, if there's anything left, it's not a subset
Given a sample.yml file of:
```yaml
- foobar
- foobaz
- blarp
```
then
```bash
yq '["baz", "bar"] - . | length == 0' sample.yml
```
will output
```yaml
false
```
## Object included in array
Given a sample.yml file of:
```yaml
+5 -29
View File
@@ -3,7 +3,7 @@
Various operators for parsing and manipulating dates.
## Date time formattings
This uses Golang's built in time library for parsing and formatting date times.
This uses the golangs built in time library for parsing and formatting date times.
When not specified, the RFC3339 standard is assumed `2006-01-02T15:04:05Z07:00` for parsing.
@@ -17,13 +17,13 @@ See the [library docs](https://pkg.go.dev/time#pkg-constants) for examples of fo
## Timezones
This uses Golang's built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
This uses golangs built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
## Durations
Durations are parsed using Golang's built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
You can add durations to time using the `+` operator.
You can durations to time using the `+` operator.
## Format: from standard RFC3339 format
Providing a single parameter assumes a standard RFC3339 datetime format. If the target format is not a valid yaml datetime format, the result will be a string tagged node.
@@ -60,7 +60,7 @@ a: 2001-12-15
## Format: get the day of the week
Given a sample.yml file of:
```yaml
a: 2001-12-15
a: 2001-12-15T02:59:43.1Z
```
then
```bash
@@ -86,30 +86,6 @@ a: cool
updated: 2021-05-19T01:02:03Z
```
## From Unix
Converts from unix time. Note, you don't have to pipe through the tz operator :)
Running
```bash
yq --null-input '1675301929 | from_unix | tz("UTC")'
```
will output
```yaml
2023-02-02T01:38:49Z
```
## To Unix
Converts to unix time
Running
```bash
yq --null-input 'now | to_unix'
```
will output
```yaml
1621386123
```
## Timezone: from standard RFC3339 format
Returns a new datetime in the specified timezone. Specify standard IANA Time Zone format or 'utc', 'local'. When given a single parameter, this assumes the datetime is in RFC3339 format.
-61
View File
@@ -1,61 +0,0 @@
# Divide
Divide behaves differently according to the type of the LHS:
* strings: split by the divider
* number: arithmetic division
## String split
Given a sample.yml file of:
```yaml
a: cat_meow
b: _
```
then
```bash
yq '.c = .a / .b' sample.yml
```
will output
```yaml
a: cat_meow
b: _
c:
- cat
- meow
```
## Number division
The result during division is calculated as a float
Given a sample.yml file of:
```yaml
a: 12
b: 2.5
```
then
```bash
yq '.a = .a / .b' sample.yml
```
will output
```yaml
a: 4.8
b: 2.5
```
## Number division by zero
Dividing by zero results in +Inf or -Inf
Given a sample.yml file of:
```yaml
a: 1
b: -1
```
then
```bash
yq '.a = .a / 0 | .b = .b / 0' sample.yml
```
will output
```yaml
a: !!float +Inf
b: !!float -Inf
```
+5 -51
View File
@@ -16,8 +16,6 @@ These operators are useful to process yaml documents that have stringified embed
| TSV | from_tsv/@tsvd | to_tsv/@tsv |
| XML | from_xml/@xmld | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
| URI | @urid | @uri |
| Shell | | @sh |
See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) for accepted formats.
@@ -25,7 +23,7 @@ See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) f
XML uses the `--xml-attribute-prefix` and `xml-content-name` flags to identify attributes and content fields.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a utf-8 string and not binary content.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a string.
## Encode value as json string
Given a sample.yml file of:
@@ -309,7 +307,7 @@ cat,"thing1,thing2",true,3.40
dog,thing3,false,12
```
## Encode array of arrays as tsv string
## Encode array of array scalars as tsv string
Scalars are strings, numbers and booleans.
Given a sample.yml file of:
@@ -339,7 +337,7 @@ Given a sample.yml file of:
a:
cool:
foo: bar
+@id: hi
+id: hi
```
then
```bash
@@ -359,7 +357,7 @@ Given a sample.yml file of:
a:
cool:
foo: bar
+@id: hi
+id: hi
```
then
```bash
@@ -377,7 +375,7 @@ Given a sample.yml file of:
a:
cool:
foo: bar
+@id: hi
+id: hi
```
then
```bash
@@ -437,50 +435,6 @@ will output
YTogYXBwbGUK
```
## Encode a string to uri
Given a sample.yml file of:
```yaml
coolData: this has & special () characters *
```
then
```bash
yq '.coolData | @uri' sample.yml
```
will output
```yaml
this+has+%26+special+%28%29+characters+%2A
```
## Decode a URI to a string
Given a sample.yml file of:
```yaml
this+has+%26+special+%28%29+characters+%2A
```
then
```bash
yq '@urid' sample.yml
```
will output
```yaml
this has & special () characters *
```
## Encode a string to sh
Sh/Bash friendly string
Given a sample.yml file of:
```yaml
coolData: strings with spaces and a 'quote'
```
then
```bash
yq '.coolData | @sh' sample.yml
```
will output
```yaml
strings' with spaces and a '\'quote\'
```
## Decode a base64 encoded string
Decoded data is assumed to be a string.
+1 -1
View File
@@ -67,7 +67,7 @@ a: 1
b: 2
```
## from_entries with numeric key indices
## from_entries with numeric key indexes
from_entries always creates a map, even for numeric keys
Given a sample.yml file of:
+2 -2
View File
@@ -2,9 +2,9 @@
Use `eval` to dynamically process an expression - for instance from an environment variable.
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, be it a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, beit a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
Tip: This can be a useful way to parameterise complex scripts.
Tip: This can be useful way parameterise complex scripts.
## Dynamically evaluate a path
Given a sample.yml file of:
-42
View File
@@ -1,42 +0,0 @@
# Filter
Filters an array (or map values) by the expression given. Equivalent to doing `map(select(exp))`.
## Filter array
Given a sample.yml file of:
```yaml
- 1
- 2
- 3
```
then
```bash
yq 'filter(. < 3)' sample.yml
```
will output
```yaml
- 1
- 2
```
## Filter map values
Given a sample.yml file of:
```yaml
c:
things: cool
frog: yes
d:
things: hot
frog: false
```
then
```bash
yq 'filter(.things == "cool")' sample.yml
```
will output
```yaml
- things: cool
frog: yes
```
+1 -1
View File
@@ -26,7 +26,7 @@ will output
bar: 100
```
## Group by field, with nulls
## Group by field, with nuls
Given a sample.yml file of:
```yaml
- cat: dog
+1 -1
View File
@@ -1,6 +1,6 @@
# Has
This operation returns true if the key exists in a map (or index in an array), false otherwise.
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
## Has map key
Given a sample.yml file of:
+1 -1
View File
@@ -26,7 +26,7 @@ yq '.a.b[0].c' file.yaml
cat file.yaml | yq '.a.b[0].c'
```
## Update a yaml file, in place
## Update a yaml file, inplace
```bash
yq -i '.a.b[0].c = "cool"' file.yaml
```
@@ -1,9 +0,0 @@
# Array to Map
Use this operator to convert an array to..a map. The indices are used as map keys, null values in the array are skipped over.
Behind the scenes, this is implemented using reduce:
```
(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)
```
@@ -3,10 +3,10 @@
This operator is used to update node values. It can be used in either the:
### plain form: `=`
Which will set the LHS node values equal to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
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, but the RHS expression is run with _each LHS node as context_. This is useful for updating values based on old values, e.g. increment.
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
### Flags
@@ -5,7 +5,7 @@ Use these comment operators to set or retrieve comments. Note that line comments
Like the `=` and `|=` assign operators, the same syntax applies when updating comments:
### plain form: `=`
This will set the LHS nodes' comments equal to the expression on the RHS. The RHS is run against the matching nodes in the pipeline
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: `|=`
This is similar to the plain form, but it evaluates the RHS with _each matching LHS node as context_. This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
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.
+1 -9
View File
@@ -1,11 +1,3 @@
# Contains
This returns `true` if the context contains the passed in parameter, and false otherwise. For arrays, this will return true if the passed in array is contained within the array. For strings, it will return true if the string is a substring.
{% hint style="warning" %}
_Note_ that, just like jq, when checking if an array of strings `contains` another, this will use `contains` and _not_ equals to check each string. This means an expression like `contains(["cat"])` will return true for an array `["cats"]`.
See the "Array has a subset array" example below on how to check for a subset.
{% endhint %}
This returns `true` if the context contains the passed in parameter, and false otherwise.
+4 -4
View File
@@ -3,7 +3,7 @@
Various operators for parsing and manipulating dates.
## Date time formattings
This uses Golang's built in time library for parsing and formatting date times.
This uses the golangs built in time library for parsing and formatting date times.
When not specified, the RFC3339 standard is assumed `2006-01-02T15:04:05Z07:00` for parsing.
@@ -17,10 +17,10 @@ See the [library docs](https://pkg.go.dev/time#pkg-constants) for examples of fo
## Timezones
This uses Golang's built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
This uses golangs built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
## Durations
Durations are parsed using Golang's built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
You can add durations to time using the `+` operator.
You can durations to time using the `+` operator.
@@ -1,5 +0,0 @@
# Divide
Divide behaves differently according to the type of the LHS:
* strings: split by the divider
* number: arithmetic division
@@ -16,8 +16,6 @@ These operators are useful to process yaml documents that have stringified embed
| TSV | from_tsv/@tsvd | to_tsv/@tsv |
| XML | from_xml/@xmld | to_xml(i)/@xml |
| Base64 | @base64d | @base64 |
| URI | @urid | @uri |
| Shell | | @sh |
See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) for accepted formats.
@@ -25,4 +23,4 @@ See CSV and TSV [documentation](https://mikefarah.gitbook.io/yq/usage/csv-tsv) f
XML uses the `--xml-attribute-prefix` and `xml-content-name` flags to identify attributes and content fields.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a utf-8 string and not binary content.
Base64 assumes [rfc4648](https://rfc-editor.org/rfc/rfc4648.html) encoding. Encoding and decoding both assume that the content is a string.
+2 -2
View File
@@ -2,6 +2,6 @@
Use `eval` to dynamically process an expression - for instance from an environment variable.
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, be it a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
`eval` takes a single argument, and evaluates that as a `yq` expression. Any valid expression can be used, beit a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
Tip: This can be a useful way to parameterise complex scripts.
Tip: This can be useful way parameterise complex scripts.
@@ -1,4 +0,0 @@
# Filter
Filters an array (or map values) by the expression given. Equivalent to doing `map(select(exp))`.
+1 -1
View File
@@ -1,3 +1,3 @@
# Has
This operation returns true if the key exists in a map (or index in an array), false otherwise.
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
-2
View File
@@ -14,8 +14,6 @@ You can load files of the following supported types:
| Plain String | load_str |
| Base64 | load_base64 |
Note that load_base64 only works for base64 encoded utf-8 strings.
## Samples files for tests:
### yaml
@@ -1,3 +0,0 @@
# Modulo
Arithmetic modulo operator, returns the remainder from dividing two numbers.
@@ -1,6 +1,6 @@
# 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.
This operator recursively matches (or globs) all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
## match values form `..`
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
@@ -12,7 +12,7 @@ yq '.. style= "flow"' file.yaml
```
## match values and map keys form `...`
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling and tags and also use anchors and aliases.
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
@@ -1,4 +0,0 @@
# Shuffle
Shuffles an array. Note that this command does _not_ use a cryptographically secure random number generator to randomise the array order.
@@ -1,5 +0,0 @@
# Slice/Splice Array
The slice array operator takes an array as input and returns a subarray. Like the `jq` equivalent, `.[10:15]` will return an array of length 5, starting from index 10 inclusive, up to index 15 exclusive. Negative numbers count backwards from the end of the array.
You may leave out the first or second number, which will will refer to the start or end of the array respectively.
+1 -1
View File
@@ -10,7 +10,7 @@ yq -i -P 'sort_keys(..)' 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 you are using merge anchors.
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.
For more advanced sorting, using `to_entries` to convert the map to an array, then sort/process the array as you like (e.g. using `sort_by`) and convert back to a map using `from_entries`.
See [here](https://mikefarah.gitbook.io/yq/operators/entries#custom-sort-map-keys) for an example.
@@ -1,7 +1,7 @@
# String Operators
## RegEx
This uses Golang's 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 their [docs](https://github.com/google/re2/wiki/Syntax) for the supported syntax.
Case insensitive tip: prefix the regex with `(?i)` - e.g. `test("(?i)cats)"`.
@@ -15,7 +15,7 @@ Capture returns named RegEx capture groups in a map. Can be more convenient than
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 parameter specifies what to replace those matches with. This can refer to capture groups from the first RegEx.
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
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_.
@@ -27,7 +27,7 @@ a: |
cat
```
Using `$( exp )` wont work, as it will trim the trailing newline.
Using `$( exp )` wont work, as it will trim the trailing new line.
```
m=$(echo "cat\n") yq -n '.a = strenv(m)'
@@ -49,7 +49,7 @@ a: |
cat
```
Similarly, if you're trying to set the content from a file, and want a trailing newline:
Similarly, if you're trying to set the content from a file, and want a trailing new line:
```
IFS= read -rd '' output < <(cat my_file)
+1 -1
View File
@@ -1,3 +1,3 @@
# Subtract
You can use subtract to subtract numbers as well as remove elements from an array.
You can use subtract to subtract numbers, as well as removing elements from an array.
@@ -1,3 +1,3 @@
# Traverse (Read)
This is the simplest (and perhaps most used) operator. It is used to navigate deeply into yaml structures.
This is the simplest (and perhaps most used) operator, it is used to navigate deeply into yaml structures.
+1 -1
View File
@@ -29,7 +29,7 @@ b:
```
then
```bash
yq '.b | key | line' sample.yml
yq '.b | key| line' sample.yml
```
will output
```yaml
-2
View File
@@ -14,8 +14,6 @@ You can load files of the following supported types:
| Plain String | load_str |
| Base64 | load_base64 |
Note that load_base64 only works for base64 encoded utf-8 strings.
## Samples files for tests:
### yaml
-75
View File
@@ -1,75 +0,0 @@
# Modulo
Arithmetic modulo operator, returns the remainder from dividing two numbers.
## Number modulo - int
If the lhs and rhs are ints then the expression will be calculated with ints.
Given a sample.yml file of:
```yaml
a: 13
b: 2
```
then
```bash
yq '.a = .a % .b' sample.yml
```
will output
```yaml
a: 1
b: 2
```
## Number modulo - float
If the lhs or rhs are floats then the expression will be calculated with floats.
Given a sample.yml file of:
```yaml
a: 12
b: 2.5
```
then
```bash
yq '.a = .a % .b' sample.yml
```
will output
```yaml
a: !!float 2
b: 2.5
```
## Number modulo - int by zero
If the lhs is an int and rhs is a 0 the result is an error.
Given a sample.yml file of:
```yaml
a: 1
b: 0
```
then
```bash
yq '.a = .a % .b' sample.yml
```
will output
```bash
Error: cannot modulo by 0
```
## Number modulo - float by zero
If the lhs is a float and rhs is a 0 the result is NaN.
Given a sample.yml file of:
```yaml
a: 1.1
b: 0
```
then
```bash
yq '.a = .a % .b' sample.yml
```
will output
```yaml
a: !!float NaN
b: 0
```
+2 -42
View File
@@ -250,7 +250,7 @@ thing:
```
## Merge, deeply merging arrays
Merging arrays deeply means arrays are merged like objects, with indices as their key. In this case, we merge the first item in the array and do nothing with the second.
Merging arrays deeply means arrays are merge like objects, with indexes as their key. In this case, we merge the first item in the array, and do nothing with the second.
Given a sample.yml file of:
```yaml
@@ -477,7 +477,7 @@ b: !goat
```
## Custom types: clobber tags
Use the `c` option to clobber custom tags. Note that the second tag is now used.
Use the `c` option to clobber custom tags. Note that the second tag is now used
Given a sample.yml file of:
```yaml
@@ -499,43 +499,3 @@ b: !goat
dog: woof
```
## Merging a null with a map
Running
```bash
yq --null-input 'null * {"some": "thing"}'
```
will output
```yaml
some: thing
```
## Merging a map with null
Running
```bash
yq --null-input '{"some": "thing"} * null'
```
will output
```yaml
some: thing
```
## Merging an null with an array
Running
```bash
yq --null-input 'null * ["some"]'
```
will output
```yaml
- some
```
## Merging an array with null
Running
```bash
yq --null-input '["some"] * null'
```
will output
```yaml
- some
```
-27
View File
@@ -122,33 +122,6 @@ a:
b: things
```
## Set path to prune deep paths
Like pick but recursive. This uses `ireduce` to deeply set the selected paths into an empty object.
Given a sample.yml file of:
```yaml
parentA: bob
parentB:
child1: i am child1
child2: i am child2
parentC:
child1: me child1
child2: me child2
```
then
```bash
yq '(.parentB.child2, .parentC.child1) as $i
ireduce({}; setpath($i | path; $i))' sample.yml
```
will output
```yaml
parentB:
child2: i am child2
parentC:
child1: me child1
```
## Set array path
Given a sample.yml file of:
```yaml
+3 -3
View File
@@ -13,7 +13,7 @@ myMap:
cat: meow
dog: bark
thing: hamster
hamster: squeak
hamster: squeek
```
then
```bash
@@ -22,12 +22,12 @@ yq '.myMap |= pick(["hamster", "cat", "goat"])' sample.yml
will output
```yaml
myMap:
hamster: squeak
hamster: squeek
cat: meow
```
## Pick indices from array
Note that the order of the indices matches the pick order and non existent indices are skipped.
Note that the order of the indexes matches the pick order and non existent indexes are skipped.
Given a sample.yml file of:
```yaml
@@ -1,6 +1,6 @@
# 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.
This operator recursively matches (or globs) all children nodes given of a particular element, including that node itself. This is most often used to apply a filter recursively against all matches. It can be used in either the
## match values form `..`
This will, like the `jq` equivalent, recursively match all _value_ nodes. Use it to find/manipulate particular values.
@@ -12,7 +12,7 @@ yq '.. style= "flow"' file.yaml
```
## match values and map keys form `...`
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling and tags and also use anchors and aliases.
The also includes map keys in the results set. This is particularly useful in YAML as unlike JSON, map keys can have their own styling, tags and use anchors and aliases.
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
+1 -1
View File
@@ -62,7 +62,7 @@ going
```
## Select elements from array with regular expression
See more regular expression examples under the [`string` operator docs](https://mikefarah.gitbook.io/yq/operators/string-operators).
See more regular expression examples under the `string` operator docs.
Given a sample.yml file of:
```yaml
-51
View File
@@ -1,51 +0,0 @@
# Shuffle
Shuffles an array. Note that this command does _not_ use a cryptographically secure random number generator to randomise the array order.
## Shuffle array
Given a sample.yml file of:
```yaml
- 1
- 2
- 3
- 4
- 5
```
then
```bash
yq 'shuffle' sample.yml
```
will output
```yaml
- 5
- 2
- 4
- 1
- 3
```
## Shuffle array in place
Given a sample.yml file of:
```yaml
cool:
- 1
- 2
- 3
- 4
- 5
```
then
```bash
yq '.cool |= shuffle' sample.yml
```
will output
```yaml
cool:
- 5
- 2
- 4
- 1
- 3
```
-105
View File
@@ -1,105 +0,0 @@
# Slice/Splice Array
The slice array operator takes an array as input and returns a subarray. Like the `jq` equivalent, `.[10:15]` will return an array of length 5, starting from index 10 inclusive, up to index 15 exclusive. Negative numbers count backwards from the end of the array.
You may leave out the first or second number, which will will refer to the start or end of the array respectively.
## Slicing arrays
Given a sample.yml file of:
```yaml
- cat
- dog
- frog
- cow
```
then
```bash
yq '.[1:3]' sample.yml
```
will output
```yaml
- dog
- frog
```
## Slicing arrays - without the first number
Starts from the start of the array
Given a sample.yml file of:
```yaml
- cat
- dog
- frog
- cow
```
then
```bash
yq '.[:2]' sample.yml
```
will output
```yaml
- cat
- dog
```
## Slicing arrays - without the second number
Finishes at the end of the array
Given a sample.yml file of:
```yaml
- cat
- dog
- frog
- cow
```
then
```bash
yq '.[2:]' sample.yml
```
will output
```yaml
- frog
- cow
```
## Slicing arrays - use negative numbers to count backwards from the end
Given a sample.yml file of:
```yaml
- cat
- dog
- frog
- cow
```
then
```bash
yq '.[1:-1]' sample.yml
```
will output
```yaml
- dog
- frog
```
## Inserting into the middle of an array
using an expression to find the index
Given a sample.yml file of:
```yaml
- cat
- dog
- frog
- cow
```
then
```bash
yq '(.[] | select(. == "dog") | key + 1) as $pos | .[0:($pos)] + ["rabbit"] + .[$pos:]' sample.yml
```
will output
```yaml
- cat
- dog
- rabbit
- frog
- cow
```

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