mirror of
https://github.com/mikefarah/yq.git
synced 2025-02-05 11:20:21 +00:00
Merge branch 'master' into toml
This commit is contained in:
commit
f116ef8fd0
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.20'
|
||||
id: go
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.20'
|
||||
check-latest: true
|
||||
|
@ -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
|
||||
|
@ -4,7 +4,7 @@ WORKDIR /go/src/mikefarah/yq
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 go build .
|
||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w" .
|
||||
# RUN ./scripts/test.sh -- this too often times out in the github pipeline.
|
||||
RUN ./scripts/acceptance.sh
|
||||
|
||||
|
@ -7,6 +7,7 @@ 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 ?=
|
||||
|
||||
|
11
README.md
11
README.md
@ -229,6 +229,8 @@ 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
|
||||
|
||||
@ -286,15 +288,6 @@ 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
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
setUp() {
|
||||
rm test*.yml 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
|
||||
@ -29,6 +30,22 @@ EOM
|
||||
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" } }
|
||||
|
24
cmd/utils.go
24
cmd/utils.go
@ -10,6 +10,10 @@ 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
|
||||
|
||||
@ -60,15 +64,20 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
|
||||
if inputFormat == "" || inputFormat == "auto" || inputFormat == "a" {
|
||||
|
||||
inputFormat = yqlib.FormatFromFilename(inputFilename)
|
||||
if outputFormat == "" || outputFormat == "auto" || outputFormat == "a" {
|
||||
if inputFormat == "toml" {
|
||||
// toml not yet supported for output
|
||||
|
||||
_, 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 {
|
||||
outputFormat = yqlib.FormatFromFilename(inputFilename)
|
||||
}
|
||||
} else if isAutomaticOutputFormat() {
|
||||
// automatic input worked, we can do it for output too unless specified
|
||||
outputFormat = inputFormat
|
||||
}
|
||||
} else if outputFormat == "" || outputFormat == "auto" || outputFormat == "a" {
|
||||
} else if isAutomaticOutputFormat() {
|
||||
// backwards compatibility -
|
||||
// before this was introduced, `yq -pcsv things.csv`
|
||||
// would produce *yaml* output.
|
||||
@ -85,7 +94,8 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
yqlib.GetLogger().Debug("Using outputformat %v", outputFormat)
|
||||
yqlib.GetLogger().Debug("Using input format %v", inputFormat)
|
||||
yqlib.GetLogger().Debug("Using output format %v", outputFormat)
|
||||
|
||||
if outputFormatType == yqlib.YamlOutputFormat ||
|
||||
outputFormatType == yqlib.PropsOutputFormat {
|
||||
|
@ -11,7 +11,7 @@ var (
|
||||
GitDescribe string
|
||||
|
||||
// Version is main version number that is being run at the moment.
|
||||
Version = "v4.31.2"
|
||||
Version = "v4.32.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
|
||||
|
2
debian/changelog
vendored
2
debian/changelog
vendored
@ -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
|
||||
|
||||
|
4
go.mod
4
go.mod
@ -6,8 +6,8 @@ require (
|
||||
github.com/alecthomas/repr v0.2.0
|
||||
github.com/dimchansky/utfbom v1.1.1
|
||||
github.com/elliotchance/orderedmap v1.5.0
|
||||
github.com/fatih/color v1.14.1
|
||||
github.com/goccy/go-json v0.10.0
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/goccy/go-json v0.10.2
|
||||
github.com/goccy/go-yaml v1.10.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/magiconair/properties v1.8.7
|
||||
|
8
go.sum
8
go.sum
@ -14,14 +14,14 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
|
||||
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.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
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.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
|
||||
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
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.10.0 h1:rBi+5HGuznOxx0JZ+60LDY85gc0dyIJCIMvsMJTKSKQ=
|
||||
github.com/goccy/go-yaml v1.10.0/go.mod h1:h/18Lr6oSQ3mvmqFoWmQ47KChOgpfHpTyIHl3yVmpiY=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
|
@ -4,10 +4,33 @@ 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
|
||||
@ -20,7 +43,7 @@ func NewBase64Decoder() Decoder {
|
||||
}
|
||||
|
||||
func (dec *base64Decoder) Init(reader io.Reader) error {
|
||||
dec.reader = reader
|
||||
dec.reader = &base64Padder{Reader: reader}
|
||||
dec.readAnything = false
|
||||
dec.finished = false
|
||||
return nil
|
||||
|
@ -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
|
||||
|
@ -3,10 +3,10 @@
|
||||
This operator is used to update node values. It can be used in either the:
|
||||
|
||||
### plain form: `=`
|
||||
Which will assign the LHS node values to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
|
||||
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.
|
||||
|
||||
### relative form: `|=`
|
||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
||||
This will do a similar thing to the plain form, 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.
|
||||
|
||||
|
||||
### Flags
|
||||
@ -203,7 +203,7 @@ a:
|
||||
```
|
||||
|
||||
## Update node value that has an anchor
|
||||
Anchor will remaple
|
||||
Anchor will remain
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@ -250,7 +250,7 @@ a: !cat woof
|
||||
b: !dog woof
|
||||
```
|
||||
|
||||
## Custom types: clovver
|
||||
## Custom types: clobber
|
||||
Use the `c` option to clobber custom tags
|
||||
|
||||
Given a sample.yml file of:
|
||||
|
@ -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 assign the LHS nodes comments to the expression on the RHS. The RHS is run against the matching nodes in the pipeline
|
||||
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
|
||||
|
||||
### relative form: `|=`
|
||||
Similar to the plain form, however the RHS evaluates against each matching LHS node! This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
|
||||
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.
|
||||
|
||||
## Set line comment
|
||||
Set the comment on the key node for more reliability (see below).
|
||||
|
@ -4,7 +4,7 @@ This returns `true` if the context contains the passed in parameter, and false o
|
||||
|
||||
{% 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 array like `contains(["cat"])` will return true for an array `["cats"]`.
|
||||
_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.
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
Various operators for parsing and manipulating dates.
|
||||
|
||||
## Date time formattings
|
||||
This uses the golangs built in time library for parsing and formatting date times.
|
||||
This uses Golang's 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 golangs built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
|
||||
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.
|
||||
|
||||
|
||||
## Durations
|
||||
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
Durations are parsed using Golang's built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
|
||||
You can durations to time using the `+` operator.
|
||||
You can add 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.
|
||||
|
61
pkg/yqlib/doc/operators/divide.md
Normal file
61
pkg/yqlib/doc/operators/divide.md
Normal file
@ -0,0 +1,61 @@
|
||||
# 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
|
||||
```
|
||||
|
@ -309,7 +309,7 @@ cat,"thing1,thing2",true,3.40
|
||||
dog,thing3,false,12
|
||||
```
|
||||
|
||||
## Encode array of array scalars as tsv string
|
||||
## Encode array of arrays as tsv string
|
||||
Scalars are strings, numbers and booleans.
|
||||
|
||||
Given a sample.yml file of:
|
||||
|
@ -67,7 +67,7 @@ a: 1
|
||||
b: 2
|
||||
```
|
||||
|
||||
## from_entries with numeric key indexes
|
||||
## from_entries with numeric key indices
|
||||
from_entries always creates a map, even for numeric keys
|
||||
|
||||
Given a sample.yml file of:
|
||||
|
@ -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, beit 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, be it a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
|
||||
|
||||
Tip: This can be useful way parameterise complex scripts.
|
||||
Tip: This can be a useful way to parameterise complex scripts.
|
||||
|
||||
## Dynamically evaluate a path
|
||||
Given a sample.yml file of:
|
||||
|
@ -1,3 +1,7 @@
|
||||
# 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:
|
||||
@ -16,3 +20,23 @@ will output
|
||||
- 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,6 +1,6 @@
|
||||
# Has
|
||||
|
||||
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
|
||||
This operation 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:
|
||||
|
@ -3,10 +3,10 @@
|
||||
This operator is used to update node values. It can be used in either the:
|
||||
|
||||
### plain form: `=`
|
||||
Which will assign the LHS node values to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
|
||||
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.
|
||||
|
||||
### relative form: `|=`
|
||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
||||
This will do a similar thing to the plain form, 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.
|
||||
|
||||
|
||||
### 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 assign the LHS nodes comments to the expression on the RHS. The RHS is run against the matching nodes in the pipeline
|
||||
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
|
||||
|
||||
### relative form: `|=`
|
||||
Similar to the plain form, however the RHS evaluates against each matching LHS node! This is useful if you want to set the comments as a relative expression of the node, for instance its value or path.
|
||||
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.
|
||||
|
@ -4,7 +4,7 @@ This returns `true` if the context contains the passed in parameter, and false o
|
||||
|
||||
{% 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 array like `contains(["cat"])` will return true for an array `["cats"]`.
|
||||
_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.
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
Various operators for parsing and manipulating dates.
|
||||
|
||||
## Date time formattings
|
||||
This uses the golangs built in time library for parsing and formatting date times.
|
||||
This uses Golang's 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 golangs built in LoadLocation function to parse timezones strings. See the [library docs](https://pkg.go.dev/time#LoadLocation) for more details.
|
||||
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.
|
||||
|
||||
|
||||
## Durations
|
||||
Durations are parsed using golangs built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
Durations are parsed using Golang's built in [ParseDuration](https://pkg.go.dev/time#ParseDuration) function.
|
||||
|
||||
You can durations to time using the `+` operator.
|
||||
You can add durations to time using the `+` operator.
|
||||
|
5
pkg/yqlib/doc/operators/headers/divide.md
Normal file
5
pkg/yqlib/doc/operators/headers/divide.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Divide
|
||||
|
||||
Divide behaves differently according to the type of the LHS:
|
||||
* strings: split by the divider
|
||||
* number: arithmetic division
|
@ -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, beit 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, be it a path `.a.b.c | select(. == "cat")`, or an update `.a.b.c = "gogo"`.
|
||||
|
||||
Tip: This can be useful way parameterise complex scripts.
|
||||
Tip: This can be a useful way to parameterise complex scripts.
|
||||
|
4
pkg/yqlib/doc/operators/headers/filter.md
Normal file
4
pkg/yqlib/doc/operators/headers/filter.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Filter
|
||||
|
||||
Filters an array (or map values) by the expression given. Equivalent to doing `map(select(exp))`.
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Has
|
||||
|
||||
This is operation that returns true if the key exists in a map (or index in an array), false otherwise.
|
||||
This operation returns true if the key exists in a map (or index in an array), false otherwise.
|
||||
|
3
pkg/yqlib/doc/operators/headers/modulo.md
Normal file
3
pkg/yqlib/doc/operators/headers/modulo.md
Normal file
@ -0,0 +1,3 @@
|
||||
# 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. It can be used in either the
|
||||
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.
|
||||
|
||||
## 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, tags and 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 and tags and also use anchors and aliases.
|
||||
|
||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||
|
||||
|
@ -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 your are using merge anchors.
|
||||
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.
|
||||
|
||||
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 golangs native regex functions under the hood - See their [docs](https://github.com/google/re2/wiki/Syntax) for the supported syntax.
|
||||
This uses Golang's 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 is a 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 parameter specifies 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 new line.
|
||||
Using `$( exp )` wont work, as it will trim the trailing newline.
|
||||
|
||||
```
|
||||
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 new line:
|
||||
Similarly, if you're trying to set the content from a file, and want a trailing newline:
|
||||
|
||||
```
|
||||
IFS= read -rd '' output < <(cat my_file)
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Subtract
|
||||
|
||||
You can use subtract to subtract numbers, as well as removing elements from an array.
|
||||
You can use subtract to subtract numbers as well as remove 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.
|
||||
|
@ -29,7 +29,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.b | key| line' sample.yml
|
||||
yq '.b | key | line' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
75
pkg/yqlib/doc/operators/modulo.md
Normal file
75
pkg/yqlib/doc/operators/modulo.md
Normal file
@ -0,0 +1,75 @@
|
||||
# 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
|
||||
```
|
||||
|
@ -250,7 +250,7 @@ thing:
|
||||
```
|
||||
|
||||
## Merge, deeply merging arrays
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
|
@ -123,7 +123,7 @@ a:
|
||||
```
|
||||
|
||||
## Set path to prune deep paths
|
||||
Like pick but recursive. This uses `ireduce` to deeply set the selected paths into an empty object,
|
||||
Like pick but recursive. This uses `ireduce` to deeply set the selected paths into an empty object.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
|
@ -27,7 +27,7 @@ myMap:
|
||||
```
|
||||
|
||||
## Pick indices from array
|
||||
Note that the order of the indexes matches the pick order and non existent indexes are skipped.
|
||||
Note that the order of the indices matches the pick order and non existent indices 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. It can be used in either the
|
||||
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.
|
||||
|
||||
## 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, tags and 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 and tags and also use anchors and aliases.
|
||||
|
||||
For instance to set the `style` of all nodes in a yaml doc, including the map keys:
|
||||
|
||||
|
@ -62,7 +62,7 @@ going
|
||||
```
|
||||
|
||||
## Select elements from array with regular expression
|
||||
See more regular expression examples under the `string` operator docs.
|
||||
See more regular expression examples under the [`string` operator docs](https://mikefarah.gitbook.io/yq/operators/string-operators).
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
|
@ -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 your are using merge anchors.
|
||||
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.
|
||||
|
||||
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 golangs native regex functions under the hood - See their [docs](https://github.com/google/re2/wiki/Syntax) for the supported syntax.
|
||||
This uses Golang's 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 is a 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 parameter specifies 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 new line.
|
||||
Using `$( exp )` wont work, as it will trim the trailing newline.
|
||||
|
||||
```
|
||||
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 new line:
|
||||
Similarly, if you're trying to set the content from a file, and want a trailing newline:
|
||||
|
||||
```
|
||||
IFS= read -rd '' output < <(cat my_file)
|
||||
@ -298,7 +298,7 @@ false
|
||||
```
|
||||
|
||||
## Substitute / Replace string
|
||||
This uses golang regex, described [here](https://github.com/google/re2/wiki/Syntax)
|
||||
This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).
|
||||
Note the use of `|=` to run in context of the current string value.
|
||||
|
||||
Given a sample.yml file of:
|
||||
@ -315,7 +315,7 @@ a: cats are great
|
||||
```
|
||||
|
||||
## Substitute / Replace string with regex
|
||||
This uses golang regex, described [here](https://github.com/google/re2/wiki/Syntax)
|
||||
This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).
|
||||
Note the use of `|=` to run in context of the current string value.
|
||||
|
||||
Given a sample.yml file of:
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Subtract
|
||||
|
||||
You can use subtract to subtract numbers, as well as removing elements from an array.
|
||||
You can use subtract to subtract numbers as well as remove elements from an array.
|
||||
|
||||
## Array subtraction
|
||||
Running
|
||||
@ -59,24 +59,6 @@ a: -1.5
|
||||
b: 4.5
|
||||
```
|
||||
|
||||
## Number subtraction - float
|
||||
If the lhs or rhs are floats then the expression will be calculated with floats.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: 3
|
||||
b: 4.5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a = .a - .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: -1.5
|
||||
b: 4.5
|
||||
```
|
||||
|
||||
## Number subtraction - int
|
||||
If both the lhs and rhs are ints then the expression will be calculated with ints.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
|
||||
## Simple map navigation
|
||||
Given a sample.yml file of:
|
||||
@ -51,7 +51,7 @@ will output
|
||||
```
|
||||
|
||||
## Special characters
|
||||
Use quotes with brackets around path elements with special characters
|
||||
Use quotes with square brackets around path elements with special characters
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@ -83,7 +83,7 @@ apple
|
||||
```
|
||||
|
||||
## Keys with spaces
|
||||
Use quotes with brackets around path elements with special characters
|
||||
Use quotes with square brackets around path elements with special characters
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
|
@ -51,7 +51,7 @@ func (pe *propertiesEncoder) PrintLeadingContent(writer io.Writer, content strin
|
||||
|
||||
if errors.Is(errReading, io.EOF) {
|
||||
if readline != "" {
|
||||
// the last comment we read didn't have a new line, put one in
|
||||
// the last comment we read didn't have a newline, put one in
|
||||
if err := writeString(writer, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ func (ye *yamlEncoder) PrintLeadingContent(writer io.Writer, content string) err
|
||||
|
||||
if errors.Is(errReading, io.EOF) {
|
||||
if readline != "" {
|
||||
// the last comment we read didn't have a new line, put one in
|
||||
// the last comment we read didn't have a newline, put one in
|
||||
if err := writeString(writer, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -210,6 +210,10 @@ var participleYqRules = []*participleYqRule{
|
||||
{"MultiplyAssign", `\*=[\+|\?cdn]*`, multiplyWithPrefs(multiplyAssignOpType), 0},
|
||||
{"Multiply", `\*[\+|\?cdn]*`, multiplyWithPrefs(multiplyOpType), 0},
|
||||
|
||||
{"Divide", `\/`, opToken(divideOpType), 0},
|
||||
|
||||
{"Modulo", `%`, opToken(moduloOpType), 0},
|
||||
|
||||
{"AddAssign", `\+=`, opToken(addAssignOpType), 0},
|
||||
{"Add", `\+`, opToken(addOpType), 0},
|
||||
|
||||
|
@ -62,6 +62,10 @@ var assignAliasOpType = &operationType{Type: "ASSIGN_ALIAS", NumArgs: 2, Precede
|
||||
var multiplyOpType = &operationType{Type: "MULTIPLY", NumArgs: 2, Precedence: 42, Handler: multiplyOperator}
|
||||
var multiplyAssignOpType = &operationType{Type: "MULTIPLY_ASSIGN", NumArgs: 2, Precedence: 42, Handler: multiplyAssignOperator}
|
||||
|
||||
var divideOpType = &operationType{Type: "DIVIDE", NumArgs: 2, Precedence: 42, Handler: divideOperator}
|
||||
|
||||
var moduloOpType = &operationType{Type: "MODULO", NumArgs: 2, Precedence: 42, Handler: moduloOperator}
|
||||
|
||||
var addOpType = &operationType{Type: "ADD", NumArgs: 2, Precedence: 42, Handler: addOperator}
|
||||
var subtractOpType = &operationType{Type: "SUBTRACT", NumArgs: 2, Precedence: 42, Handler: subtractOperator}
|
||||
var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 42, Handler: alternativeOperator}
|
||||
|
@ -228,7 +228,7 @@ foobar:
|
||||
},
|
||||
{
|
||||
description: "Dereference and update a field",
|
||||
subdescription: "`Use explode with multiply to dereference an object",
|
||||
subdescription: "Use explode with multiply to dereference an object",
|
||||
document: simpleArrayRef,
|
||||
expression: `.thingOne |= explode(.) * {"value": false}`,
|
||||
expected: []string{expectedUpdatedArrayRef},
|
||||
|
@ -196,7 +196,7 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Update node value that has an anchor",
|
||||
subdescription: "Anchor will remaple",
|
||||
subdescription: "Anchor will remain",
|
||||
dontFormatInputForDoc: true,
|
||||
document: `a: &cool cat`,
|
||||
expression: `.a = "dog"`,
|
||||
@ -230,7 +230,7 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Custom types: clovver",
|
||||
description: "Custom types: clobber",
|
||||
subdescription: "Use the `c` option to clobber custom tags",
|
||||
document: "a: !cat meow\nb: !dog woof",
|
||||
expression: `.a =c .b`,
|
||||
|
78
pkg/yqlib/operator_divide.go
Normal file
78
pkg/yqlib/operator_divide.go
Normal file
@ -0,0 +1,78 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func divideOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("Divide operator")
|
||||
|
||||
return crossFunction(d, context.ReadOnlyClone(), expressionNode, divide, false)
|
||||
}
|
||||
|
||||
func divide(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
lhs.Node = unwrapDoc(lhs.Node)
|
||||
rhs.Node = unwrapDoc(rhs.Node)
|
||||
|
||||
lhsNode := lhs.Node
|
||||
|
||||
if lhsNode.Tag == "!!null" {
|
||||
return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath())
|
||||
}
|
||||
|
||||
target := &yaml.Node{}
|
||||
|
||||
if lhsNode.Kind == yaml.ScalarNode && rhs.Node.Kind == yaml.ScalarNode {
|
||||
if err := divideScalars(target, lhsNode, rhs.Node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("%v (%v) cannot be divided by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath())
|
||||
}
|
||||
|
||||
return lhs.CreateReplacement(target), nil
|
||||
}
|
||||
|
||||
func divideScalars(target *yaml.Node, lhs *yaml.Node, rhs *yaml.Node) error {
|
||||
lhsTag := lhs.Tag
|
||||
rhsTag := guessTagFromCustomType(rhs)
|
||||
lhsIsCustom := false
|
||||
if !strings.HasPrefix(lhsTag, "!!") {
|
||||
// custom tag - we have to have a guess
|
||||
lhsTag = guessTagFromCustomType(lhs)
|
||||
lhsIsCustom = true
|
||||
}
|
||||
|
||||
if lhsTag == "!!str" && rhsTag == "!!str" {
|
||||
res := split(lhs.Value, rhs.Value)
|
||||
target.Kind = res.Kind
|
||||
target.Tag = res.Tag
|
||||
target.Content = res.Content
|
||||
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
|
||||
target.Kind = yaml.ScalarNode
|
||||
target.Style = lhs.Style
|
||||
|
||||
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
quotient := lhsNum / rhsNum
|
||||
if lhsIsCustom {
|
||||
target.Tag = lhs.Tag
|
||||
} else {
|
||||
target.Tag = "!!float"
|
||||
}
|
||||
target.Value = fmt.Sprintf("%v", quotient)
|
||||
} else {
|
||||
return fmt.Errorf("%v cannot be divided by %v", lhsTag, rhsTag)
|
||||
}
|
||||
return nil
|
||||
}
|
130
pkg/yqlib/operator_divide_test.go
Normal file
130
pkg/yqlib/operator_divide_test.go
Normal file
@ -0,0 +1,130 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var divideOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `[{a: foo_bar, b: _}, {a: 4, b: 2}]`,
|
||||
expression: ".[] | .a / .b",
|
||||
expected: []string{
|
||||
"D0, P[0 a], (!!seq)::- foo\n- bar\n",
|
||||
"D0, P[1 a], (!!float)::2\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{}`,
|
||||
expression: "(.a / .b) as $x | .",
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "String split",
|
||||
document: `{a: cat_meow, b: _}`,
|
||||
expression: `.c = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: cat_meow, b: _, c: [cat, meow]}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number division",
|
||||
subdescription: "The result during division is calculated as a float",
|
||||
document: `{a: 12, b: 2.5}`,
|
||||
expression: `.a = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: 4.8, b: 2.5}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number division by zero",
|
||||
subdescription: "Dividing by zero results in +Inf or -Inf",
|
||||
document: `{a: 1, b: -1}`,
|
||||
expression: `.a = .a / 0 | .b = .b / 0`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: !!float +Inf, b: !!float -Inf}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: that are really strings",
|
||||
document: "a: !horse cat_meow\nb: !goat _",
|
||||
expression: `.a = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: !horse\n - cat\n - meow\nb: !goat _\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: that are really numbers",
|
||||
document: "a: !horse 1.2\nb: !goat 2.3",
|
||||
expression: `.a = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: !horse 0.5217391304347826\nb: !goat 2.3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: "a: 2\nb: !goat 2.3",
|
||||
expression: `.a = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: 0.8695652173913044\nb: !goat 2.3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: that are really ints",
|
||||
document: "a: !horse 2\nb: !goat 3",
|
||||
expression: `.a = .a / .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: !horse 0.6666666666666666\nb: !goat 3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Keep anchors",
|
||||
document: "a: &horse [1]",
|
||||
expression: `.a[1] = .a[0] / 2`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: &horse [1, 0.5]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Divide int by string",
|
||||
document: "a: 123\nb: '2'",
|
||||
expression: `.a / .b`,
|
||||
expectedError: "!!int cannot be divided by !!str",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Divide string by int",
|
||||
document: "a: 2\nb: '123'",
|
||||
expression: `.b / .a`,
|
||||
expectedError: "!!str cannot be divided by !!int",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Divide map by int",
|
||||
document: "a: {\"a\":1}\nb: 2",
|
||||
expression: `.a / .b`,
|
||||
expectedError: "!!map (a) cannot be divided by !!int (b)",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Divide array by str",
|
||||
document: "a: [1,2]\nb: '2'",
|
||||
expression: `.a / .b`,
|
||||
expectedError: "!!seq (a) cannot be divided by !!str (b)",
|
||||
},
|
||||
}
|
||||
|
||||
func TestDivideOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range divideOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentOperatorScenarios(t, "divide", divideOperatorScenarios)
|
||||
}
|
@ -79,13 +79,13 @@ func encodeOperator(d *dataTreeNavigator, context Context, expressionNode *Expre
|
||||
|
||||
original := originalList.Front().Value.(*CandidateNode)
|
||||
originalNode := unwrapDoc(original.Node)
|
||||
// original block did not have a new line at the end, get rid of this one too
|
||||
// original block did not have a newline at the end, get rid of this one too
|
||||
if !endWithNewLine.MatchString(originalNode.Value) {
|
||||
stringValue = chomper.ReplaceAllString(stringValue, "")
|
||||
}
|
||||
}
|
||||
|
||||
// dont print a new line when printing json on a single line.
|
||||
// dont print a newline when printing json on a single line.
|
||||
if (preferences.format == JSONOutputFormat && preferences.indent == 0) ||
|
||||
preferences.format == CSVOutputFormat ||
|
||||
preferences.format == TSVOutputFormat {
|
||||
|
@ -179,7 +179,7 @@ var encoderDecoderOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Encode array of array scalars as tsv string",
|
||||
description: "Encode array of arrays as tsv string",
|
||||
subdescription: "Scalars are strings, numbers and booleans.",
|
||||
document: `[[cat, "thing1,thing2", true, 3.40], [dog, thing3, false, 12]]`,
|
||||
expression: `@tsv`,
|
||||
@ -310,6 +310,22 @@ var encoderDecoderOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!str)::\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "base64 missing padding test",
|
||||
skipDoc: true,
|
||||
expression: `"Y2F0cw" | @base64d`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::cats\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "base64 missing padding test",
|
||||
skipDoc: true,
|
||||
expression: `"cats" | @base64 | @base64d`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!str)::cats\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
requiresFormat: "xml",
|
||||
description: "empty xml decode",
|
||||
|
@ -36,7 +36,7 @@ var entriesOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "from_entries with numeric key indexes",
|
||||
description: "from_entries with numeric key indices",
|
||||
subdescription: "from_entries always creates a map, even for numeric keys",
|
||||
document: `[a,b]`,
|
||||
expression: `to_entries | from_entries`,
|
||||
|
@ -13,6 +13,14 @@ var filterOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!seq)::[1, 2]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Filter map values",
|
||||
document: `{c: {things: cool, frog: yes}, d: {things: hot, frog: false}}`,
|
||||
expression: `filter(.things == "cool")`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!seq)::[{things: cool, frog: yes}]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `[1,2,3]`,
|
||||
|
@ -17,7 +17,7 @@ var lineOperatorScenarios = []expressionScenario{
|
||||
description: "Returns line of _key_ node",
|
||||
subdescription: "Pipe through the key operator to get the line of the key",
|
||||
document: "a: cat\nb:\n c: cat",
|
||||
expression: `.b | key| line`,
|
||||
expression: `.b | key | line`,
|
||||
expected: []string{
|
||||
"D0, P[b], (!!int)::2\n",
|
||||
},
|
||||
|
93
pkg/yqlib/operator_modulo.go
Normal file
93
pkg/yqlib/operator_modulo.go
Normal file
@ -0,0 +1,93 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func moduloOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("Modulo operator")
|
||||
|
||||
return crossFunction(d, context.ReadOnlyClone(), expressionNode, modulo, false)
|
||||
}
|
||||
|
||||
func modulo(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
lhs.Node = unwrapDoc(lhs.Node)
|
||||
rhs.Node = unwrapDoc(rhs.Node)
|
||||
|
||||
lhsNode := lhs.Node
|
||||
|
||||
if lhsNode.Tag == "!!null" {
|
||||
return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath())
|
||||
}
|
||||
|
||||
target := &yaml.Node{}
|
||||
|
||||
if lhsNode.Kind == yaml.ScalarNode && rhs.Node.Kind == yaml.ScalarNode {
|
||||
if err := moduloScalars(target, lhsNode, rhs.Node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("%v (%v) cannot modulo by %v (%v)", lhsNode.Tag, lhs.GetNicePath(), rhs.Node.Tag, rhs.GetNicePath())
|
||||
}
|
||||
|
||||
return lhs.CreateReplacement(target), nil
|
||||
}
|
||||
|
||||
func moduloScalars(target *yaml.Node, lhs *yaml.Node, rhs *yaml.Node) error {
|
||||
lhsTag := lhs.Tag
|
||||
rhsTag := guessTagFromCustomType(rhs)
|
||||
lhsIsCustom := false
|
||||
if !strings.HasPrefix(lhsTag, "!!") {
|
||||
// custom tag - we have to have a guess
|
||||
lhsTag = guessTagFromCustomType(lhs)
|
||||
lhsIsCustom = true
|
||||
}
|
||||
|
||||
if lhsTag == "!!int" && rhsTag == "!!int" {
|
||||
target.Kind = yaml.ScalarNode
|
||||
target.Style = lhs.Style
|
||||
|
||||
format, lhsNum, err := parseInt64(lhs.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, rhsNum, err := parseInt64(rhs.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rhsNum == 0 {
|
||||
return fmt.Errorf("cannot modulo by 0")
|
||||
}
|
||||
remainder := lhsNum % rhsNum
|
||||
|
||||
target.Tag = lhs.Tag
|
||||
target.Value = fmt.Sprintf(format, remainder)
|
||||
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
|
||||
target.Kind = yaml.ScalarNode
|
||||
target.Style = lhs.Style
|
||||
|
||||
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remainder := math.Mod(lhsNum, rhsNum)
|
||||
if lhsIsCustom {
|
||||
target.Tag = lhs.Tag
|
||||
} else {
|
||||
target.Tag = "!!float"
|
||||
}
|
||||
target.Value = fmt.Sprintf("%v", remainder)
|
||||
} else {
|
||||
return fmt.Errorf("%v cannot modulo by %v", lhsTag, rhsTag)
|
||||
}
|
||||
return nil
|
||||
}
|
120
pkg/yqlib/operator_modulo_test.go
Normal file
120
pkg/yqlib/operator_modulo_test.go
Normal file
@ -0,0 +1,120 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var moduloOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `[{a: 2.5, b: 2}, {a: 2, b: 0.75}]`,
|
||||
expression: ".[] | .a % .b",
|
||||
expected: []string{
|
||||
"D0, P[0 a], (!!float)::0.5\n",
|
||||
"D0, P[1 a], (!!float)::0.5\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{}`,
|
||||
expression: "(.a / .b) as $x | .",
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number modulo - int",
|
||||
subdescription: "If the lhs and rhs are ints then the expression will be calculated with ints.",
|
||||
document: `{a: 13, b: 2}`,
|
||||
expression: `.a = .a % .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: 1, b: 2}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number modulo - float",
|
||||
subdescription: "If the lhs or rhs are floats then the expression will be calculated with floats.",
|
||||
document: `{a: 12, b: 2.5}`,
|
||||
expression: `.a = .a % .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: !!float 2, b: 2.5}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number modulo - int by zero",
|
||||
subdescription: "If the lhs is an int and rhs is a 0 the result is an error.",
|
||||
document: `{a: 1, b: 0}`,
|
||||
expression: `.a = .a % .b`,
|
||||
expectedError: "cannot modulo by 0",
|
||||
},
|
||||
{
|
||||
description: "Number modulo - float by zero",
|
||||
subdescription: "If the lhs is a float and rhs is a 0 the result is NaN.",
|
||||
document: `{a: 1.1, b: 0}`,
|
||||
expression: `.a = .a % .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: !!float NaN, b: 0}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: that are really numbers",
|
||||
document: "a: !horse 333.975\nb: !goat 299.2",
|
||||
expression: `.a = .a % .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: !horse 34.775000000000034\nb: !goat 299.2\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: "a: 2\nb: !goat 2.3",
|
||||
expression: `.a = .a % .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: !!float 2\nb: !goat 2.3\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Keep anchors",
|
||||
document: "a: &horse [1]",
|
||||
expression: `.a[1] = .a[0] % 2`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: &horse [1, 1]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Modulo int by string",
|
||||
document: "a: 123\nb: '2'",
|
||||
expression: `.a % .b`,
|
||||
expectedError: "!!int cannot modulo by !!str",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Modulo string by int",
|
||||
document: "a: 2\nb: '123'",
|
||||
expression: `.b % .a`,
|
||||
expectedError: "!!str cannot modulo by !!int",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Modulo map by int",
|
||||
document: "a: {\"a\":1}\nb: 2",
|
||||
expression: `.a % .b`,
|
||||
expectedError: "!!map (a) cannot modulo by !!int (b)",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Modulo array by str",
|
||||
document: "a: [1,2]\nb: '2'",
|
||||
expression: `.a % .b`,
|
||||
expectedError: "!!seq (a) cannot modulo by !!str (b)",
|
||||
},
|
||||
}
|
||||
|
||||
func TestModuloOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range moduloOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentOperatorScenarios(t, "modulo", moduloOperatorScenarios)
|
||||
}
|
@ -420,7 +420,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Merge, deeply merging arrays",
|
||||
subdescription: "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.",
|
||||
subdescription: "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.",
|
||||
document: `{a: [{name: fred, age: 12}, {name: bob, age: 32}], b: [{name: fred, age: 34}]}`,
|
||||
expression: `.a *d .b`,
|
||||
expected: []string{
|
||||
@ -525,7 +525,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Custom types: clobber tags",
|
||||
subdescription: "Use the `c` option to clobber custom tags. Note that the second tag is now used",
|
||||
subdescription: "Use the `c` option to clobber custom tags. Note that the second tag is now used.",
|
||||
document: "a: !horse {cat: meow}\nb: !goat {dog: woof}",
|
||||
expression: ".a *=c .b",
|
||||
expected: []string{
|
||||
@ -535,7 +535,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: clobber tags - *=",
|
||||
subdescription: "Use the `c` option to clobber custom tags - on both the `=` and `*` operator. Note that the second tag is now used",
|
||||
subdescription: "Use the `c` option to clobber custom tags - on both the `=` and `*` operator. Note that the second tag is now used.",
|
||||
document: "a: !horse {cat: meow}\nb: !goat {dog: woof}",
|
||||
expression: ".a =c .a *c .b",
|
||||
expected: []string{
|
||||
@ -545,7 +545,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Custom types: dont clobber tags - *=",
|
||||
subdescription: "Use the `c` option to clobber custom tags - on both the `=` and `*` operator. Note that the second tag is now used",
|
||||
subdescription: "Use the `c` option to clobber custom tags - on both the `=` and `*` operator. Note that the second tag is now used.",
|
||||
document: "a: !horse {cat: meow}\nb: !goat {dog: woof}",
|
||||
expression: ".a *= .b",
|
||||
expected: []string{
|
||||
|
@ -90,7 +90,7 @@ var pathOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Set path to prune deep paths",
|
||||
subdescription: "Like pick but recursive. This uses `ireduce` to deeply set the selected paths into an empty object,",
|
||||
subdescription: "Like pick but recursive. This uses `ireduce` to deeply set the selected paths into an empty object.",
|
||||
document: documentToPrune,
|
||||
expression: "(.parentB.child2, .parentC.child1) as $i\n ireduce({}; setpath($i | path; $i))",
|
||||
expected: []string{
|
||||
|
@ -34,7 +34,7 @@ var pickOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Pick indices from array",
|
||||
subdescription: "Note that the order of the indexes matches the pick order and non existent indexes are skipped.",
|
||||
subdescription: "Note that the order of the indices matches the pick order and non existent indices are skipped.",
|
||||
document: `[cat, leopard, lion]`,
|
||||
expression: `pick([2, 0, 734, -5])`,
|
||||
expected: []string{
|
||||
|
@ -57,7 +57,7 @@ var selectOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Select elements from array with regular expression",
|
||||
subdescription: "See more regular expression examples under the `string` operator docs.",
|
||||
subdescription: "See more regular expression examples under the [`string` operator docs](https://mikefarah.gitbook.io/yq/operators/string-operators).",
|
||||
document: `[this_0, not_this, nor_0_this, thisTo_4]`,
|
||||
expression: `.[] | select(test("[a-zA-Z]+_[0-9]$"))`,
|
||||
expected: []string{
|
||||
|
@ -205,7 +205,7 @@ var stringsOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Substitute / Replace string",
|
||||
subdescription: "This uses golang regex, described [here](https://github.com/google/re2/wiki/Syntax)\nNote the use of `|=` to run in context of the current string value.",
|
||||
subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
||||
document: `a: dogs are great`,
|
||||
expression: `.a |= sub("dogs", "cats")`,
|
||||
expected: []string{
|
||||
@ -214,7 +214,7 @@ var stringsOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Substitute / Replace string with regex",
|
||||
subdescription: "This uses golang regex, described [here](https://github.com/google/re2/wiki/Syntax)\nNote the use of `|=` to run in context of the current string value.",
|
||||
subdescription: "This uses Golang's regex, described [here](https://github.com/google/re2/wiki/Syntax).\nNote the use of `|=` to run in context of the current string value.",
|
||||
document: "a: cat\nb: heat",
|
||||
expression: `.[] |= sub("(a)", "${1}r")`,
|
||||
expected: []string{
|
||||
|
@ -67,15 +67,6 @@ var subtractOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (doc)::{a: -1.5, b: 4.5}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number subtraction - float",
|
||||
subdescription: "If the lhs or rhs are floats then the expression will be calculated with floats.",
|
||||
document: `{a: 3, b: 4.5}`,
|
||||
expression: `.a = .a - .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: -1.5, b: 4.5}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Number subtraction - int",
|
||||
subdescription: "If both the lhs and rhs are ints then the expression will be calculated with ints.",
|
||||
|
@ -89,7 +89,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
// rhs is a collect expression that will yield indexes to retrieve of the arrays
|
||||
// rhs is a collect expression that will yield indices to retrieve of the arrays
|
||||
|
||||
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.RHS)
|
||||
|
||||
@ -267,7 +267,7 @@ func traverseMap(context Context, matchingNode *CandidateNode, keyNode *yaml.Nod
|
||||
|
||||
func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode, wantedKey string, prefs traversePreferences, splat bool) error {
|
||||
// value.Content is a concatenated array of key, value,
|
||||
// so keys are in the even indexes, values in odd.
|
||||
// so keys are in the even indices, values in odd.
|
||||
// merge aliases are defined first, but we only want to traverse them
|
||||
// if we don't find a match directly on this node first.
|
||||
|
||||
|
@ -116,7 +116,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Special characters",
|
||||
subdescription: "Use quotes with brackets around path elements with special characters",
|
||||
subdescription: "Use quotes with square brackets around path elements with special characters",
|
||||
document: `{"{}": frog}`,
|
||||
expression: `.["{}"]`,
|
||||
expected: []string{
|
||||
@ -133,7 +133,7 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Keys with spaces",
|
||||
subdescription: "Use quotes with brackets around path elements with special characters",
|
||||
subdescription: "Use quotes with square brackets around path elements with special characters",
|
||||
document: `{"red rabbit": frog}`,
|
||||
expression: `.["red rabbit"]`,
|
||||
expected: []string{
|
||||
|
@ -1,3 +1,16 @@
|
||||
4.32.2:
|
||||
- Fixed behaviour for unknown file types (defaults to yaml) #1609
|
||||
|
||||
4.32.1:
|
||||
- Added divide and modulo operators (#1593) - thanks @teejaded!
|
||||
- Add support for decoding base64 strings without padding (#1555) - thanks @teejaded!
|
||||
- Add filter operation (#1588) - thanks @rbren!
|
||||
- Detect input format based on file name extension (#1582) - thanks @ryenus!
|
||||
- Auto output format when input format is automatically detected
|
||||
- Fixed npe in log #1596
|
||||
- Improved binary file size!
|
||||
- Bumped dependency versions
|
||||
|
||||
4.31.2:
|
||||
- Fixed variable handling #1458, #1566
|
||||
- Fixed merged anchor reference problem #1482
|
||||
@ -27,7 +40,7 @@
|
||||
|
||||
4.30.6:
|
||||
- Fixed xml comment in array of scalars #1465
|
||||
- Include blank new lines in leading header preprocessing #1462
|
||||
- Include blank newlines in leading header preprocessing #1462
|
||||
- Added aarch64 build (#1261)
|
||||
- Bumped dependency versions (#1453)
|
||||
|
||||
@ -171,7 +184,7 @@
|
||||
|
||||
4.24.1:
|
||||
- Added comparison operators! (#94)
|
||||
- Bumped golang to 1.18 (#1153)
|
||||
- Bumped Golang to 1.18 (#1153)
|
||||
- XML parser no longer runs in strict mode (added new flag to run in strict mode) (#1155)
|
||||
|
||||
4.23.1:
|
||||
|
2
scripts/build-small-yq.sh
Executable file
2
scripts/build-small-yq.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
go build -tags yq_notoml -tags yq_noxml -tags yq_nojson -ldflags "-s -w" .
|
@ -28,7 +28,7 @@ show_help() {
|
||||
echo " -h, --help Shows this help"
|
||||
echo " -d, --distribution DISTRO The distribution to use for the changelog generation. If not provided, last changelog entry"
|
||||
echo " distribution is considered"
|
||||
echo " --goversion VERSION The version of golang to use. Default to $GOVERSION"
|
||||
echo " --goversion VERSION The version of Golang to use. Default to $GOVERSION"
|
||||
echo " -k, --sign-key KEYID Sign the package sources with the provided gpg key id (long format). When not provided this"
|
||||
echo " paramater, the generated sources are not signed"
|
||||
echo " -s, --sign Sign the package sources with a gpg key of the maintainer"
|
||||
@ -156,7 +156,7 @@ fi
|
||||
# generate changelog
|
||||
gbp dch --ignore-branch --no-multimaint -N "$VERSION" -s "\$SINCE" -D "\$DISTRIBUTION"
|
||||
|
||||
# using -d to prevent failing when searching for golang dep on control file
|
||||
# using -d to prevent failing when searching for Golang dep on control file
|
||||
params=("-d" "-S")
|
||||
|
||||
# add the -sa option for signing along with the key to use when provided key id
|
||||
@ -208,7 +208,7 @@ RUN set -e \
|
||||
&& sed -i -- 's/# deb-src/deb-src/g' /etc/apt/sources.list \
|
||||
&& apt-get -qq update
|
||||
|
||||
# install golang on its $GOVERSION
|
||||
# install Golang on its $GOVERSION
|
||||
FROM base as golang
|
||||
RUN apt-get -qq -y --no-install-recommends install \
|
||||
ca-certificates \
|
||||
|
@ -2,7 +2,7 @@
|
||||
set -e
|
||||
# you may need to go install github.com/mitchellh/gox@v1.0.1 first
|
||||
echo $VERSION
|
||||
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}" --osarch="darwin/amd64 darwin/arm64 freebsd/386 freebsd/amd64 freebsd/arm linux/386 linux/amd64 linux/arm linux/arm64 linux/mips linux/mips64 linux/mips64le linux/mipsle linux/ppc64 linux/ppc64le linux/s390x netbsd/386 netbsd/amd64 netbsd/arm openbsd/386 openbsd/amd64 windows/386 windows/amd64"
|
||||
CGO_ENABLED=0 gox -ldflags "-s -w ${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}" --osarch="darwin/amd64 darwin/arm64 freebsd/386 freebsd/amd64 freebsd/arm linux/386 linux/amd64 linux/arm linux/arm64 linux/mips linux/mips64 linux/mips64le linux/mipsle linux/ppc64 linux/ppc64le linux/s390x netbsd/386 netbsd/amd64 netbsd/arm openbsd/386 openbsd/amd64 windows/386 windows/amd64"
|
||||
|
||||
cd build
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: yq
|
||||
version: 'v4.31.2'
|
||||
version: 'v4.32.2'
|
||||
summary: A lightweight and portable command-line YAML processor
|
||||
description: |
|
||||
The aim of the project is to be the jq or sed of yaml files.
|
||||
|
Loading…
Reference in New Issue
Block a user