Compare commits

...
Author SHA1 Message Date
Mike Farah 23a7b173bf Fixing merge anchor key order 2025-07-19 15:27:44 +10:00
Mike Farah 4019d42d60 Install specific version of gosec 2025-07-16 15:51:42 +10:00
Mike Farah 55daf6d93c Fixed panic for syntax error when creating a map #2423 2025-07-16 15:35:12 +10:00
Mike Farah 8e731ac13c Added "debug-node-info" flag for inspecting yq AST 2025-07-15 21:35:54 +10:00
ryenusandMike Farah d0c897f5e6 skip format check for filenames ending with dot
also add a unit test for func FormatStringFromFilename to cover such case
2025-07-15 19:30:07 +10:00
Mike Farah 6e8cc00030 Added flag to fix #2110 2025-07-14 16:26:26 +10:00
Mike Farah b9d9e2fbad Moar tests 2025-07-11 22:00:20 +10:00
dependabot[bot]andMike Farah a98921213f Bump golang.org/x/text from 0.26.0 to 0.27.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.26.0 to 0.27.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-version: 0.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-11 11:18:33 +10:00
dependabot[bot]andMike Farah 0153cccda9 Bump golang from 1.24.4 to 1.24.5
Bumps golang from 1.24.4 to 1.24.5.

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.24.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-11 11:18:23 +10:00
Mike Farah 9b299649f7 Refactored initCommand 2025-07-11 10:17:21 +10:00
Mike Farah 369fe56e2d Adding test file (CursorAI) 2025-07-11 09:59:59 +10:00
Mike Farah 422300457c (attempt) to build snapcract for all architectures 2025-07-10 16:17:23 +10:00
cloudclaimandMike Farah 544bd9ff6f chore: fix some minor issues in the comments
Signed-off-by: cloudclaim <824973921@qq.com>
2025-07-10 13:33:36 +10:00
Mike Farah 1187c954ec Bumping version 2025-07-10 13:09:34 +10:00
Mike Farah 08d3789daa Preparing release 2025-07-10 13:07:43 +10:00
Mike Farah 6a5e95ac84 Merge branch 'imzue-build-small-yq' 2025-07-10 13:06:54 +10:00
Mike Farah 221a5b1106 Adding tinygo to project words 2025-07-10 13:06:42 +10:00
Mike Farah c10bfe0602 Switching to YAML org supported go-yaml 2025-07-10 13:04:54 +10:00
Mike Farah 99f88df21e Switching to YAML org supported go-yaml 2025-07-10 13:01:09 +10:00
Zue 7696723d5c Add more build tags to reduce binary size 2025-07-01 15:52:40 +08:00
Zue a9f7cc1ebb Add TinyGo build example 2025-07-01 13:28:10 +08:00
Zue 384d227efe Add yq_noini tag to build-small-yq 2025-07-01 13:27:21 +08:00
Zue 25365a0f0b Fix compilation errors when building build-small-yq 2025-07-01 13:26:26 +08:00
dependabot[bot]andMike Farah 40808838ba Bump golang.org/x/net from 0.40.0 to 0.41.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.40.0 to 0.41.0.
- [Commits](https://github.com/golang/net/compare/v0.40.0...v0.41.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-13 10:47:51 +10:00
Mike Farah 176873e93a Refining add op 2025-06-12 15:41:27 +10:00
dependabot[bot]andMike Farah fd7e750040 Bump golang from 1.24.3 to 1.24.4
Bumps golang from 1.24.3 to 1.24.4.

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.24.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-12 15:01:24 +10:00
Mike Farah ff9d2acd4a Preparing release notes (won't release till I get back from holiday) 2025-06-12 14:53:39 +10:00
Mike Farah 88bfbec97b Fix add op when there are not matches piped in, #2383, #2384 2025-06-12 14:48:10 +10:00
Antoine DeschênesandMike Farah b15ce77cad fix: correct key order after add, flatten, keys, sort, reverse and shuffle
Signed-off-by: Antoine Deschênes <antoine.deschenes@linux.com>
2025-06-07 21:04:26 +10:00
Mike Farah b84fd47934 More goccy progress 2025-06-07 15:23:38 +10:00
dependabot[bot]andMike Farah 58e0cd2600 Bump github.com/goccy/go-yaml from 1.17.1 to 1.18.0
Bumps [github.com/goccy/go-yaml](https://github.com/goccy/go-yaml) from 1.17.1 to 1.18.0.
- [Release notes](https://github.com/goccy/go-yaml/releases)
- [Changelog](https://github.com/goccy/go-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-yaml/compare/v1.17.1...v1.18.0)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-yaml
  dependency-version: 1.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-06 10:51:48 +10:00
o.bilkoandMike Farah c58d9e7da4 fix tests 2025-05-17 18:55:53 +10:00
beliysandMike Farah 3ac203ebb8 Add INI support 2025-05-17 18:55:53 +10:00
Mike Farah b534aa9ee5 Bumping version 2025-05-11 21:31:47 +10:00
Mike Farah 39a65b62d2 Updating release notes 2025-05-10 07:41:19 +10:00
Mike Farah 1e3006e951 Removing old issue template 2025-05-10 07:25:48 +10:00
Mike Farah 22949df0fd Fixing running map against empty array bug #2359 2025-05-10 07:24:48 +10:00
Mike Farah 734e2cd254 Bumping version 2025-05-09 15:48:44 +10:00
Mike Farah 082b76affa Preparing release notes 2025-05-09 15:48:13 +10:00
Mike Farah 5bc2cd03da Bumping golang version 2025-05-09 15:45:28 +10:00
Mike Farah 20407a07a5 Adding more tests to prevent regression again :sweat 2025-05-09 15:40:29 +10:00
dependabot[bot]andMike Farah 0a83da6b38 Bump github.com/pelletier/go-toml/v2 from 2.2.3 to 2.2.4
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-version: 2.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-09 15:40:02 +10:00
dependabot[bot]andMike Farah 77da8b7d32 Bump golang from 1.24.2 to 1.24.3
Bumps golang from 1.24.2 to 1.24.3.

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.24.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-09 15:39:48 +10:00
dependabot[bot]andMike Farah a27db3aacc Bump golang.org/x/net from 0.39.0 to 0.40.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.39.0 to 0.40.0.
- [Commits](https://github.com/golang/net/compare/v0.39.0...v0.40.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-09 15:35:30 +10:00
dependabot[bot]andMike Farah ed7fd54dac Bump github.com/a8m/envsubst from 1.4.2 to 1.4.3
Bumps [github.com/a8m/envsubst](https://github.com/a8m/envsubst) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/a8m/envsubst/releases)
- [Commits](https://github.com/a8m/envsubst/compare/v1.4.2...v1.4.3)

---
updated-dependencies:
- dependency-name: github.com/a8m/envsubst
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-09 15:33:53 +10:00
Mike Farah 2c2487c0bd Fixing Regression in #2353, #2359, #2325 2025-05-09 15:29:44 +10:00
Mike Farah 2c7cce0878 Line and Column working with Goccy, Fixed Anchor Map problem 2025-05-04 19:29:42 +10:00
Mike Farah 2bd08ea4e8 Dont panic on tests 2025-05-04 10:33:09 +10:00
Mike Farah 72fa3cca98 goccy decoder supports merge maps 2025-05-03 20:20:50 +10:00
Mike Farah f89605e3c0 goccy yaml decoder supports anchor/aliases 2025-05-03 20:01:16 +10:00
Mike Farah c59fa8de59 Bumping version 2025-05-03 16:40:24 +10:00
Mike Farah ef8b520f89 Updating release notes 2025-05-03 16:39:36 +10:00
Mike Farah 20b5129120 Updating golanglint 2025-05-03 16:34:21 +10:00
Mike Farah 89518a09b8 Bumping golint 2025-05-03 15:58:14 +10:00
Mike Farah d01ac7801d Regen doc 2025-05-03 11:37:52 +10:00
Mike Farah 67520b5e7b Adding windows arm build #2344 2025-05-03 11:37:52 +10:00
Romain Lebrun ThaurontandMike Farah 7b6e61ba2c Update README.md 2025-05-03 11:36:12 +10:00
Romain Lebrun ThaurontandMike Farah cf8621d9e3 Install to /usr/local in README install instruction 2025-05-03 11:36:12 +10:00
dependabot[bot]andMike Farah 340b897252 Bump github.com/spf13/cobra from 1.8.1 to 1.9.1
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.1 to 1.9.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.1...v1.9.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-03 11:28:22 +10:00
n4zukkerandMike Farah 4155c99a12 Typo in cats example
The quotation mark and closing parenthesis were swapped.

Before:
```
$ echo "Hello kitty" | yq eval 'test("(?i)cats)"'
Error: bad expression - probably missing close bracket on TEST
```

After:
```
$ echo "Hello kitty" | yq eval 'test("(?i)cats")'
false
```
2025-05-03 11:27:51 +10:00
dependabot[bot]andMike Farah b26de94758 Bump github.com/magiconair/properties from 1.8.9 to 1.8.10
Bumps [github.com/magiconair/properties](https://github.com/magiconair/properties) from 1.8.9 to 1.8.10.
- [Release notes](https://github.com/magiconair/properties/releases)
- [Commits](https://github.com/magiconair/properties/compare/v1.8.9...v1.8.10)

---
updated-dependencies:
- dependency-name: github.com/magiconair/properties
  dependency-version: 1.8.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-03 11:24:22 +10:00
dependabot[bot]andMike Farah 7dc5efee62 Bump golang.org/x/net from 0.34.0 to 0.39.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.34.0 to 0.39.0.
- [Commits](https://github.com/golang/net/compare/v0.34.0...v0.39.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-03 11:24:12 +10:00
Alberto CavalcanteandMike Farah 2cb7498444 chore(release): add windows arm64 binary target for release 2025-05-03 11:23:55 +10:00
Alberto CavalcanteandMike Farah 649c9a083a chore(check): use golangci-lint from GOPATH/bin as first option 2025-05-03 11:23:55 +10:00
Alberto CavalcanteandMike Farah 074d785396 chore(devtools): use curl instead of wget for better compatibility with MacOS 2025-05-03 11:23:55 +10:00
dependabot[bot]andMike Farah de2f77b49c Bump github.com/alecthomas/participle/v2 from 2.1.1 to 2.1.4
Bumps [github.com/alecthomas/participle/v2](https://github.com/alecthomas/participle) from 2.1.1 to 2.1.4.
- [Release notes](https://github.com/alecthomas/participle/releases)
- [Changelog](https://github.com/alecthomas/participle/blob/master/CHANGES.md)
- [Commits](https://github.com/alecthomas/participle/compare/v2.1.1...v2.1.4)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/participle/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-05 21:36:59 +11:00
Ashok PariyaandMike Farah fe06096514 Add s390x platform support to Docker release workflow
Updated the list of supported platforms in the GitHub Actions
Docker release workflow to include linux/s390x.

Signed-off-by: Ashok Pariya <ashok.pariya@ibm.com>
2025-04-05 20:18:39 +11:00
dependabot[bot]andMike Farah 40f2c2381b Bump golang from 1.24.1 to 1.24.2
Bumps golang from 1.24.1 to 1.24.2.

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.24.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-05 20:17:56 +11:00
dependabot[bot]andMike Farah 64bee0fbe3 Bump golang from 1.24.0 to 1.24.1
Bumps golang from 1.24.0 to 1.24.1.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 15:45:53 +11:00
dependabot[bot]andMike Farah 6e6575d5b0 Bump golang.org/x/text from 0.22.0 to 0.23.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.22.0 to 0.23.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 15:45:42 +11:00
Oleksandr RedkoandMike Farah ce2ce51236 Remove mistakenly committed cover.out 2025-03-25 15:45:27 +11:00
Zoltán ReegnandMike Farah c9766c1cab Also push docker images to ghcr.io
With docker-hub starting to introduce a much stricter limit on anonymous
pulls, it makes sense to also host the image in ghcr.io as well,
allowing users flexibility in where they pull the docker images from.

Also with the github action it makes more sense hosting the docker image
on github infrastructure.

I've introduced a github action for logging into registries as well.
2025-03-25 15:45:15 +11:00
Mike Farah 337960a6d1 Fixing add when there is no node match #2325 2025-03-25 15:35:16 +11:00
damuzhi0810andMike Farah 1395d6e230 refactor: using slices.Contains to simplify the code
Signed-off-by: damuzhi0810 <rust@before.tech>
2025-03-25 15:10:25 +11:00
Mike Farah ba1b9737b6 Added recursive update map keys example 2025-03-03 15:10:42 +11:00
dependabot[bot]andMike Farah d74e70104f Bump golang.org/x/text from 0.21.0 to 0.22.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-22 11:19:34 +11:00
dependabot[bot]andMike Farah 15071ba393 Bump github.com/goccy/go-json from 0.10.4 to 0.10.5
Bumps [github.com/goccy/go-json](https://github.com/goccy/go-json) from 0.10.4 to 0.10.5.
- [Release notes](https://github.com/goccy/go-json/releases)
- [Changelog](https://github.com/goccy/go-json/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-json/compare/v0.10.4...v0.10.5)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-22 11:19:24 +11:00
dependabot[bot]andMike Farah a9495ff395 Bump github.com/spf13/pflag from 1.0.5 to 1.0.6
Bumps [github.com/spf13/pflag](https://github.com/spf13/pflag) from 1.0.5 to 1.0.6.
- [Release notes](https://github.com/spf13/pflag/releases)
- [Commits](https://github.com/spf13/pflag/compare/v1.0.5...v1.0.6)

---
updated-dependencies:
- dependency-name: github.com/spf13/pflag
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-22 11:19:12 +11:00
dependabot[bot]andMike Farah e176ec649f Bump golang from 1.23.5 to 1.24.0
Bumps golang from 1.23.5 to 1.24.0.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-22 11:19:00 +11:00
dependabot[bot]andMike Farah c34d3f7805 Bump golang from 1.23.4 to 1.23.5
Bumps golang from 1.23.4 to 1.23.5.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-23 22:04:08 +11:00
dependabot[bot]andMike Farah 99e24956b3 Bump github.com/elliotchance/orderedmap from 1.7.1 to 1.8.0
Bumps [github.com/elliotchance/orderedmap](https://github.com/elliotchance/orderedmap) from 1.7.1 to 1.8.0.
- [Release notes](https://github.com/elliotchance/orderedmap/releases)
- [Commits](https://github.com/elliotchance/orderedmap/compare/v1.7.1...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/elliotchance/orderedmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-22 14:40:05 +11:00
dependabot[bot]andMike Farah 2bce6b2608 Bump golang.org/x/net from 0.33.0 to 0.34.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.34.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.34.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-22 14:39:55 +11:00
Mike Farah f202d06d82 sort_by works on maps 2025-01-22 14:36:50 +11:00
Stephen UridgeandMike Farah 1508f1fd5f Update docs and tests for --properties-separator flag 2025-01-22 09:53:51 +11:00
Mike Farah 8bf425b4d1 Bumping version 2025-01-12 14:17:39 +11:00
Mike Farah f755755bb0 Updated release notes 2025-01-12 14:17:20 +11:00
Mike Farah 0f390b27aa Bumping goccy 2025-01-12 14:13:31 +11:00
dependabot[bot]andMike Farah 31ad7fbaa2 Bump github.com/magiconair/properties from 1.8.7 to 1.8.9
Bumps [github.com/magiconair/properties](https://github.com/magiconair/properties) from 1.8.7 to 1.8.9.
- [Release notes](https://github.com/magiconair/properties/releases)
- [Commits](https://github.com/magiconair/properties/compare/v1.8.7...v1.8.9)

---
updated-dependencies:
- dependency-name: github.com/magiconair/properties
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-12 14:03:15 +11:00
dependabot[bot]andMike Farah 566cf82d08 Bump github.com/goccy/go-json from 0.10.3 to 0.10.4
Bumps [github.com/goccy/go-json](https://github.com/goccy/go-json) from 0.10.3 to 0.10.4.
- [Release notes](https://github.com/goccy/go-json/releases)
- [Changelog](https://github.com/goccy/go-json/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-json/compare/v0.10.3...v0.10.4)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-12 14:03:05 +11:00
dependabot[bot]andMike Farah 2c9f8331c4 Bump github.com/elliotchance/orderedmap from 1.7.0 to 1.7.1
Bumps [github.com/elliotchance/orderedmap](https://github.com/elliotchance/orderedmap) from 1.7.0 to 1.7.1.
- [Release notes](https://github.com/elliotchance/orderedmap/releases)
- [Commits](https://github.com/elliotchance/orderedmap/compare/v1.7.0...v1.7.1)

---
updated-dependencies:
- dependency-name: github.com/elliotchance/orderedmap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-12 14:02:52 +11:00
dependabot[bot]andMike Farah c02d44de63 Bump golang.org/x/net from 0.32.0 to 0.33.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.32.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.32.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-12 14:02:38 +11:00
Rudolf ThomasandMike Farah f73c862cc5 feat: Create parent directories if --split-exp is used.
Problem: When --split-exp is used and produces filenames with slashes in
them, the target directories must already exist otherwise yq fails.

Fix/feature: Create the necessary directories with os.MkdirAll().
The permissions 0750 were chosen to satisfy the vulnerability checker.
2024-12-14 19:52:09 +11:00
Mike Farah 294a1709ad Bumping version 2024-12-07 17:33:47 +11:00
Mike Farah 342efb23ff Fixed panic on multipling string by very large number #2211 2024-12-07 16:53:40 +11:00
Mike Farah 2201381235 Fixed multiply string by negative number panic #2211 2024-12-07 16:28:59 +11:00
Mike Farah 5273715428 Fixed panic error #2211 2024-12-07 16:20:45 +11:00
Mike Farah e204677ff8 Fixed no-colors regression #2218 2024-12-07 16:05:58 +11:00
Brian EggeandMike Farah f76815959a Create docker image for armv7 / raspberry pi3 2024-12-07 11:10:20 +11:00
Jan DuboisandMike Farah c16b1800a0 Make sure to update the key when deleting array elements 2024-12-07 11:09:52 +11:00
dependabot[bot]andMike Farah 3bca3a23c0 Bump github.com/elliotchance/orderedmap from 1.6.0 to 1.7.0
Bumps [github.com/elliotchance/orderedmap](https://github.com/elliotchance/orderedmap) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/elliotchance/orderedmap/releases)
- [Commits](https://github.com/elliotchance/orderedmap/compare/v1.6.0...v1.7.0)

---
updated-dependencies:
- dependency-name: github.com/elliotchance/orderedmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-07 11:03:57 +11:00
dependabot[bot]andMike Farah 70bef5b9d2 Bump golang.org/x/net from 0.31.0 to 0.32.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.31.0 to 0.32.0.
- [Commits](https://github.com/golang/net/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-07 11:03:23 +11:00
dependabot[bot]andMike Farah ea2ba18ef4 Bump golang from 1.23.3 to 1.23.4
Bumps golang from 1.23.3 to 1.23.4.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-07 11:00:34 +11:00
Mike Farah 80310eaaac Removing temp docker fix 2024-11-16 20:37:27 +11:00
Mike Farah 8391193732 Temp fix docker version 2024-11-16 20:34:50 +11:00
Mike Farah d858ab1644 Removing riscv64 from docker build as its not supported by the base golang:1.23.2 image 2024-11-16 20:31:39 +11:00
Mike Farah f1c7e5ca79 Updated release notes 2024-11-16 15:45:36 +11:00
Mike Farah bc5b54cb1d Bumping version 2024-11-16 15:45:01 +11:00
Mike Farah 129e597346 Fixing release pipeline 2024-11-16 15:43:21 +11:00
Mike Farah 42db154e2e Bumping version 2024-11-16 15:25:31 +11:00
Mike Farah f06c7c6b52 Updating release notes 2024-11-16 15:24:53 +11:00
Mike Farah 1ae6ac18f9 Merge branch 'gabe565-add-comment-style' 2024-11-16 15:23:27 +11:00
Mike Farah b710fadfc0 Regenerating go mod 2024-11-16 15:23:08 +11:00
Mike Farah 6a43f17d02 Merge branch 'add-comment-style' of github.com:gabe565/yq into gabe565-add-comment-style 2024-11-16 15:19:21 +11:00
Mike FarahandGitHub 1a4b2485ff Merge branch 'master' into add-comment-style 2024-11-16 15:16:12 +11:00
Mike Farah 58cc9db721 Updated release notes 2024-11-16 15:14:43 +11:00
Mike Farah 4af292f076 Fixed handling of nulls with sort_by expressions #2164 2024-11-16 12:27:18 +11:00
dependabot[bot]andMike Farah f238f01856 Bump github.com/fatih/color from 1.17.0 to 1.18.0
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.17.0 to 1.18.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.17.0...v1.18.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 12:25:41 +11:00
dependabot[bot]andMike Farah 58a4d2401f Bump golang.org/x/net from 0.30.0 to 0.31.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.30.0 to 0.31.0.
- [Commits](https://github.com/golang/net/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 12:11:59 +11:00
Mike Farah 887b4a560f Fixed linting 2024-11-16 12:04:43 +11:00
dependabot[bot]andMike Farah f2cc2ea5a8 Bump golang from 1.23.2 to 1.23.3
Bumps golang from 1.23.2 to 1.23.3.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-16 11:59:54 +11:00
Mike Farah 95e7b35f74 Fixed spelling of coloured 2024-11-16 11:54:58 +11:00
Vladimir VarankinandMike Farah f071a25fa9 cmd: force no color output when NO_COLOR env presents 2024-11-16 11:54:19 +11:00
Mike Farah b8607bacb9 Prefer not having nolint 2024-11-16 11:52:42 +11:00
Marco Vito MoscaritoloandMike Farah 6908161f1f replace error creation 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah f168172bf4 remove unused variable parameters from functions 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah 3ce266bfa0 fix parameter order in error type comparison 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah 7eef1a454e exclude lint errors to keep cobra params unchanged 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah 072491c656 remove lint exception no longer required 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah 18972b290a replace deprecated megacheck with specific linters 2024-11-16 11:48:53 +11:00
Marco Vito MoscaritoloandMike Farah 9d60c79609 update golangci-lint to the last version 2024-11-16 11:48:53 +11:00
Gabe Cook 9caeb429ac Format comments with a gray foreground 2024-11-10 03:30:03 -06:00
dependabot[bot]andMike Farah 39a81da170 Bump golang.org/x/net from 0.29.0 to 0.30.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.29.0 to 0.30.0.
- [Commits](https://github.com/golang/net/compare/v0.29.0...v0.30.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-10 13:26:42 +11:00
dependabot[bot]andMike Farah b84e23e1ec Bump golang from 1.23.1 to 1.23.2
Bumps golang from 1.23.1 to 1.23.2.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-10 13:25:50 +11:00
Mike Farah f654fbf459 Fixed array subtraction update bug #2159 2024-09-29 15:21:11 +10:00
Mike Farah 5df71072f5 Fixed index out of range error 2024-09-29 15:06:34 +10:00
dependabot[bot]andMike Farah cc7738bb8d Bump golang.org/x/net from 0.28.0 to 0.29.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.28.0 to 0.29.0.
- [Commits](https://github.com/golang/net/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 10:45:18 +10:00
dependabot[bot]andMike Farah 302ce1291f Bump golang from 1.23.0 to 1.23.1
Bumps golang from 1.23.0 to 1.23.1.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-19 10:45:00 +10:00
dependabot[bot]andMike Farah f57de74cfe Bump github.com/pelletier/go-toml/v2 from 2.2.2 to 2.2.3
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.2.2 to 2.2.3.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.2.2...v2.2.3)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-06 19:09:43 +10:00
dependabot[bot]andMike Farah 383cd0f182 Bump golang from 1.22.5 to 1.23.0
Bumps golang from 1.22.5 to 1.23.0.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-06 13:37:14 +10:00
Mike Farah 3727b3e664 Fixed unecessary int64 to int conversion 2024-09-06 13:24:10 +10:00
Mike Farah c477fc08cf Updated readme to include x-cmd 2024-09-06 13:11:09 +10:00
Mike Farah 1846006082 Can traverse straight from parent operator (parent.blah) 2024-09-06 12:46:23 +10:00
Mike Farah dff0122481 Regen kind docs 2024-09-06 12:33:27 +10:00
Mike Farah 42b92aff13 Added pick including all keys example 2024-09-06 12:32:36 +10:00
dependabot[bot]andMike Farah c76e432de3 Bump golang.org/x/net from 0.27.0 to 0.28.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.27.0 to 0.28.0.
- [Commits](https://github.com/golang/net/compare/v0.27.0...v0.28.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-06 12:25:19 +10:00
Tiger KaovilaiandMike Farah 19e2591b1e Only use podman if CLI can execute. Use docker if non-Linux podman has no connection to Linux system.
Solves
```
❯ make test
Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM Error: unable to connect to Podman socket: failed to read identity "/Users/tiger/.local/share/containers/podman/machine/machine": open /Users/tiger/.local/share/containers/podman/machine/machine: no such file or directory /opt/homebrew/bin/docker run --rm -e LDFLAGS=" -X main.GitCommit=bbdd974+CHANGES -X main.GitDescribe=v4 -w -s" -e GITHUB_TOKEN="" -v /Users/tiger/git/yq-k8s/vendor:/go/src -v /Users/tiger/git/yq-k8s:/yq/src/github.com/mikefarah/yq -w /yq/src/github.com/mikefarah/yq yq_dev go mod vendor
Error: podman-machine-default: VM already exists
```

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2024-09-06 12:25:07 +10:00
William AllenandMike Farah 6eb2ae757a Create kind.md header doc 2024-08-20 15:23:06 +10:00
Mike Farah 82fca30efa Fix cspell errors 2024-08-20 13:14:50 +10:00
Matheus MacabuandGitHub c46c1a7128 build: use goreleaser for building cross-compiled binaries and add riscv64 target (#2135)
* build: use goreleaser to cross-compile binaries for all platforms and archs

The main motivation behind it is because "gox" is unmaintained and archived
and it does not support "linux/riscv64" as a target.

Right now, goreleaser is only building the binaries, and I've tried to replicate
the exact same way the old script does.

In the future, if so desired, goreleaser could be used to further automate the
build and release pipeline by creating the release in GitHub.

* build: create binaries and OCI image for linux/riscv64
2024-08-20 13:09:12 +10:00
Mike Farah bbdd97482f Bumping version 2024-08-05 15:38:57 +10:00
Mike Farah 9940668729 Preparing release 2024-08-05 15:38:30 +10:00
95aaccee46 Add Flox to installation methods (#2117)
Co-authored-by: Bryan Honof <bryanhonof@bryans-mbp.space.flox.local>
2024-08-05 15:15:06 +10:00
ryenusandGitHub b9c3ff6f0a convert file ext to lowercase for format detection (#2121)
* convert file ext to lowercase for format detection

To ensure proper file format detection with case-insensitive file
systems.

* use filepath.Ext for more reliable file ext detection

especially for paths like index.js/foo

* add a test for file ext based format detection
2024-08-05 15:14:43 +10:00
Kian ParvinandGitHub b80e1cb35e Use static bin in snap (#2090) 2024-07-21 10:52:32 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0ff8415244 Bump golang.org/x/net from 0.26.0 to 0.27.0 (#2099)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.26.0 to 0.27.0.
- [Commits](https://github.com/golang/net/compare/v0.26.0...v0.27.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 10:08:58 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
e8dcf3f1a4 Bump github.com/goccy/go-yaml from 1.11.3 to 1.12.0 (#2108)
Bumps [github.com/goccy/go-yaml](https://github.com/goccy/go-yaml) from 1.11.3 to 1.12.0.
- [Release notes](https://github.com/goccy/go-yaml/releases)
- [Changelog](https://github.com/goccy/go-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-yaml/compare/v1.11.3...v1.12.0)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-yaml
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 10:08:42 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
208302cf6b Bump golang from 1.22.4 to 1.22.5 (#2091)
Bumps golang from 1.22.4 to 1.22.5.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-21 10:08:23 +10:00
Mike Farah ef6fb92e7f Log printing follow no-colors flag #2082 2024-06-29 15:26:10 +10:00
Mike Farah 28646c7b50 Skip and warn when interpolating strings and theres a unclosed bracket #2083 2024-06-29 15:20:07 +10:00
Mike Farah 0b7d4b799c Fixed CSV content starting with # issue #2076 2024-06-29 15:04:07 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7e1722510a Bump github.com/spf13/cobra from 1.8.0 to 1.8.1 (#2075)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-29 13:59:50 +10:00
Mike Farah f15500b20a Bumping version 2024-06-16 11:13:40 +10:00
Mike Farah b8aec71e66 Preparing release 2024-06-16 11:13:25 +10:00
Mike Farah 68aafb6a53 Handle numbers with underscores #2039 2024-06-16 11:09:52 +10:00
Mike Farah d58870b056 Adding splat[] short hand to explode,collect,flatten,groupby,path,pivot,select and more 2024-06-16 10:48:01 +10:00
Mike Farah f1964dece0 Adding splat[] short hand to collect,eval,map,omit,path,pick 2024-06-16 10:22:42 +10:00
Mike Farah 45eda8dbae Added support for shorthand splat[] for filter,reverse,sort,shuffle 2024-06-15 22:13:58 +10:00
Mike Farah d9af2dd976 Support env[] expression #2071 2024-06-15 21:56:32 +10:00
Mike Farah 7bad2f4f06 Adding back in commented tests :facepalm 2024-06-15 21:49:23 +10:00
Mike Farah 3ea19ad2ed clean code 2024-06-15 17:06:17 +10:00
Mike Farah 42120e1341 Unique now works on maps and arrays #2068 2024-06-15 17:04:48 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1147113fd3 Bump github.com/goccy/go-json from 0.10.2 to 0.10.3 (#2046)
Bumps [github.com/goccy/go-json](https://github.com/goccy/go-json) from 0.10.2 to 0.10.3.
- [Release notes](https://github.com/goccy/go-json/releases)
- [Changelog](https://github.com/goccy/go-json/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-json/compare/v0.10.2...v0.10.3)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-15 16:00:53 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2edfa834d5 Bump github.com/elliotchance/orderedmap from 1.5.1 to 1.6.0 (#2053)
Bumps [github.com/elliotchance/orderedmap](https://github.com/elliotchance/orderedmap) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/elliotchance/orderedmap/releases)
- [Commits](https://github.com/elliotchance/orderedmap/compare/v1.5.1...v1.6.0)

---
updated-dependencies:
- dependency-name: github.com/elliotchance/orderedmap
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-15 16:00:38 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8c7cfb720c Bump golang.org/x/net from 0.25.0 to 0.26.0 (#2061)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.26.0.
- [Commits](https://github.com/golang/net/compare/v0.25.0...v0.26.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-15 16:00:16 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
356c60f40c Bump golang from 1.22.3 to 1.22.4 (#2062)
Bumps golang from 1.22.3 to 1.22.4.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-15 16:00:02 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4cc646b16b Bump github.com/fatih/color from 1.16.0 to 1.17.0 (#2043)
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-01 16:45:11 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2e44ab4512 Bump golang.org/x/net from 0.24.0 to 0.25.0 (#2035)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.25.0.
- [Commits](https://github.com/golang/net/compare/v0.24.0...v0.25.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-01 16:45:01 +10:00
Mike Farah 557dcb87b8 Bumping version 2024-05-12 12:27:39 +10:00
Mike Farah 2daa39e306 Updating release notes 2024-05-12 12:27:06 +10:00
Mike Farah 0c15cf35a7 Added properties convert to numbers example #2023 2024-05-12 12:07:04 +10:00
Jakub JirutkaandGitHub d9adcdb668 Update instructions for Alpine Linux (#2034)
The package has been renamed from `yq` to `yq-go` to match other distros.
2024-05-12 11:55:06 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9010809d89 Bump github.com/pelletier/go-toml/v2 from 2.2.1 to 2.2.2 (#2024)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.2.1...v2.2.2)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-12 11:53:40 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8250f0c2bd Bump golang.org/x/text from 0.14.0 to 0.15.0 (#2036)
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.14.0 to 0.15.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-12 11:53:02 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8ac9f605f6 Bump golang from 1.22.2 to 1.22.3 (#2037)
Bumps golang from 1.22.2 to 1.22.3.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-12 11:52:48 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1748171463 Bump github.com/pelletier/go-toml/v2 from 2.2.0 to 2.2.1 (#2014)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.2.0 to 2.2.1.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.2.0...v2.2.1)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-22 14:15:45 +10:00
Cory LatschkowskiandGitHub 21ba506edb Fix: shell-completion (#2006)
* fix: shell-completion

* update: description
2024-04-22 14:15:36 +10:00
Matt BensonandGitHub b54d7eb21c handle escaped backslashes (#1997) 2024-04-14 18:52:08 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
db6f2dc6a2 Bump golang from 1.22.1 to 1.22.2 (#1998)
Bumps golang from 1.22.1 to 1.22.2.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-14 18:51:39 +10:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1411f45055 Bump golang.org/x/net from 0.22.0 to 0.24.0 (#2008)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.24.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.24.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-14 18:51:28 +10:00
Cory LatschkowskiandGitHub c7baa8bc34 Fix: linux (w/ selinux) build (#2004)
* add: check for selinux for vol mount

* update: install packages first

build time not increased if script changes

* update: selinux check
2024-04-14 18:51:17 +10:00
Mike Farah a4b9c3049b Removed unused debian directory #2000 2024-04-13 11:00:39 +10:00
Mike Farah fe84f62288 Docs 2024-03-30 14:01:42 +11:00
Mike Farah 28c406706a Fixes npe when given filename ending with "." #1994 2024-03-30 14:00:57 +11:00
Matt BensonandGitHub 101cf14b8c min/max operators (#1992)
* min/max operators

* min, max operator headers
2024-03-30 13:34:36 +11:00
Matt BensonandGitHub 3283c65dc4 pivot operator (#1993) 2024-03-30 13:29:35 +11:00
Mike Farah 2ee7508b76 typos 2024-03-24 11:32:02 +11:00
Mike Farah 2ecd8b6092 updated contribe guide 2024-03-24 11:29:48 +11:00
Mike Farah 021d5f05f9 Fixing omit docs 2024-03-24 10:59:29 +11:00
Mike Farah 19a0e6dd8b Bumping version 2024-03-24 10:54:35 +11:00
Mike Farah fbd4c8428a Remove old JSON warning 2024-03-23 17:17:23 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d9ef03a2d1 Bump github.com/pelletier/go-toml/v2 from 2.1.1 to 2.2.0 (#1986)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.1.1 to 2.2.0.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.1.1...v2.2.0)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-23 17:15:56 +11:00
Matt BensonandGitHub f5bfe5a248 omit operator (#1989) 2024-03-23 17:15:45 +11:00
Matt BensonandGitHub 3b85cef340 support string X int multiplication as jq (#1988) 2024-03-22 20:44:49 +11:00
Mike Farah 76a0da3937 Refactoring load op 2024-03-12 15:57:26 +11:00
Mike Farah 2b2c285415 Adding release notes 2024-03-12 11:02:15 +11:00
Mike Farah 8a07e3da3d Can specify parent levels #1970 2024-03-12 10:49:26 +11:00
Mike Farah 9e9cb65ec0 Fixed CSV line break issue #1974 2024-03-12 10:22:35 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
29056ee87f Bump golang from 1.22.0 to 1.22.1 (#1968)
Bumps golang from 1.22.0 to 1.22.1.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 09:47:47 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8f4e971829 Bump golang.org/x/net from 0.21.0 to 0.22.0 (#1969)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.21.0 to 0.22.0.
- [Commits](https://github.com/golang/net/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-12 09:47:37 +11:00
Mike Farah b4463e29e8 Adding a EvaluateAll function to StringEvaluator #1966 2024-03-07 12:02:40 +11:00
Mike Farah 93ed666000 yqlib, default to colors off when using yaml library #1964 2024-03-07 10:55:44 +11:00
Mike Farah b5e3a01452 Added comment to goccy decoder, its will WIP 2024-03-07 10:54:15 +11:00
Mike Farah b6ea54ba93 Updating release notes 2024-03-05 14:11:13 +11:00
Mike Farah e092329bf3 String interpolation! #1149 2024-03-05 14:10:12 +11:00
Mike Farah 152b158411 Uncomment tests - oops 2024-03-05 11:23:07 +11:00
Mike Farah 72a78472af Added tostring #72 2024-03-05 10:40:55 +11:00
Mike Farah 706424a459 Improving column docs 2024-03-05 10:13:36 +11:00
Mike Farah 9adde1ac14 Bumping version 2024-02-26 08:33:29 +11:00
Mike Farah ef24680ee9 Updating release notes 2024-02-26 08:31:48 +11:00
Mike Farah 447bf28cd8 Introduced 'format' to encapsulate encoding and decoding formats together 2024-02-24 16:37:13 +11:00
Mike Farah 8f6d642012 Refactoring encoding configuration 2024-02-24 16:07:15 +11:00
Mike Farah 1d371b712f Refactoring encoding configuration 2024-02-24 15:59:12 +11:00
Mike Farah 55f6a3a49d Refactoring JSON encoder prefs 2024-02-24 15:48:59 +11:00
Mike Farah 7a01e216c4 Refactoring Yaml encoder prefs 2024-02-24 15:36:16 +11:00
Mike Farah f44d47a204 Refactoring Props encoder prefs 2024-02-24 15:14:21 +11:00
Mike Farah 2866e90c49 Refactoring XML encoder prefs 2024-02-24 15:03:30 +11:00
Mike Farah 571caa696a Refactoring Output types 2024-02-24 14:58:11 +11:00
Mike Farah 8a538394a5 Updating release notes 2024-02-24 13:59:36 +11:00
Mike Farah d0bbda20c3 Merge branch 'scop-feat/completions' 2024-02-24 13:58:33 +11:00
Mike Farah 359c4a11b2 Merge branch 'feat/completions' of github.com:scop/yq into scop-feat/completions 2024-02-24 13:48:42 +11:00
Mike Farah 3b84aaabe4 Updating release notes 2024-02-24 13:47:22 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
311c9afe2f Bump github.com/alecthomas/repr from 0.3.0 to 0.4.0 (#1953)
Bumps [github.com/alecthomas/repr](https://github.com/alecthomas/repr) from 0.3.0 to 0.4.0.
- [Commits](https://github.com/alecthomas/repr/compare/v0.3.0...v0.4.0)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/repr
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-24 13:45:17 +11:00
Mike Farah abef92d7d9 Added prune recipe 2024-02-21 14:50:55 +11:00
Mike Farah 9f3822fbaa Improving property docs 2024-02-20 13:45:31 +11:00
Mike Farah b24b484efc Added --properties-array-brackets flag for properties encoder #1933 2024-02-20 11:39:56 +11:00
Ryan DrewandGitHub 2865022cf8 Add --properties-separator option (#1951)
This commit adds the --properties-separator option, which lets users
specify the separator used between keys and values in the properties
output format. This is done by adjusting the value of
github.com/magiconair/properties#Properties.WriteSeparator at encode
time.

Some refactoring of the properties encoder unit tests was done to make
it easier to write unit tests that include different separator values.

Fixes: #1864

Signed-off-by: Ryan Drew <ryan.drew@isovalent.com>
2024-02-20 10:57:44 +11:00
Mike Farah 9a8151d316 Added csv separator flag #1950 2024-02-17 19:11:41 +11:00
Mike Farah 42439b7d00 Adding shebang documentation 2024-02-16 11:03:35 +11:00
Mike Farah 796b4a0955 Adding shebang documentation 2024-02-16 10:56:18 +11:00
Mike Farah 86bb90f989 Can shebang yq scripts! #1851 2024-02-16 10:48:07 +11:00
Mike Farah 047694546c Bumping version 2024-02-16 09:48:51 +11:00
Mike Farah 3c3f1180d9 Cleaning up log message formats 2024-02-16 09:44:22 +11:00
Mike Farah 9142c93d1b Improved log format 2024-02-16 09:26:31 +11:00
Mike Farah d9e1a789ea Fixed Toml decoding when table array defined before parent #1922 2024-02-15 16:15:01 +11:00
Mike Farah c32a9ceab8 Added new CSV option to turn off auto-parsing #1947 2024-02-15 13:11:53 +11:00
Mike Farah e81b600744 Fixing with_entries context #1925
Can now update key/value w.r.t each other
2024-02-11 10:25:38 +11:00
Mike Farah 8cde0c837c Can now retrieve the alias names of merge anchors #1942 2024-02-09 17:24:59 +11:00
Mike Farah b55f52f377 Improve merge docs 2024-02-09 14:54:22 +11:00
Mike Farah 1d06d8b482 Another comment example 2024-02-09 13:58:59 +11:00
Mike Farah 2871fa058c Release notes for next release 2024-02-09 13:55:48 +11:00
Mike Farah 2dda0a203d Comments in yq expressions! #1919 2024-02-09 13:54:27 +11:00
Mike Farah 24bd563680 Updating style docs 2024-02-09 10:47:09 +11:00
Mike Farah bf2bc29e47 Dont run release build on v4 branch 2024-02-09 10:23:46 +11:00
Mike Farah 7781eddad2 Updating release notes 2024-02-09 10:22:54 +11:00
Mike Farah c9722c22bc Re-releasing for latest dependency updates 2024-02-09 10:21:29 +11:00
Mike Farah bb66c9c872 Bumping version 2024-02-09 10:21:09 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
279d9a691d Bump golang.org/x/net from 0.20.0 to 0.21.0 (#1940)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.20.0 to 0.21.0.
- [Commits](https://github.com/golang/net/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-08 19:27:24 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1b17de134b Bump golang from 1.21.6 to 1.22.0 (#1939)
Bumps golang from 1.21.6 to 1.22.0.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-08 19:27:12 +11:00
Mike Farah e19046273e Bumping version 2024-02-08 13:34:41 +11:00
Mike Farah 5513ac8a7d Empty TOML table is an empty object 2024-02-08 13:31:56 +11:00
Elijah LopezandGitHub d4e16a413e fix: empty TOML table (#1936) 2024-02-07 19:59:50 +11:00
Mike Farah 6e21c9f77f Need to escape single quotes in bash, updated docs #1932 2024-02-02 14:58:49 +11:00
Mike Farah 2473068a1a Attempt to use the latest snapcraft build 2024-02-02 14:49:41 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6183350182 Bump github.com/goccy/go-yaml from 1.11.2 to 1.11.3 (#1930)
Bumps [github.com/goccy/go-yaml](https://github.com/goccy/go-yaml) from 1.11.2 to 1.11.3.
- [Release notes](https://github.com/goccy/go-yaml/releases)
- [Changelog](https://github.com/goccy/go-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/goccy/go-yaml/compare/v1.11.2...v1.11.3)

---
updated-dependencies:
- dependency-name: github.com/goccy/go-yaml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 15:15:28 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
33a3bb3bdf Bump golang from 1.21.5 to 1.21.6 (#1915)
Bumps golang from 1.21.5 to 1.21.6.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 11:31:17 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c06e160480 Bump golang.org/x/net from 0.19.0 to 0.20.0 (#1916)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.19.0 to 0.20.0.
- [Commits](https://github.com/golang/net/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-12 11:31:06 +11:00
Mike Farah 010750daf6 Updated to latest golint 2024-01-11 13:17:34 +11:00
Mike Farah 8af3e46fcb Fixed bump version to move v4 tag 2024-01-04 13:28:10 +11:00
Ville Skyttä 84890ae34d Add arg and flag completions 2023-12-20 09:36:57 +02:00
Ville Skyttä a69c1b5230 Generate v2 bash completions
https://github.com/spf13/cobra/blob/main/site/content/completions/_index.md#bash-completion-v2
2023-12-20 09:33:51 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
aaef27147f Bump github.com/pelletier/go-toml/v2 from 2.1.0 to 2.1.1 (#1904)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-14 16:32:51 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
16bab88946 Bump github/codeql-action from 2 to 3 (#1903)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-14 16:32:38 +11:00
Mike Farah dea8f95670 Fixed "all" error message #1845 2023-12-13 11:02:22 +11:00
Mike Farah eb4278784a Added another new recipe 2023-12-13 10:55:53 +11:00
Mike Farah cbd03f8a93 Added new recipe 2023-12-13 10:41:56 +11:00
Mike Farah 4cf123fed5 Fixed to_entries[] 2023-12-12 15:44:34 +11:00
Mike Farah eff7d99e2b Added sample yq script 2023-12-12 13:08:18 +11:00
Mike Farah dd64899434 Bumping version 2023-12-12 11:35:15 +11:00
Mike Farah 755becdde3 Release notes 2023-12-12 11:34:38 +11:00
Mike Farah 7f26d91cd0 Fixed handling of --- #1890, #1896 2023-12-12 11:30:12 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fa322aec33 Bump golang from 1.21.4 to 1.21.5 (#1895)
Bumps golang from 1.21.4 to 1.21.5.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 09:55:54 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c7b14eacbd Bump actions/setup-go from 4 to 5 (#1894)
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4 to 5.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 09:55:42 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2fd1537b35 Bump github.com/alecthomas/participle/v2 from 2.1.0 to 2.1.1 (#1893)
Bumps [github.com/alecthomas/participle/v2](https://github.com/alecthomas/participle) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/alecthomas/participle/releases)
- [Changelog](https://github.com/alecthomas/participle/blob/master/CHANGES.md)
- [Commits](https://github.com/alecthomas/participle/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: github.com/alecthomas/participle/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 09:55:33 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
1db4b52c3a Bump github.com/yuin/gopher-lua from 1.1.0 to 1.1.1 (#1892)
Bumps [github.com/yuin/gopher-lua](https://github.com/yuin/gopher-lua) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/yuin/gopher-lua/releases)
- [Commits](https://github.com/yuin/gopher-lua/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: github.com/yuin/gopher-lua
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 09:55:24 +11:00
Mike Farah d474bb8ba4 Fixing sef fault on bad XML #1888 2023-12-05 13:21:12 +11:00
Mike Farah 1c3d551060 Bumping version 2023-12-04 11:17:53 +11:00
Mike Farah d16b6fbb03 Release notes 2023-12-04 11:17:40 +11:00
Mike Farah 54a6978e97 Release notes 2023-12-04 11:16:49 +11:00
Mike Farah a988cd9005 Updating JSON doc: NDJSON spec deprecated, prefer JSON Lines 2023-12-01 11:39:02 +11:00
Mike Farah 779b26310e Updating references to yq being a YAML processor 2023-11-30 15:32:21 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
638deed03e Bump golang.org/x/net from 0.18.0 to 0.19.0 (#1887)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/net/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-30 15:12:03 +11:00
Mike Farah 730f240d24 Fixed to_entries and del bug #1886 2023-11-30 14:04:54 +11:00
Mike Farah c11a53322b Bumping version 2023-11-23 11:59:22 +11:00
Mike Farah 430a6d5237 Release notes 2023-11-23 11:58:31 +11:00
Ville SkyttäandGitHub eecc106529 Update JSON to YAML example for new JSON input output default (#1875) 2023-11-23 11:54:43 +11:00
Ville SkyttäandGitHub 998b4edb34 Grammar fixes (#1877) 2023-11-23 11:54:25 +11:00
Mike Farah 26effddb8c Fixed empty array json bug #1880 2023-11-23 11:53:18 +11:00
Mike Farah 1cf9ecc79d Bumping version 2023-11-18 15:05:29 +11:00
Mike Farah 8024470b51 Updating release notes 2023-11-18 15:04:42 +11:00
Alessandro Di StefanoandGitHub e5cc57bedf Do not panic when StdIn is closed (#1867)
When the shell executing yq has no open stdin, os.Stdin.Stat() return nil and yq fails to continue. This commit fixes a missing verification on the result of os.Stdin.Stat() in the utils.processStdInArgs function and adds an acceptance test to cover this scenario in the future. This bug affects yq since version 4.26.1.
2023-11-18 12:20:12 +11:00
Mike Farah 3d64bdadc1 Fixes issue when update against self #1869 2023-11-18 12:19:27 +11:00
Mike Farah 4b8c8506a5 Updating release notes 2023-11-14 14:39:37 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f789740f7e Bump github.com/elliotchance/orderedmap from 1.5.0 to 1.5.1 (#1854)
Bumps [github.com/elliotchance/orderedmap](https://github.com/elliotchance/orderedmap) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/elliotchance/orderedmap/releases)
- [Commits](https://github.com/elliotchance/orderedmap/compare/v1.5.0...v1.5.1)

---
updated-dependencies:
- dependency-name: github.com/elliotchance/orderedmap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 13:55:55 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0523c9df87 Bump golang.org/x/net from 0.17.0 to 0.18.0 (#1856)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/net/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-14 13:55:32 +11:00
Mike Farah c7ef946031 Fixed multi doc anchor bug #1861 2023-11-14 13:00:30 +11:00
Mike Farah 79a50b9c20 Fixes dos line separator issue when reading expression file #1860 2023-11-10 09:34:01 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b75dc0782b Bump github.com/fatih/color from 1.15.0 to 1.16.0 (#1857)
Bumps [github.com/fatih/color](https://github.com/fatih/color) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/fatih/color/releases)
- [Commits](https://github.com/fatih/color/compare/v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: github.com/fatih/color
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 09:15:04 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
fc940689bf Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#1858)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 09:14:49 +11:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7892d38fca Bump golang from 1.21.3 to 1.21.4 (#1859)
Bumps golang from 1.21.3 to 1.21.4.

---
updated-dependencies:
- dependency-name: golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-10 09:14:31 +11:00
Mike Farah 5f4c1fbd0a Bumping version 2023-11-08 09:35:43 +11:00
Mike Farah 8122c9edf2 Release notes 2023-11-08 09:14:45 +11:00
Mike Farah d6e099f7ff Formatting 2023-11-08 09:09:21 +11:00
Jason MeridthandGitHub bbe196ba11 feat: upgrade go.mod to 1.21 (#1830)
This matches what was changed in the Dockerfile

### CSpell results

CSpell: Files checked: 243, Issues found: 0 in 0 files

### GOSec results

Summary:
  Gosec  : 2.18.1
  Files  : 121
  Lines  : 13091
  Nosec  : 8
  Issues : 0

### Test Results

?   	github.com/mikefarah/yq/v4	[no test files]
ok  	github.com/mikefarah/yq/v4/cmd	0.693s
ok  	github.com/mikefarah/yq/v4/pkg/yqlib	1.023

Signed-off-by: jmeridth <jmeridth@gmail.com>
2023-10-23 20:04:10 +11:00
Valentin LabandGitHub a60d27975a add tests for root node unwrap bug in previous versions (#1837) 2023-10-23 20:03:51 +11:00
Mike Farah c8f4ba7f45 Removing copier lib 2023-10-18 12:36:52 +11:00
Mike FarahandGitHub 13d1bbb45f Generic ast (#1829)
Remove dependency on yaml.Node for internal AST representation. Yaml decoder is now just another decoder.
2023-10-18 12:11:53 +11:00
313 changed files with 12511 additions and 4272 deletions
-51
View File
@@ -1,51 +0,0 @@
---
name: Bug report - V3
about: Create a report to help us improve
title: ''
labels: bug, v3
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
Note that any how to questions should be posted in the discussion board and not raised as an issue.
Version of yq: 3.X.X
Operating system: mac/linux/windows/....
Installed via: docker/binary release/homebrew/snap/...
**Input Yaml**
Concise yaml document(s) (as simple as possible to show the bug, please keep it to 10 lines or less)
data1.yml:
```yaml
this: should really work
```
data2.yml:
```yaml
but: it strangely didn't
```
**Command**
The command you ran:
```
yq merge data1.yml data2.yml
```
**Actual behavior**
```yaml
cat: meow
```
**Expected behavior**
```yaml
this: should really work
but: it strangely didn't
```
**Additional context**
Add any other context about the problem here.
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,7 +53,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -67,4 +67,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
+23 -5
View File
@@ -30,6 +30,19 @@ jobs:
- name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }} && docker version
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
run: |
echo "GithubRef: ${GITHUB_REF}"
@@ -38,14 +51,13 @@ jobs:
IMAGE_VERSION=${VERSION:1}
echo "IMAGE_VERSION: ${IMAGE_VERSION}"
PLATFORMS="linux/amd64,linux/ppc64le,linux/arm64"
PLATFORMS="linux/amd64,linux/ppc64le,linux/arm64,linux/arm/v7,linux/s390x"
echo "Building and pushing version ${IMAGE_VERSION} of image ${IMAGE_NAME}"
echo '${{ secrets.DOCKER_PASSWORD }}' | docker login -u '${{ secrets.DOCKER_USERNAME }}' --password-stdin
docker buildx build \
--label "org.opencontainers.image.authors=https://github.com/mikefarah/yq/graphs/contributors" \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--label "org.opencontainers.image.description=yq is a portable command-line YAML processor" \
--label "org.opencontainers.image.description=yq is a portable command-line data file processor" \
--label "org.opencontainers.image.documentation=https://mikefarah.gitbook.io/yq/" \
--label "org.opencontainers.image.licenses=MIT" \
--label "org.opencontainers.image.revision=$(git rev-parse HEAD)" \
@@ -59,13 +71,16 @@ jobs:
-t "${IMAGE_NAME}:${IMAGE_VERSION}" \
-t "${IMAGE_NAME}:4" \
-t "${IMAGE_NAME}:latest" \
-t "ghcr.io/${IMAGE_NAME}:${IMAGE_VERSION}" \
-t "ghcr.io/${IMAGE_NAME}:4" \
-t "ghcr.io/${IMAGE_NAME}:latest" \
.
cd github-action
docker buildx build \
--label "org.opencontainers.image.authors=https://github.com/mikefarah/yq/graphs/contributors" \
--label "org.opencontainers.image.created=$(date --rfc-3339=seconds)" \
--label "org.opencontainers.image.description=yq is a portable command-line YAML processor" \
--label "org.opencontainers.image.description=yq is a portable command-line data file processor" \
--label "org.opencontainers.image.documentation=https://mikefarah.gitbook.io/yq/" \
--label "org.opencontainers.image.licenses=MIT" \
--label "org.opencontainers.image.revision=$(git rev-parse HEAD)" \
@@ -79,4 +94,7 @@ jobs:
-t "${IMAGE_NAME}:${IMAGE_VERSION}-githubaction" \
-t "${IMAGE_NAME}:4-githubaction" \
-t "${IMAGE_NAME}:latest-githubaction" \
-t "ghcr.io/${IMAGE_NAME}:${IMAGE_VERSION}-githubaction" \
-t "ghrc.io/${IMAGE_NAME}:4-githubaction" \
-t "ghcr.io/${IMAGE_NAME}:latest-githubaction" \
.
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
steps:
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: '^1.20'
id: go
+3 -5
View File
@@ -2,7 +2,7 @@ name: Release YQ
on:
push:
tags:
- 'v*'
- 'v4.*'
- 'draft-*'
jobs:
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version: '^1.20'
check-latest: true
@@ -40,9 +40,7 @@ jobs:
- name: Cross compile
run: |
sudo apt-get install rhash -y
go install github.com/mitchellh/gox@v1.0.1
mkdir -p build
cp yq.1 build/yq.1
go install github.com/goreleaser/goreleaser/v2@latest
./scripts/xcompile.sh
- name: Release
+3
View File
@@ -22,6 +22,7 @@ _cgo_gotypes.go
_cgo_export.*
_testmain.go
cover.out
coverage.out
coverage.html
*.exe
@@ -44,6 +45,8 @@ test*.yml
test*.xml
test*.toml
test*.yaml
test_dir1/
test_dir2/
0.yml
1.yml
2.yml
+38
View File
@@ -0,0 +1,38 @@
run:
timeout: 5m
linters:
enable:
- asciicheck
- depguard
- errorlint
- gci
- gochecknoinits
- gofmt
- goimports
- gosec
- gosimple
- staticcheck
- unused
- misspell
- nakedret
- nolintlint
- predeclared
- revive
- unconvert
- unparam
linters-settings:
depguard:
rules:
prevent_unmaintained_packages:
list-mode: lax
files:
- $all
- "!$test"
deny:
- pkg: io/ioutil
desc: "replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil"
issues:
exclude-rules:
- linters:
- revive
text: "var-naming"
+38 -26
View File
@@ -1,16 +1,11 @@
run:
timeout: 5m
version: "2"
linters:
enable:
- asciicheck
- depguard
- errorlint
- gci
- gochecknoinits
- gofmt
- goimports
- gosec
- megacheck
- misspell
- nakedret
- nolintlint
@@ -18,23 +13,40 @@ linters:
- revive
- unconvert
- unparam
linters-settings:
depguard:
list-type: blacklist
include-go-root: true
packages:
- io/ioutil
packages-with-error-message:
- io/ioutil: "The 'io/ioutil' package is deprecated. Use corresponding 'os' or 'io' functions instead."
issues:
exclude-rules:
- linters:
- gosec
text: "Implicit memory aliasing in for loop."
path: _test\.go
- linters:
- revive
text: "unexported-return"
- linters:
- revive
text: "var-naming"
settings:
depguard:
rules:
prevent_unmaintained_packages:
list-mode: lax
files:
- $all
- '!$test'
deny:
- pkg: io/ioutil
desc: 'replaced by io and os packages since Go 1.16: https://tip.golang.org/doc/go1.16#ioutil'
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- linters:
- revive
text: var-naming
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
+48
View File
@@ -0,0 +1,48 @@
version: 2
dist: build
builds:
- id: yq
binary: yq_{{ .Os }}_{{ .Arch }}
ldflags:
- -s -w
env:
- CGO_ENABLED=0
targets:
- 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_riscv64
- linux_s390x
- netbsd_386
- netbsd_amd64
- netbsd_arm
- openbsd_386
- openbsd_amd64
- windows_386
- windows_amd64
- windows_arm
- windows_arm64
no_unique_dist_dir: true
release:
disable: true
skip_upload: true
+3 -1
View File
@@ -1,4 +1,4 @@
# Development
.# Development
1. Install (Golang)[https://golang.org/]
1. Run `scripts/devtools.sh` to install the required devtools
@@ -25,6 +25,8 @@ The pipeline will run the tests and automatically concatenate the files together
The first step is to find if what you want is automatically generated or not - start by looking in the master branch.
Note that PRs with small changes (e.g. minor typos) may not be merged (see https://joel.net/how-one-guy-ruined-hacktoberfest2020-drama).
### Updating dynamic documentation from master
- Search for the documentation you want to update. If you find matches in a `*_test.go` file - update that, as that will automatically update the matching `*.md` file
- Assuming you are updating a `*_test.go` file, once updated, run the test to regenerated the docs. E.g. for the 'Add' test generated docs, from the pkg/yqlib folder run:
+2 -2
View File
@@ -1,4 +1,4 @@
FROM golang:1.21.3 as builder
FROM golang:1.24.5 AS builder
WORKDIR /go/src/mikefarah/yq
@@ -10,7 +10,7 @@ RUN ./scripts/acceptance.sh
# Choose alpine as a base image to make this useful for CI, as many
# CI tools expect an interactive shell inside the container
FROM alpine:3 as production
FROM alpine:3 AS production
LABEL maintainer="Mike Farah <mikefarah@users.noreply.github.com>"
COPY --from=builder /go/src/mikefarah/yq/yq /usr/bin/yq
+8 -5
View File
@@ -1,12 +1,15 @@
FROM golang:1.21.3
FROM golang:1.24.5
RUN apt-get update && \
apt-get install -y npm && \
npm install -g npx cspell@latest
COPY scripts/devtools.sh /opt/devtools.sh
RUN set -e -x \
&& /opt/devtools.sh
ENV PATH=/go/bin:$PATH
RUN set -e -x && \
/opt/devtools.sh
RUN apt-get update && apt-get install -y npm && npm install -g npx cspell@latest
ENV PATH=/go/bin:$PATH
ENV CGO_ENABLED 0
ENV GOPATH /go:/yq
+1 -1
View File
@@ -2,7 +2,7 @@ MAKEFLAGS += --warn-undefined-variables
SHELL := /bin/bash
.SHELLFLAGS := -o pipefail -euc
.DEFAULT_GOAL := install
ENGINE := $(shell { command -v podman || command -v docker; } 2>/dev/null)
ENGINE := $(shell { (podman version > /dev/null 2>&1 && command -v podman) || command -v docker; } 2>/dev/null)
include Makefile.variables
+3 -2
View File
@@ -26,6 +26,7 @@ ifeq ($(CYG_CHECK),1)
else
# all non-windows environments
ROOT := $(shell pwd)
SELINUX := $(shell which getenforce 2>&1 >/dev/null && echo :z)
endif
DEV_IMAGE := ${PROJECT}_dev
@@ -33,7 +34,7 @@ DEV_IMAGE := ${PROJECT}_dev
ENGINERUN := ${ENGINE} run --rm \
-e LDFLAGS="${LDFLAGS}" \
-e GITHUB_TOKEN="${GITHUB_TOKEN}" \
-v ${ROOT}/vendor:/go/src \
-v ${ROOT}:/${PROJECT}/src/${IMPORT_PATH} \
-v ${ROOT}/vendor:/go/src${SELINUX} \
-v ${ROOT}:/${PROJECT}/src/${IMPORT_PATH}${SELINUX} \
-w /${PROJECT}/src/${IMPORT_PATH} \
${DEV_IMAGE}
+67 -22
View File
@@ -3,7 +3,7 @@
![Build](https://github.com/mikefarah/yq/workflows/Build/badge.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/mikefarah/yq.svg) ![Github Releases (by Release)](https://img.shields.io/github/downloads/mikefarah/yq/total.svg) ![Go Report](https://goreportcard.com/badge/github.com/mikefarah/yq) ![CodeQL](https://github.com/mikefarah/yq/workflows/CodeQL/badge.svg)
a lightweight and portable command-line YAML, JSON and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json, xml, properties, csv and tsv. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
a lightweight and portable command-line YAML, JSON, INI and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json, xml, ini, properties, csv and tsv. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
yq is written in go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as Docker and Podman, all listed below.
@@ -31,6 +31,10 @@ NAME=mike yq -i '.a.b[0].c = strenv(NAME)' file.yaml
Merge multiple files
```bash
# merge two files
yq -n 'load("file1.yaml") * load("file2.yaml")'
# merge using globs:
# note the use of `ea` to evaluate all the files at once
# instead of in sequence
yq ea '. as $item ireduce ({}; . * $item )' path/to/*.yml
@@ -72,21 +76,21 @@ 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 - |\
tar xz && mv ${BINARY} /usr/bin/yq
tar xz && mv ${BINARY} /usr/local/bin/yq
```
#### Plain binary
```bash
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq &&\
chmod +x /usr/bin/yq
wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/local/bin/yq &&\
chmod +x /usr/local/bin/yq
```
#### Latest version
```bash
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq &&\
chmod +x /usr/bin/yq
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq &&\
chmod +x /usr/local/bin/yq
```
### MacOS / Linux via Homebrew:
@@ -237,6 +241,14 @@ As these are supported by the community :heart: - however, they may be out of da
_Please note that the Debian package (previously supported by @rmescandon) is no longer maintained. Please use an alternative installation method._
### X-CMD
Checkout `yq` on x-cmd: https://x-cmd.com/mod/yq
- Instant Results: See the output of your yq filter in real-time.
- Error Handling: Encounter a syntax error? It will display the error message and the results of the closest valid filter
Thanks @edwinjhlee!
### Nix
```
@@ -291,18 +303,31 @@ sudo port install yq
Supported by @herbygillot (https://ports.macports.org/maintainer/github/herbygillot)
### Alpine Linux
- Enable edge/community repo by adding ```$MIRROR/alpine/edge/community``` to ```/etc/apk/repositories```
- Update database index with ```apk update```
- Install yq with ```apk add yq```
Supported by Tuan Hoang
https://pkgs.alpinelinux.org/package/edge/community/x86/yq
Alpine Linux v3.20+ (and Edge):
```
apk add yq-go
```
Alpine Linux up to v3.19:
```
apk add yq
```
Supported by Tuan Hoang (https://pkgs.alpinelinux.org/packages?name=yq-go)
### Flox:
Flox can be used to install yq on Linux, MacOS, and Windows through WSL.
```
flox install yq
```
## Features
- [Detailed documentation with many examples](https://mikefarah.gitbook.io/yq/)
- Written in portable go, so you can download a lovely dependency free binary
- Uses similar syntax as `jq` but works with YAML, [JSON](https://mikefarah.gitbook.io/yq/usage/convert) and [XML](https://mikefarah.gitbook.io/yq/usage/xml) files
- Uses similar syntax as `jq` but works with YAML, INI, [JSON](https://mikefarah.gitbook.io/yq/usage/convert) and [XML](https://mikefarah.gitbook.io/yq/usage/xml) files
- Fully supports multi document yaml files
- Supports yaml [front matter](https://mikefarah.gitbook.io/yq/usage/front-matter) blocks (e.g. jekyll/assemble)
- Colorized yaml output
@@ -341,32 +366,52 @@ yq -i '.stuff = "foo"' myfile.yml # update myfile.yml in place
Available Commands:
completion Generate the autocompletion script for the specified shell
eval (default) Apply the expression to each document in each yaml file in sequence
eval-all Loads _all_ yaml documents of _all_ yaml files and runs expression once
help Help about any command
shell-completion Generate completion script
completion Generate the autocompletion script for the specified shell
eval (default) Apply the expression to each document in each yaml file in sequence
eval-all Loads _all_ yaml documents of _all_ yaml files and runs expression once
help Help about any command
Flags:
-C, --colors force print with colors
--csv-auto-parse parse CSV YAML/JSON values (default true)
--csv-separator char CSV Separator character (default ,)
-e, --exit-status set exit status if there are no matches or null or false is returned
--expression string forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.
--from-file string Load expression from specified file.
-f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact
--header-preprocess Slurp any header comments and separators before processing expression. (default true)
-h, --help help for yq
-I, --indent int sets indent level for output (default 2)
-i, --inplace update the file in place 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")
-p, --input-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|lua|l|ini|i] parse format for input. (default "auto")
--lua-globals output keys as top-level global variables
--lua-prefix string prefix (default "return ")
--lua-suffix string suffix (default ";\n")
--lua-unquoted output unquoted string keys (e.g. {foo="bar"})
-M, --no-colors force print with no colors
-N, --no-doc Don't print document separators (---)
-0, --nul-output Use NUL char to separate values. If unwrap scalar is also set, fail if unwrapped scalar contains NUL char.
-n, --null-input Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.
-o, --output-format string [yaml|y|json|j|props|p|xml|x] output format type. (default "yaml")
-o, --output-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|shell|s|lua|l|ini|i] output format type. (default "auto")
-P, --prettyPrint pretty print, shorthand for '... style = ""'
-s, --split-exp string print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.
--unwrapScalar unwrap scalar, print the value with no quotes, colors or comments (default true)
--properties-array-brackets use [x] in array paths (e.g. for SpringBoot)
--properties-separator string separator to use between keys and values (default " = ")
-s, --split-exp string print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter. The necessary directories will be created.
--split-exp-file string Use a file to specify the split-exp expression.
--string-interpolation Toggles strings interpolation of \(exp) (default true)
--tsv-auto-parse parse TSV YAML/JSON values (default true)
-r, --unwrapScalar unwrap scalar, print the value with no quotes, colors or comments. Defaults to true for yaml (default true)
-v, --verbose verbose mode
-V, --version Print version information and quit
--xml-attribute-prefix string prefix for xml attributes (default "+")
--xml-attribute-prefix string prefix for xml attributes (default "+@")
--xml-content-name string name for xml content (if no attribute name is present). (default "+content")
--xml-directive-name string name for xml directives (e.g. <!DOCTYPE thing cat>) (default "+directive")
--xml-keep-namespace enables keeping namespace after parsing attributes (default true)
--xml-proc-inst-prefix string prefix for xml processing instructions (e.g. <?xml version="1"?>) (default "+p_")
--xml-raw-token enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details. (default true)
--xml-skip-directives skip over directives (e.g. <!DOCTYPE thing cat>)
--xml-skip-proc-inst skip over process instructions (e.g. <?xml version="1"?>)
--xml-strict-mode enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details.
Use "yq [command] --help" for more information about a command.
```
+18 -1
View File
@@ -96,6 +96,17 @@ testBasicExpressionFromFile() {
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
}
testBasicExpressionFromFileDos() {
./yq -n ".xyz = 123" > test.yml
echo '.xyz = "meow" | .cool = "frog"' | sed 's/$'"/`echo \\\r`/" > instructions.txt
X=$(./yq --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
X=$(./yq ea --from-file instructions.txt test.yml -o=j -I=0)
assertEquals '{"xyz":"meow","cool":"frog"}' "$X"
}
testBasicGitHubAction() {
./yq -n ".a = 123" > test.yml
X=$(cat /dev/null | ./yq test.yml)
@@ -351,6 +362,12 @@ EOM
assertEquals "$expected" "$X"
}
testBasicClosedStdIn() {
cat >test.yml <<EOL
a: 1
EOL
X=$(./yq e '.a' test.yml <&-)
assertEquals "1" "$X"
}
source ./scripts/shunit2
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
setUp() {
rm test*.yml || true
cat >test.yml <<EOL
# comment
EOL
}
testStringInterpolation() {
X=$(./yq -n '"Mike \(3 + 4)"')
assertEquals "Mike 7" "$X"
}
testNoStringInterpolation() {
X=$(./yq --string-interpolation=f -n '"Mike \(3 + 4)"')
assertEquals "Mike \(3 + 4)" "$X"
}
source ./scripts/shunit2
+55
View File
@@ -63,6 +63,61 @@ EOM
assertEquals "$expected" "$X"
}
testInputCSVCustomSeparator() {
cat >test.csv <<EOL
fruit;yumLevel
apple;5
banana;4
EOL
read -r -d '' expected << EOM
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOM
X=$(./yq -p=csv --csv-separator ";" test.csv)
assertEquals "$expected" "$X"
X=$(./yq ea -p=csv --csv-separator ";" test.csv)
assertEquals "$expected" "$X"
}
testInputCSVNoAuto() {
cat >test.csv <<EOL
thing1
name: cat
EOL
read -r -d '' expected << EOM
- thing1: 'name: cat'
EOM
X=$(./yq --csv-auto-parse=f test.csv -oy)
assertEquals "$expected" "$X"
X=$(./yq ea --csv-auto-parse=f test.csv -oy)
assertEquals "$expected" "$X"
}
testInputTSVNoAuto() {
cat >test.tsv <<EOL
thing1
name: cat
EOL
read -r -d '' expected << EOM
- thing1: 'name: cat'
EOM
X=$(./yq --tsv-auto-parse=f test.tsv -oy)
assertEquals "$expected" "$X"
X=$(./yq ea --tsv-auto-parse=f test.tsv -oy)
assertEquals "$expected" "$X"
}
testInputCSVUTF8() {
read -r -d '' expected << EOM
- id: 1
+4 -4
View File
@@ -3,25 +3,25 @@
testLoadFileNotExist() {
result=$(./yq e -n 'load("cat.yml")' 2>&1)
assertEquals 1 $?
assertEquals "Error: Failed to load cat.yml: open cat.yml: no such file or directory" "$result"
assertEquals "Error: failed to load cat.yml: open cat.yml: no such file or directory" "$result"
}
testLoadFileExpNotExist() {
result=$(./yq e -n 'load(.a)' 2>&1)
assertEquals 1 $?
assertEquals "Error: Filename expression returned nil" "$result"
assertEquals "Error: filename expression returned nil" "$result"
}
testStrLoadFileNotExist() {
result=$(./yq e -n 'strload("cat.yml")' 2>&1)
assertEquals 1 $?
assertEquals "Error: Failed to load cat.yml: open cat.yml: no such file or directory" "$result"
assertEquals "Error: failed to load cat.yml: open cat.yml: no such file or directory" "$result"
}
testStrLoadFileExpNotExist() {
result=$(./yq e -n 'strload(.a)' 2>&1)
assertEquals 1 $?
assertEquals "Error: Filename expression returned nil" "$result"
assertEquals "Error: filename expression returned nil" "$result"
}
source ./scripts/shunit2
+30
View File
@@ -72,6 +72,15 @@ EOL
assertEquals "\"cat\"" "$X"
}
testOutputYamlRawOnRoot() {
cat >test.yml <<EOL
'a'
EOL
X=$(./yq e -r '.' test.yml)
assertEquals "a" "$X"
}
testOutputJsonRaw() {
cat >test.yml <<EOL
a: cat
@@ -189,6 +198,27 @@ EOM
assertEquals "$expected" "$X"
}
testOutputCSVCustomSeparator() {
cat >test.yml <<EOL
- fruit: apple
yumLevel: 5
- fruit: banana
yumLevel: 4
EOL
read -r -d '' expected << EOM
fruit;yumLevel
apple;5
banana;4
EOM
X=$(./yq -oc --csv-separator ";" test.yml)
assertEquals "$expected" "$X"
X=$(./yq ea -o=csv --csv-separator ";" test.yml)
assertEquals "$expected" "$X"
}
testOutputTSV() {
cat >test.yml <<EOL
- fruit: apple
+26
View File
@@ -0,0 +1,26 @@
#!/bin/bash
setUp() {
rm test*.yq || true
cat >test.yq <<EOL
#!./yq
.a.b
EOL
chmod +x test.yq
rm test*.yml || true
cat >test.yml <<EOL
a: {b: apple}
EOL
}
testCanExecYqFile() {
read -r -d '' expected << EOM
apple
EOM
X=$(./test.yq test.yml)
assertEquals "$expected" "$X"
}
source ./scripts/shunit2
+21 -1
View File
@@ -2,6 +2,7 @@
setUp() {
rm test*.yml || true
rm -rf test_dir* || true
}
testBasicSplitWithName() {
@@ -204,4 +205,23 @@ EOM
assertEquals "$expectedDoc3" "$doc3"
}
source ./scripts/shunit2
testSplitWithDirectories() {
cat >test.yml <<EOL
f: test_dir1/test_file1
---
f: test_dir2/dir22/test_file2
---
f: test_file3
EOL
./yq e --no-doc -s ".f" test.yml
doc1=$(cat test_dir1/test_file1.yml)
assertEquals "f: test_dir1/test_file1" "$doc1"
doc2=$(cat test_dir2/dir22/test_file2.yml)
assertEquals "f: test_dir2/dir22/test_file2" "$doc2"
doc3=$(cat test_file3.yml)
assertEquals "f: test_file3" "$doc3"
}
source ./scripts/shunit2
+10 -9
View File
@@ -7,19 +7,20 @@ import (
)
var completionCmd = &cobra.Command{
Use: "shell-completion [bash|zsh|fish|powershell]",
Short: "Generate completion script",
Use: "completion [bash|zsh|fish|powershell]",
Aliases: []string{"shell-completion"},
Short: "Generate the autocompletion script for the specified shell",
Long: `To load completions:
Bash:
$ source <(yq shell-completion bash)
$ source <(yq completion bash)
# To load completions for each session, execute once:
Linux:
$ yq shell-completion bash > /etc/bash_completion.d/yq
$ yq completion bash > /etc/bash_completion.d/yq
MacOS:
$ yq shell-completion bash > /usr/local/etc/bash_completion.d/yq
$ yq completion bash > /usr/local/etc/bash_completion.d/yq
Zsh:
@@ -29,16 +30,16 @@ Zsh:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ yq shell-completion zsh > "${fpath[1]}/_yq"
$ yq completion zsh > "${fpath[1]}/_yq"
# You will need to start a new shell for this setup to take effect.
Fish:
$ yq shell-completion fish | source
$ yq completion fish | source
# To load completions for each session, execute once:
$ yq shell-completion fish > ~/.config/fish/completions/yq.fish
$ yq completion fish > ~/.config/fish/completions/yq.fish
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
@@ -47,7 +48,7 @@ $ yq shell-completion fish > ~/.config/fish/completions/yq.fish
var err error = nil
switch args[0] {
case "bash":
err = cmd.Root().GenBashCompletion(os.Stdout)
err = cmd.Root().GenBashCompletionV2(os.Stdout, true)
case "zsh":
err = cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
+6 -3
View File
@@ -2,6 +2,8 @@ package cmd
var unwrapScalarFlag = newUnwrapFlag()
var printNodeInfo = false
var unwrapScalar = false
var writeInplace = false
@@ -12,9 +14,6 @@ var outputFormat = ""
var inputFormat = ""
var exitStatus = false
var forceColor = false
var forceNoColor = false
var colorsEnabled = false
var indent = 2
var noDocSeparators = false
var nullInput = false
@@ -23,6 +22,10 @@ var verbose = false
var version = false
var prettyPrint = false
var forceColor = false
var forceNoColor = false
var colorsEnabled = false
// can be either "" (off), "extract" or "process"
var frontMatter = ""
+8 -2
View File
@@ -12,6 +12,12 @@ func createEvaluateAllCommand() *cobra.Command {
Use: "eval-all [expression] [yaml_file1]...",
Aliases: []string{"ea"},
Short: "Loads _all_ yaml documents of _all_ yaml files and runs expression once",
ValidArgsFunction: func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveDefault
},
Example: `
# Merge f2.yml into f1.yml (in place)
yq eval-all --inplace 'select(fileIndex == 0) * select(fileIndex == 1)' f1.yml f2.yml
@@ -26,7 +32,7 @@ yq ea '. as $item ireduce ({}; . * $item )' file1.yml file2.yml ...
## use '-' as a filename to pipe from STDIN
cat file2.yml | yq ea '.a.b' file1.yml - file3.yml
`,
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
Long: `yq is a portable command-line data file processor (https://github.com/mikefarah/yq/)
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.
## Evaluate All ##
@@ -70,7 +76,7 @@ func evaluateAll(cmd *cobra.Command, args []string) (cmdError error) {
}()
}
format, err := yqlib.OutputFormatFromString(outputFormat)
format, err := yqlib.FormatFromString(outputFormat)
if err != nil {
return err
}
+13 -2
View File
@@ -13,6 +13,12 @@ func createEvaluateSequenceCommand() *cobra.Command {
Use: "eval [expression] [yaml_file1]...",
Aliases: []string{"e"},
Short: "(default) Apply the expression to each document in each yaml file in sequence",
ValidArgsFunction: func(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveDefault
},
Example: `
# Reads field under the given path for each file
yq e '.a.b' f1.yml f2.yml
@@ -31,7 +37,7 @@ yq e -n '.a.b.c = "cat"'
# Update a file in place
yq e '.a.b = "cool"' -i file.yaml
`,
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
Long: `yq is a portable command-line data file processor (https://github.com/mikefarah/yq/)
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.
## Evaluate Sequence ##
@@ -84,7 +90,7 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
}()
}
format, err := yqlib.OutputFormatFromString(outputFormat)
format, err := yqlib.FormatFromString(outputFormat)
if err != nil {
return err
}
@@ -99,6 +105,11 @@ func evaluateSequence(cmd *cobra.Command, args []string) (cmdError error) {
}
printer := yqlib.NewPrinter(encoder, printerWriter)
if printNodeInfo {
printer = yqlib.NewNodeInfoPrinter(printerWriter)
}
if nulSepOutput {
printer.SetNulSepOutput(true)
}
+123 -17
View File
@@ -1,21 +1,52 @@
package cmd
import (
"fmt"
"os"
"strings"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
logging "gopkg.in/op/go-logging.v1"
)
type runeValue rune
func newRuneVar(p *rune) *runeValue {
return (*runeValue)(p)
}
func (r *runeValue) String() string {
return string(*r)
}
func (r *runeValue) Set(rawVal string) error {
val := strings.ReplaceAll(rawVal, "\\n", "\n")
val = strings.ReplaceAll(val, "\\t", "\t")
val = strings.ReplaceAll(val, "\\r", "\r")
val = strings.ReplaceAll(val, "\\f", "\f")
val = strings.ReplaceAll(val, "\\v", "\v")
if len(val) != 1 {
return fmt.Errorf("[%v] is not a valid character. Must be length 1 was %v", val, len(val))
}
*r = runeValue(rune(val[0]))
return nil
}
func (r *runeValue) Type() string {
return "char"
}
func New() *cobra.Command {
var rootCmd = &cobra.Command{
Use: "yq",
Short: "yq is a lightweight and portable command-line YAML processor.",
Long: `yq is a portable command-line YAML processor (https://github.com/mikefarah/yq/)
Short: "yq is a lightweight and portable command-line data file processor.",
Long: `yq is a portable command-line data file processor (https://github.com/mikefarah/yq/)
See https://mikefarah.gitbook.io/yq/ for detailed documentation and examples.`,
Example: `
# yq defaults to 'eval' command if no command is specified. See "yq eval --help" for more examples.
# yq tries to auto-detect the file format based off the extension, and defaults to YAML if it's unknown (or piping through STDIN)
# Use the '-p/--input-format' flag to specify a format type.
cat file.xml | yq -p xml
# read the "stuff" node from "myfile.yml"
yq '.stuff' < myfile.yml
@@ -24,7 +55,7 @@ yq '.stuff' < myfile.yml
yq -i '.stuff = "foo"' myfile.yml
# print contents of sample.json as idiomatic YAML
yq -P sample.json
yq -P -oy sample.json
`,
RunE: func(cmd *cobra.Command, args []string) error {
@@ -35,20 +66,30 @@ yq -P sample.json
return evaluateSequence(cmd, args)
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
cmd.SetOut(cmd.OutOrStdout())
level := logging.WARNING
stringFormat := `[%{level}] %{color}%{time:15:04:05}%{color:reset} %{message}`
var format = logging.MustStringFormatter(
`%{color}%{time:15:04:05} %{shortfunc} [%{level:.4s}]%{color:reset} %{message}`,
)
// when NO_COLOR environment variable presents and not an empty string the coloured output should be disabled;
// refer to no-color.org
forceNoColor = forceNoColor || os.Getenv("NO_COLOR") != ""
if verbose && forceNoColor {
level = logging.DEBUG
stringFormat = `[%{level:5.5s}] %{time:15:04:05} %{shortfile:-33s} %{shortfunc:-25s} %{message}`
} else if verbose {
level = logging.DEBUG
stringFormat = `[%{level:5.5s}] %{color}%{time:15:04:05}%{color:bold} %{shortfile:-33s} %{shortfunc:-25s}%{color:reset} %{message}`
} else if forceNoColor {
stringFormat = `[%{level}] %{time:15:04:05} %{message}`
}
var format = logging.MustStringFormatter(stringFormat)
var backend = logging.AddModuleLevel(
logging.NewBackendFormatter(logging.NewLogBackend(os.Stderr, "", 0), format))
if verbose {
backend.SetLevel(logging.DEBUG, "")
} else {
backend.SetLevel(logging.WARNING, "")
}
backend.SetLevel(level, "")
logging.SetBackend(backend)
yqlib.InitExpressionParser()
@@ -58,6 +99,7 @@ yq -P sample.json
}
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose mode")
rootCmd.PersistentFlags().BoolVarP(&printNodeInfo, "debug-node-info", "", false, "debug node info")
rootCmd.PersistentFlags().BoolVarP(&outputToJSON, "tojson", "j", false, "(deprecated) output as json. Set indent to 0 to print json in one line.")
err := rootCmd.PersistentFlags().MarkDeprecated("tojson", "please use -o=json instead")
@@ -65,28 +107,76 @@ 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", "auto", fmt.Sprintf("[auto|a|%v] output format type.", yqlib.GetAvailableOutputFormatString()))
var outputCompletions = []string{"auto"}
for _, formats := range yqlib.GetAvailableOutputFormats() {
outputCompletions = append(outputCompletions, formats.FormalName)
}
if err = rootCmd.RegisterFlagCompletionFunc("output-format", cobra.FixedCompletions(outputCompletions, cobra.ShellCompDirectiveNoFileComp)); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&inputFormat, "input-format", "p", "auto", fmt.Sprintf("[auto|a|%v] parse format for input.", yqlib.GetAvailableInputFormatString()))
var inputCompletions = []string{"auto"}
for _, formats := range yqlib.GetAvailableInputFormats() {
inputCompletions = append(inputCompletions, formats.FormalName)
}
if err = rootCmd.RegisterFlagCompletionFunc("input-format", cobra.FixedCompletions(inputCompletions, cobra.ShellCompDirectiveNoFileComp)); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.AttributePrefix, "xml-attribute-prefix", yqlib.ConfiguredXMLPreferences.AttributePrefix, "prefix for xml attributes")
if err = rootCmd.RegisterFlagCompletionFunc("xml-attribute-prefix", cobra.NoFileCompletions); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.ContentName, "xml-content-name", yqlib.ConfiguredXMLPreferences.ContentName, "name for xml content (if no attribute name is present).")
if err = rootCmd.RegisterFlagCompletionFunc("xml-content-name", cobra.NoFileCompletions); err != nil {
panic(err)
}
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\"?>)")
if err = rootCmd.RegisterFlagCompletionFunc("xml-proc-inst-prefix", cobra.NoFileCompletions); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredXMLPreferences.DirectiveName, "xml-directive-name", yqlib.ConfiguredXMLPreferences.DirectiveName, "name for xml directives (e.g. <!DOCTYPE thing cat>)")
if err = rootCmd.RegisterFlagCompletionFunc("xml-directive-name", cobra.NoFileCompletions); err != nil {
panic(err)
}
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().BoolVar(&yqlib.ConfiguredCsvPreferences.AutoParse, "csv-auto-parse", yqlib.ConfiguredCsvPreferences.AutoParse, "parse CSV YAML/JSON values")
rootCmd.PersistentFlags().Var(newRuneVar(&yqlib.ConfiguredCsvPreferences.Separator), "csv-separator", "CSV Separator character")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredTsvPreferences.AutoParse, "tsv-auto-parse", yqlib.ConfiguredTsvPreferences.AutoParse, "parse TSV YAML/JSON values")
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocPrefix, "lua-prefix", yqlib.ConfiguredLuaPreferences.DocPrefix, "prefix")
if err = rootCmd.RegisterFlagCompletionFunc("lua-prefix", cobra.NoFileCompletions); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVar(&yqlib.ConfiguredLuaPreferences.DocSuffix, "lua-suffix", yqlib.ConfiguredLuaPreferences.DocSuffix, "suffix")
if err = rootCmd.RegisterFlagCompletionFunc("lua-suffix", cobra.NoFileCompletions); err != nil {
panic(err)
}
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.ConfiguredPropertiesPreferences.KeyValueSeparator, "properties-separator", yqlib.ConfiguredPropertiesPreferences.KeyValueSeparator, "separator to use between keys and values")
rootCmd.PersistentFlags().BoolVar(&yqlib.ConfiguredPropertiesPreferences.UseArrayBrackets, "properties-array-brackets", yqlib.ConfiguredPropertiesPreferences.UseArrayBrackets, "use [x] in array paths (e.g. for SpringBoot)")
rootCmd.PersistentFlags().BoolVar(&yqlib.StringInterpolationEnabled, "string-interpolation", yqlib.StringInterpolationEnabled, "Toggles strings interpolation of \\(exp)")
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")
if err = rootCmd.RegisterFlagCompletionFunc("indent", cobra.NoFileCompletions); err != nil {
panic(err)
}
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")
@@ -97,15 +187,31 @@ yq -P sample.json
rootCmd.PersistentFlags().BoolVarP(&exitStatus, "exit-status", "e", false, "set exit status if there are no matches or null or false is returned")
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", forceNoColor, "force print with no colors")
rootCmd.PersistentFlags().StringVarP(&frontMatter, "front-matter", "f", "", "(extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact")
if err = rootCmd.RegisterFlagCompletionFunc("front-matter", cobra.FixedCompletions([]string{"extract", "process"}, cobra.ShellCompDirectiveNoFileComp)); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&forceExpression, "expression", "", "", "forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file.")
if err = rootCmd.RegisterFlagCompletionFunc("expression", cobra.NoFileCompletions); err != nil {
panic(err)
}
rootCmd.PersistentFlags().BoolVarP(&yqlib.ConfiguredYamlPreferences.LeadingContentPreProcessing, "header-preprocess", "", true, "Slurp any header comments and separators before processing expression.")
rootCmd.PersistentFlags().BoolVarP(&yqlib.ConfiguredYamlPreferences.FixMergeAnchorToSpec, "yaml-fix-merge-anchor-to-spec", "", false, "Fix merge anchor to match YAML spec. Will default to true in late 2025")
rootCmd.PersistentFlags().StringVarP(&splitFileExp, "split-exp", "s", "", "print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter.")
rootCmd.PersistentFlags().StringVarP(&splitFileExp, "split-exp", "s", "", "print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter. The necessary directories will be created.")
if err = rootCmd.RegisterFlagCompletionFunc("split-exp", cobra.NoFileCompletions); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&splitFileExpFile, "split-exp-file", "", "", "Use a file to specify the split-exp expression.")
if err = rootCmd.MarkPersistentFlagFilename("split-exp-file"); err != nil {
panic(err)
}
rootCmd.PersistentFlags().StringVarP(&expressionFile, "from-file", "", "", "Load expression from specified file.")
if err = rootCmd.MarkPersistentFlagFilename("from-file"); err != nil {
panic(err)
}
rootCmd.AddCommand(
createEvaluateSequenceCommand(),
+116 -92
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"io"
"os"
"strings"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"github.com/spf13/cobra"
@@ -17,55 +18,103 @@ func isAutomaticOutputFormat() bool {
func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
cmd.SilenceUsage = true
fileInfo, _ := os.Stdout.Stat()
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
setupColors()
expression, args, err := processArgs(args)
if err != nil {
return "", nil, err
}
if err := loadSplitFileExpression(); err != nil {
return "", nil, err
}
handleBackwardsCompatibility()
if err := validateCommandFlags(args); err != nil {
return "", nil, err
}
if err := configureFormats(args); err != nil {
return "", nil, err
}
configureUnwrapScalar()
return expression, args, nil
}
func setupColors() {
fileInfo, _ := os.Stdout.Stat()
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true
}
}
func loadSplitFileExpression() error {
if splitFileExpFile != "" {
splitExpressionBytes, err := os.ReadFile(splitFileExpFile)
if err != nil {
return "", nil, err
return err
}
splitFileExp = string(splitExpressionBytes)
}
return nil
}
func handleBackwardsCompatibility() {
// backwards compatibility
if outputToJSON {
outputFormat = "json"
}
}
func validateCommandFlags(args []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 fmt.Errorf("write in place flag only applicable when giving an expression and at least one file")
}
if frontMatter != "" && len(args) == 0 {
return "", nil, fmt.Errorf("front matter flag only applicable when giving an expression and at least one file")
return fmt.Errorf("front matter flag only applicable when giving an expression and at least one file")
}
if writeInplace && splitFileExp != "" {
return "", nil, fmt.Errorf("write in place cannot be used with split file")
return fmt.Errorf("write in place cannot be used with split file")
}
if nullInput && len(args) > 0 {
return "", nil, fmt.Errorf("cannot pass files in when using null-input flag")
return fmt.Errorf("cannot pass files in when using null-input flag")
}
return nil
}
func configureFormats(args []string) error {
inputFilename := ""
if len(args) > 0 {
inputFilename = args[0]
}
if err := configureInputFormat(inputFilename); err != nil {
return err
}
if err := configureOutputFormat(); err != nil {
return err
}
yqlib.GetLogger().Debug("Using input format %v", inputFormat)
yqlib.GetLogger().Debug("Using output format %v", outputFormat)
return nil
}
func configureInputFormat(inputFilename string) error {
if inputFormat == "" || inputFormat == "auto" || inputFormat == "a" {
inputFormat = yqlib.FormatStringFromFilename(inputFilename)
inputFormat = yqlib.FormatFromFilename(inputFilename)
_, err := yqlib.InputFormatFromString(inputFormat)
_, err := yqlib.FormatFromString(inputFormat)
if err != nil {
// unknown file type, default to yaml
yqlib.GetLogger().Debug("Unknown file format extension '%v', defaulting to yaml", inputFormat)
@@ -74,10 +123,6 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
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() {
@@ -85,74 +130,50 @@ func initCommand(cmd *cobra.Command, args []string) (string, []string, error) {
// before this was introduced, `yq -pcsv things.csv`
// would produce *yaml* output.
//
outputFormat = yqlib.FormatFromFilename(inputFilename)
outputFormat = yqlib.FormatStringFromFilename(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"
}
return nil
}
outputFormatType, err := yqlib.OutputFormatFromString(outputFormat)
func configureOutputFormat() error {
outputFormatType, err := yqlib.FormatFromString(outputFormat)
if err != nil {
return "", nil, err
return err
}
yqlib.GetLogger().Debug("Using input format %v", inputFormat)
yqlib.GetLogger().Debug("Using output format %v", outputFormat)
if outputFormatType == yqlib.YamlOutputFormat ||
outputFormatType == yqlib.PropsOutputFormat {
if outputFormatType == yqlib.YamlFormat ||
outputFormatType == yqlib.PropertiesFormat {
unwrapScalar = true
}
return nil
}
func configureUnwrapScalar() {
if unwrapScalarFlag.IsExplicitlySet() {
unwrapScalar = unwrapScalarFlag.IsSet()
}
//copy preference form global setting
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
return expression, args, nil
}
func configureDecoder(evaluateTogether bool) (yqlib.Decoder, error) {
yqlibInputFormat, err := yqlib.InputFormatFromString(inputFormat)
format, err := yqlib.FormatFromString(inputFormat)
if err != nil {
return nil, err
}
yqlibDecoder, err := createDecoder(yqlibInputFormat, evaluateTogether)
yqlib.ConfiguredYamlPreferences.EvaluateTogether = evaluateTogether
yqlibDecoder := format.DecoderFactory()
if yqlibDecoder == nil {
return nil, fmt.Errorf("no support for %s input format", inputFormat)
}
return yqlibDecoder, err
return yqlibDecoder, nil
}
func createDecoder(format yqlib.InputFormat, evaluateTogether bool) (yqlib.Decoder, error) {
switch format {
case yqlib.LuaInputFormat:
return yqlib.NewLuaDecoder(yqlib.ConfiguredLuaPreferences), nil
case yqlib.XMLInputFormat:
return yqlib.NewXMLDecoder(yqlib.ConfiguredXMLPreferences), nil
case yqlib.PropertiesInputFormat:
return yqlib.NewPropertiesDecoder(), nil
case yqlib.JsonInputFormat:
return yqlib.NewJSONDecoder(), nil
case yqlib.CSVObjectInputFormat:
return yqlib.NewCSVObjectDecoder(','), nil
case yqlib.TSVObjectInputFormat:
return yqlib.NewCSVObjectDecoder('\t'), nil
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)
}
func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yqlib.PrinterWriter, error) {
func configurePrinterWriter(format *yqlib.Format, out io.Writer) (yqlib.PrinterWriter, error) {
var printerWriter yqlib.PrinterWriter
@@ -170,39 +191,29 @@ func configurePrinterWriter(format yqlib.PrinterOutputFormat, out io.Writer) (yq
}
func configureEncoder() (yqlib.Encoder, error) {
yqlibOutputFormat, err := yqlib.OutputFormatFromString(outputFormat)
yqlibOutputFormat, err := yqlib.FormatFromString(outputFormat)
if err != nil {
return nil, err
}
yqlibEncoder, err := createEncoder(yqlibOutputFormat)
if yqlibEncoder == nil {
yqlib.ConfiguredXMLPreferences.Indent = indent
yqlib.ConfiguredYamlPreferences.Indent = indent
yqlib.ConfiguredJSONPreferences.Indent = indent
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredPropertiesPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredJSONPreferences.UnwrapScalar = unwrapScalar
yqlib.ConfiguredYamlPreferences.ColorsEnabled = colorsEnabled
yqlib.ConfiguredJSONPreferences.ColorsEnabled = colorsEnabled
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
encoder := yqlibOutputFormat.EncoderFactory()
if encoder == nil {
return nil, fmt.Errorf("no support for %s output format", outputFormat)
}
return yqlibEncoder, err
}
func createEncoder(format yqlib.PrinterOutputFormat) (yqlib.Encoder, error) {
switch format {
case yqlib.JSONOutputFormat:
return yqlib.NewJSONEncoder(indent, colorsEnabled, unwrapScalar), nil
case yqlib.PropsOutputFormat:
return yqlib.NewPropertiesEncoder(unwrapScalar), nil
case yqlib.CSVOutputFormat:
return yqlib.NewCsvEncoder(','), nil
case yqlib.TSVOutputFormat:
return yqlib.NewCsvEncoder('\t'), nil
case yqlib.YamlOutputFormat:
return yqlib.NewYamlEncoder(indent, colorsEnabled, yqlib.ConfiguredYamlPreferences), nil
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 nil, fmt.Errorf("invalid encoder: %v", format)
return encoder, err
}
// this is a hack to enable backwards compatibility with githubactions (which pipe /dev/null into everything)
@@ -226,8 +237,11 @@ func maybeFile(str string) bool {
}
func processStdInArgs(args []string) []string {
stat, _ := os.Stdin.Stat()
pipingStdin := (stat.Mode() & os.ModeCharDevice) == 0
stat, err := os.Stdin.Stat()
if err != nil {
yqlib.GetLogger().Debugf("error getting stdin: %v", err)
}
pipingStdin := stat != nil && (stat.Mode()&os.ModeCharDevice) == 0
// if we've been given a file, don't automatically
// read from stdin.
@@ -251,15 +265,25 @@ func processStdInArgs(args []string) []string {
func processArgs(originalArgs []string) (string, []string, error) {
expression := forceExpression
args := processStdInArgs(originalArgs)
maybeFirstArgIsAFile := len(args) > 0 && maybeFile(args[0])
if expressionFile == "" && maybeFirstArgIsAFile && strings.HasSuffix(args[0], ".yq") {
// lets check if an expression file was given
yqlib.GetLogger().Debug("Assuming arg %v is an expression file", args[0])
expressionFile = args[0]
args = args[1:]
}
if expressionFile != "" {
expressionBytes, err := os.ReadFile(expressionFile)
if err != nil {
return "", nil, err
}
expression = string(expressionBytes)
//replace \r\n (windows) with good ol' unix file endings.
expression = strings.ReplaceAll(string(expressionBytes), "\r\n", "\n")
}
args := processStdInArgs(originalArgs)
yqlib.GetLogger().Debugf("processed args: %v", args)
if expression == "" && len(args) > 0 && args[0] != "-" && !maybeFile(args[0]) {
yqlib.GetLogger().Debug("assuming expression is '%v'", args[0])
+1435
View File
File diff suppressed because it is too large Load Diff
+2 -2
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 = "v4.46.1"
// 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
@@ -45,5 +45,5 @@ func getHumanVersion() string {
}
// Strip off any single quotes added by the git information.
return strings.Replace(version, "'", "", -1)
return strings.ReplaceAll(version, "'", "")
}
-210
View File
@@ -1,210 +0,0 @@
yq (4.16.2) focal; urgency=medium
* Fixed with semicolon space issue
* Updating with documentation
* Added STDIN example to the top
* minor readme cleanup
* Help text tweak
* Fixed docker timeout - simplify docker builds
* New release with docker build fixes
* Updating to go 1.17 to fix CVE #944
* Fix a typo in root.go
* Skip the tests if the nocheck Debian build option is specified
* Fixed select bug (#958)
* Sped up explode operator
* Slight performance improvement to context.ChildContext
* Speed up multiply
* Update README with recently added / changed options
* Make deepMatch report in linear time
* Removed leadingContentPreProcessing flag - header preprocessing is stable
* Revert "Removed leadingContentPreProcessing flag - header preprocessing is stable"
* Keep flag, it is needed in corner cases
* Updated Readme
* Man page
* Fixed expression parsing bug #970
* Bumping go-lang, docker versions
* Added test release flow
* Updated github action release to generate man page
* Bumping version
* Removing no longer needed github action
* Added decoder op
* Fixed newline handling when decoding/encoding
* Fixed newline handling in encoder/decoder
* Can specify indent in encode ops
* Added group_by operator
* Added flatten operator
* Fixed flatten error message
* Improving docs
* Split printer
* Refactored command logic
* Fix JSON encoding removing null #985
* Fixed acceptance tests
* gitbook
* Update document generation script
* Updating README
* Updating release instructions
* github action no longer uses data1.yml
* Create dependabot.yml
* Bump actions/create-release from 1.0.0 to 1.1.4
* Bump actions/setup-go from 1 to 2.1.4
* Bump github.com/goccy/go-yaml from 1.8.9 to 1.9.4
* Bump github.com/jinzhu/copier from 0.2.8 to 0.3.2
* Bump github.com/fatih/color from 1.10.0 to 1.13.0
* Bump github.com/spf13/cobra from 1.1.3 to 1.2.1
* Update dependabot.yml
* Update go.yml
* add build check to PRs
* Include secure as part of build process
* Fixing bad label in github action
* fixed printer test
* remove leading content indicator
* Fixed header preprocessing!
* lint : define golangci configuration file
* Update check.sh
* Load file acceptance test
* Minor improvement on handling front matter
* Improved load doc
* feature: detect MANPATh and install there
* Update install-man-page.sh
* simplify prod stage, move version label to action
* add labels, quote some values
* enable errorlint linter
* Added errorlint to devtools
* Added key operator
* Added more tests
* Fixing comments
* Attempt to fix golint problem
* Include version query for tools
* Clean up errored file?
* enable misspell linter
* updated readme
* update Golangci version to v1.43.0
* gci linter
* Better merge array by key example
* Added credit for merge by array example
* Better formatting of merge arrays example
* Better merge example
* Add accessor for the yq logger instance (#1013)
* Fixed collect op when working with multiple nodes
* Added map, map_values
* Add support for Podman as well as Docker (#1026)
* Bump github.com/jinzhu/copier from 0.3.2 to 0.3.4 (#1027)
* Added csv, tsv output formats
* Added encoder tests
* Cleanup test
* Fixed docker permission issue #1014
* Recording release notes for next release
* Assignment op no longer clobbers anchor (#1029)
* Added sort_by operator
* Improved error message
* Improved tips and tricks
* Report while filename failed to parse #1030
* Added script for extracting checksums
* Improved extract-checksum.sh
* Bump github.com/spf13/cobra from 1.2.1 to 1.3.0 (#1039)
* enable more linters (#1043)
* Bump Golang compiler #1037
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 21 Dec 2021 09:41:44 +0000
yq (4.13.0) focal; urgency=medium
* New `with` operator for making multiple changes to a given path
* New `contains` operator, works like the `jq` equivalent
* Subtract operator now supports subtracting elements from arrays!
* Fixed Swapping values using variables #934
* Github Action now properly supports multiline output #936, thanks @pjxiao
* Fixed missing closing bracket validation #932
* Fix processing of hex numbers #929
* Fixed alternative and union operator issues #930
* Can now convert yaml to properties properties format (`-o=props`), See [docs](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties) for more info.
* Fixed document header/footer comment handling when merging (https://github.com/mikefarah/yq/issues/919)
* pretty print yaml 1.1 compatibility (https://github.com/mikefarah/yq/issues/914)
-- Roberto Mier Escandon <rmescandon@gmail.com> Thu, 16 Sep 2021 20:58:30 +0200
yq (4.9.6) focal; urgency=medium
* Added darwin/arm64 build, thanks @alecthomas
* Incremented docker alpine base version, thanks @da6d6i7-bronga
* Bug fix: multiline expression
* Bug fix: special character
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 29 Jun 2021 21:32:14 +0200
yq (3.3.2) focal; urgency=medium
* Bug fix: existStatus bug (#459)
* Automatically makes a os temp directory if it does not exist (#461)
-- Roberto Mier Escandon <rmescandon@gmail.com> Fri, 07 Aug 2020 18:53:01 +0200
yq (3.3-0) focal; urgency=medium
* You can control string styles (quotes) using the new --style flag
* String values now always have quotes when outputting to json
* Negative array indices now traverse the array backwards
* Added a --stripComments flag to print yaml without any comments
* Bumped go to version 1.14
-- Roberto Mier Escandon <rmescandon@gmail.com> Thu, 30 Apr 2020 20:45:44 +0200
yq (3.1-2) eoan; urgency=medium
* Bug fix: yq 3 was removing empty inline-style objects and arrays (#355)
* Bug fix: Merge option returned different output when switching order of
merging files(#347)
* Bug fix: Add new object to existing array object was failing in 3.1.1 (#361)
* Bug fix: yq 3 empty keys did not allow merging of values (#356)
* Bug fix: keys quoted during merge (#363)
* Bug fix: Correct length with wc -l (#362)
* Bug fix: Write to empty document removed path (#359)
-- Roberto Mier Escandon <rmescandon@gmail.com> Mon, 24 Feb 2020 20:31:58 +0100
yq (3.1-1) eoan; urgency=medium
* Keeps yaml comments and formatting, can specify yaml tags when updating.
* Handles anchors
* Can print out matching paths and values when splatting
* JSON output works for all commands
* Yaml files with multiple documents are printed out as one JSON
document per line.
* Deep splat (**) to match arbitrary paths
* Update scripts file format has changed to be more powerful
* Reading and splatting, matching results are printed once per line
* Bugfixing
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 11 Feb 2020 22:18:24 +0100
yq (2.2-1) bionic; urgency=medium
* Added Windows support for the "--inplace" command flag
* Prefix now supports arrays
* Add prefix command
* Bump Alpine version to 3.8
* Improved docker build process
* Lint fixes
* Build support for all linux architectures supported by gox
-- Roberto Mier Escandon <rmescandon@gmail.com> Sat, 19 Jan 2019 15:50:47 +0100
yq (2.1-0) bionic; urgency=medium
* Ability to read multiple documents in a single file
* Ability to append list items instead of overwriting
-- Roberto Mier Escandón <rmescandon@gmail.com> Tue, 10 Jul 2018 14:02:42 +0200
yq (2.0-0) bionic; urgency=medium
* Release 2.0.0
-- Roberto Mier Escandón <rmescandon@gmail.com> Wed, 20 Jun 2018 10:29:53 +0200
yq (1.15-0) bionic; urgency=medium
* Release 1.15
-- Roberto Mier Escandón <rmescandon@gmail.com> Wed, 06 Jun 2018 11:32:03 +0200
-1
View File
@@ -1 +0,0 @@
10
-22
View File
@@ -1,22 +0,0 @@
Source: yq
Section: devel
Priority: optional
Maintainer: Roberto Mier Escandón <rmescandon@gmail.com>
Build-Depends: debhelper (>=10),
golang-1.17-go,
pandoc,
rsync
Standards-Version: 4.1.4
Homepage: https://github.com/mikefarah/yq.git
Vcs-Browser: https://github.com/mikefarah/yq.git
Vcs-Git: https://github.com/mikefarah/yq.git
XS-Go-Import-Path: github.com/mikefarah/yq
XSBC-Original-Maintainer: Roberto Mier Escandón <rmescandon@gmail.com>
Package: yq
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: lightweight and portable command-line YAML processor
.
The aim of the project is to be the
[jq](https://github.com/stedolan/jq) or sed of yaml files.
-24
View File
@@ -1,24 +0,0 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: yq
Source: https://github.com/mikefarah/yq.git
Files: *
Copyright: 2017 Mike Farah
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-2
View File
@@ -1,2 +0,0 @@
[DEFAULT]
pristine-tar = True
-74
View File
@@ -1,74 +0,0 @@
#!/usr/bin/make -f
#
# Copyright (C) 2018-2021 Roberto Mier Escandón <rmescandon@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
PROJECT := yq
OWNER := mikefarah
REPO := github.com
export DH_OPTIONS
export DH_GOPKG := ${REPO}/${OWNER}/${PROJECT}
export GOROOT := /usr/local/go
export GOPATH := ${CURDIR}/_build
export GOBIN := ${GOPATH}/bin
export PATH := ${GOROOT}/bin:${GOBIN}:${PATH}
export GOCACHE := /tmp/gocache
export GOFLAGS := -mod=vendor
export GO111MODULE := on
SRCDIR := ${GOPATH}/src/${DH_GOPKG}
DESTDIR := ${CURDIR}/debian/${PROJECT}
BINDIR := /usr/bin
MANDIR := /usr/share/man/man1/
ASSETSDIR := /usr/share/${PROJECT}
%:
dh $@
override_dh_auto_build:
mkdir -p ${SRCDIR}
mkdir -p ${GOBIN}
# copy project to local srcdir to build from there
rsync -avz --progress --exclude=_build --exclude=debian --exclude=tmp. --exclude=go.mod --exclude=docs . $(SRCDIR)
# build go code
( \
cd ${SRCDIR} && \
go install -buildmode=pie ./... \
)
# build man page
( \
cd ${SRCDIR} && \
./scripts/generate-man-page-md.sh && \
./scripts/generate-man-page.sh \
)
override_dh_auto_test:
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
(cd ${SRCDIR} && go test -v ./...)
endif
override_dh_auto_install:
cp ${GOBIN}/yq ${DESTDIR}/${BINDIR}
cp -f ${SRCDIR}/LICENSE ${DESTDIR}/${ASSETSDIR}
chmod a+x ${DESTDIR}/${BINDIR}/yq
# man
mkdir -p "${DESTDIR}"/"${MANDIR}"
cp "${SRCDIR}"/yq.1 "${DESTDIR}"/"${MANDIR}" \
override_dh_auto_clean:
dh_clean
rm -rf ${CURDIR}/_build
-1
View File
@@ -1 +0,0 @@
3.0 (native)
-3
View File
@@ -1,3 +0,0 @@
usr/bin
usr/share/yq
usr/share/man/man1
+8 -1
View File
@@ -1 +1,8 @@
["foobar", "foobaz", "blarp"]
# 001
---
abc: # 001
- 1 # one
- 2 # two
---
def # 002
+5
View File
@@ -0,0 +1,5 @@
#! yq
.[] |(
( select(kind == "scalar") | key + "='" + . + "'"),
( select(kind == "seq") | key + "=(" + (map("'" + . + "'") | join(",")) + ")")
)
+1 -1
View File
@@ -1,6 +1,6 @@
---
a: apple
b: bannana
b: banana
---
hello there
apples: great
+1 -1
View File
@@ -1 +1 @@
<cat>3</cat>
<zoo><thing><frog>boing</frog></thing></zoo>
+14
View File
@@ -0,0 +1,14 @@
; This is a INI document
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
db_host = "localhost"
db_port = 5432
db_user = "postgres"
db_password = ""
db_name = "postgres"
+2 -11
View File
@@ -1,11 +1,2 @@
# Some doc
a: true
b:
c: 2
d: [3, 4, 5]
e:
- name: fred
value: 3
- name: sam
value: 4
# things
a: apple
+8
View File
@@ -0,0 +1,8 @@
; This is a INI document
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
enabled = true
ip = "10.0.0.1"
role = "frontend"
treads = 4
+22 -20
View File
@@ -1,33 +1,35 @@
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.3.0
github.com/a8m/envsubst v1.4.3
github.com/alecthomas/participle/v2 v2.1.4
github.com/alecthomas/repr v0.4.0
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/elliotchance/orderedmap v1.8.0
github.com/fatih/color v1.18.0
github.com/go-ini/ini v1.67.0
github.com/goccy/go-json v0.10.5
github.com/goccy/go-yaml v1.18.0
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/magiconair/properties v1.8.10
github.com/pelletier/go-toml/v2 v2.2.4
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/yuin/gopher-lua v1.1.0
golang.org/x/net v0.17.0
golang.org/x/text v0.13.0
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/yuin/gopher-lua v1.1.1
go.yaml.in/yaml/v3 v3.0.4
golang.org/x/net v0.41.0
golang.org/x/text v0.27.0
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.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.33.0 // indirect
)
go 1.20
go 1.24
toolchain go1.24.1
+45 -48
View File
@@ -1,66 +1,63 @@
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.3.0 h1:NeYzUPfjjlqHY4KtzgKJiWd6sVq2eNUPTi34PiFGjY8=
github.com/alecthomas/repr v0.3.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY=
github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U=
github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
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/elliotchance/orderedmap v1.8.0 h1:TrOREecvh3JbS+NCgwposXG5ZTFHtEsQiCGOhPElnMw=
github.com/elliotchance/orderedmap v1.8.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
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/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
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/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/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.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=
github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE=
github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.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/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
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=
+4 -12
View File
@@ -2,8 +2,6 @@ package yqlib
import (
"container/list"
yaml "gopkg.in/yaml.v3"
)
// A yaml expression evaluator that runs the expression once against all files/nodes in memory.
@@ -11,7 +9,7 @@ type Evaluator interface {
EvaluateFiles(expression string, filenames []string, printer Printer, decoder Decoder) error
// EvaluateNodes takes an expression and one or more yaml nodes, returning a list of matching candidate nodes
EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error)
EvaluateNodes(expression string, nodes ...*CandidateNode) (*list.List, error)
// EvaluateCandidateNodes takes an expression and list of candidate nodes, returning a list of matching candidate nodes
EvaluateCandidateNodes(expression string, inputCandidateNodes *list.List) (*list.List, error)
@@ -26,10 +24,10 @@ func NewAllAtOnceEvaluator() Evaluator {
return &allAtOnceEvaluator{treeNavigator: NewDataTreeNavigator()}
}
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*yaml.Node) (*list.List, error) {
func (e *allAtOnceEvaluator) EvaluateNodes(expression string, nodes ...*CandidateNode) (*list.List, error) {
inputCandidates := list.New()
for _, node := range nodes {
inputCandidates.PushBack(&CandidateNode{Node: node})
inputCandidates.PushBack(node)
}
return e.EvaluateCandidateNodes(expression, inputCandidates)
}
@@ -65,13 +63,7 @@ func (e *allAtOnceEvaluator) EvaluateFiles(expression string, filenames []string
}
if allDocuments.Len() == 0 {
candidateNode := &CandidateNode{
Document: 0,
Filename: "",
Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}},
FileIndex: 0,
LeadingContent: "",
}
candidateNode := createScalarNode(nil, "")
allDocuments.PushBack(candidateNode)
}
+19 -3
View File
@@ -1,6 +1,8 @@
package yqlib
import (
"bufio"
"strings"
"testing"
"github.com/mikefarah/yq/v4/test"
@@ -18,7 +20,7 @@ var evaluateNodesScenario = []expressionScenario{
document: `a: hello`,
expression: `.`,
expected: []string{
"D0, P[], (doc)::a: hello\n",
"D0, P[], (!!map)::a: hello\n",
},
},
{
@@ -32,9 +34,23 @@ var evaluateNodesScenario = []expressionScenario{
func TestAllAtOnceEvaluateNodes(t *testing.T) {
var evaluator = NewAllAtOnceEvaluator()
// logging.SetLevel(logging.DEBUG, "")
for _, tt := range evaluateNodesScenario {
node := test.ParseData(tt.document)
list, _ := evaluator.EvaluateNodes(tt.expression, &node)
decoder := NewYamlDecoder(ConfiguredYamlPreferences)
reader := bufio.NewReader(strings.NewReader(tt.document))
err := decoder.Init(reader)
if err != nil {
t.Error(err)
return
}
candidateNode, errorReading := decoder.Decode()
if errorReading != nil {
t.Error(errorReading)
return
}
list, _ := evaluator.EvaluateNodes(tt.expression, candidateNode)
test.AssertResultComplex(t, tt.expected, resultsToString(t, list))
}
}
+452 -101
View File
@@ -3,51 +3,215 @@ package yqlib
import (
"container/list"
"fmt"
"strconv"
"strings"
"github.com/jinzhu/copier"
yaml "gopkg.in/yaml.v3"
)
type Kind uint32
const (
SequenceNode Kind = 1 << iota
MappingNode
ScalarNode
AliasNode
)
type Style uint32
const (
TaggedStyle Style = 1 << iota
DoubleQuotedStyle
SingleQuotedStyle
LiteralStyle
FoldedStyle
FlowStyle
)
func createStringScalarNode(stringValue string) *CandidateNode {
var node = &CandidateNode{Kind: ScalarNode}
node.Value = stringValue
node.Tag = "!!str"
return node
}
func createScalarNode(value interface{}, stringValue string) *CandidateNode {
var node = &CandidateNode{Kind: ScalarNode}
node.Value = stringValue
switch value.(type) {
case float32, float64:
node.Tag = "!!float"
case int, int64, int32:
node.Tag = "!!int"
case bool:
node.Tag = "!!bool"
case string:
node.Tag = "!!str"
case nil:
node.Tag = "!!null"
}
return node
}
type NodeInfo struct {
Kind string `yaml:"kind"`
Style string `yaml:"style,omitempty"`
Anchor string `yaml:"anchor,omitempty"`
Tag string `yaml:"tag,omitempty"`
HeadComment string `yaml:"headComment,omitempty"`
LineComment string `yaml:"lineComment,omitempty"`
FootComment string `yaml:"footComment,omitempty"`
Value string `yaml:"value,omitempty"`
Line int `yaml:"line,omitempty"`
Column int `yaml:"column,omitempty"`
Content []*NodeInfo `yaml:"content,omitempty"`
}
type CandidateNode struct {
Node *yaml.Node // the actual node
Kind Kind
Style Style
Tag string
Value string
Anchor string
Alias *CandidateNode
Content []*CandidateNode
HeadComment string
LineComment string
FootComment string
Parent *CandidateNode // parent node
Key *yaml.Node // node key, if this is a value from a map (or index in an array)
Key *CandidateNode // node key, if this is a value from a map (or index in an array)
LeadingContent string
TrailingContent string
LeadingContent string
Path []interface{} /// the path we took to get to this node
Document uint // the document index of this node
Filename string
FileIndex int
document uint // the document index of this node
filename string
Line int
Column int
fileIndex int
// when performing op against all nodes given, this will treat all the nodes as one
// (e.g. top level cross document merge). This property does not propagate to child nodes.
EvaluateTogether bool
IsMapKey bool
}
func (n *CandidateNode) CreateChild() *CandidateNode {
return &CandidateNode{
Parent: n,
}
}
func (n *CandidateNode) SetDocument(idx uint) {
n.document = idx
}
func (n *CandidateNode) GetDocument() uint {
// defer to parent
if n.Parent != nil {
return n.Parent.GetDocument()
}
return n.document
}
func (n *CandidateNode) SetFilename(name string) {
n.filename = name
}
func (n *CandidateNode) GetFilename() string {
if n.Parent != nil {
return n.Parent.GetFilename()
}
return n.filename
}
func (n *CandidateNode) SetFileIndex(idx int) {
n.fileIndex = idx
}
func (n *CandidateNode) GetFileIndex() int {
if n.Parent != nil {
return n.Parent.GetFileIndex()
}
return n.fileIndex
}
func (n *CandidateNode) GetKey() string {
keyPrefix := ""
if n.IsMapKey {
keyPrefix = "key-"
keyPrefix = fmt.Sprintf("key-%v-", n.Value)
}
return fmt.Sprintf("%v%v - %v", keyPrefix, n.Document, n.Path)
key := ""
if n.Key != nil {
key = n.Key.Value
}
return fmt.Sprintf("%v%v - %v", keyPrefix, n.GetDocument(), key)
}
func (n *CandidateNode) GetNiceTag() string {
return unwrapDoc(n.Node).Tag
func (n *CandidateNode) getParsedKey() interface{} {
if n.IsMapKey {
return n.Value
}
if n.Key == nil {
return nil
}
if n.Key.Tag == "!!str" {
return n.Key.Value
}
index, err := parseInt(n.Key.Value)
if err != nil {
return n.Key.Value
}
return index
}
func (n *CandidateNode) FilterMapContentByKey(keyPredicate func(*CandidateNode) bool) []*CandidateNode {
var result []*CandidateNode
for index := 0; index < len(n.Content); index = index + 2 {
keyNode := n.Content[index]
valueNode := n.Content[index+1]
if keyPredicate(keyNode) {
result = append(result, keyNode, valueNode)
}
}
return result
}
func (n *CandidateNode) GetPath() []interface{} {
key := n.getParsedKey()
if n.Parent != nil && key != nil {
return append(n.Parent.GetPath(), key)
}
if key != nil {
return []interface{}{key}
}
return make([]interface{}, 0)
}
func (n *CandidateNode) GetNicePath() string {
if n.Path != nil && len(n.Path) >= 0 {
pathStr := make([]string, len(n.Path))
for i, v := range n.Path {
pathStr[i] = fmt.Sprintf("%v", v)
var sb strings.Builder
path := n.GetPath()
for i, element := range path {
elementStr := fmt.Sprintf("%v", element)
switch element.(type) {
case int:
sb.WriteString("[" + elementStr + "]")
default:
if i == 0 {
sb.WriteString(elementStr)
} else if strings.ContainsRune(elementStr, '.') {
sb.WriteString("[" + elementStr + "]")
} else {
sb.WriteString("." + elementStr)
}
}
return strings.Join(pathStr, ".")
}
return ""
return sb.String()
}
func (n *CandidateNode) AsList() *list.List {
@@ -56,134 +220,321 @@ func (n *CandidateNode) AsList() *list.List {
return elMap
}
func (n *CandidateNode) CreateChildInMap(key *yaml.Node, node *yaml.Node) *CandidateNode {
var value interface{}
if key != nil {
value = key.Value
func (n *CandidateNode) SetParent(parent *CandidateNode) {
n.Parent = parent
}
type ValueVisitor func(*CandidateNode) error
func (n *CandidateNode) VisitValues(visitor ValueVisitor) error {
switch n.Kind {
case MappingNode:
for i := 1; i < len(n.Content); i = i + 2 {
if err := visitor(n.Content[i]); err != nil {
return err
}
}
case SequenceNode:
for i := 0; i < len(n.Content); i = i + 1 {
if err := visitor(n.Content[i]); err != nil {
return err
}
}
}
return &CandidateNode{
Node: node,
Path: n.createChildPath(value),
Parent: n,
Key: key,
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
return nil
}
func (n *CandidateNode) CanVisitValues() bool {
return n.Kind == MappingNode || n.Kind == SequenceNode
}
func (n *CandidateNode) AddKeyValueChild(rawKey *CandidateNode, rawValue *CandidateNode) (*CandidateNode, *CandidateNode) {
key := rawKey.Copy()
key.SetParent(n)
key.IsMapKey = true
value := rawValue.Copy()
value.SetParent(n)
value.IsMapKey = false // force this, incase we are creating a value from a key
value.Key = key
n.Content = append(n.Content, key, value)
return key, value
}
func (n *CandidateNode) AddChild(rawChild *CandidateNode) {
value := rawChild.Copy()
value.SetParent(n)
value.IsMapKey = false
index := len(n.Content)
keyNode := createScalarNode(index, fmt.Sprintf("%v", index))
keyNode.SetParent(n)
value.Key = keyNode
n.Content = append(n.Content, value)
}
func (n *CandidateNode) AddChildren(children []*CandidateNode) {
if n.Kind == MappingNode {
for i := 0; i < len(children); i += 2 {
key := children[i]
value := children[i+1]
n.AddKeyValueChild(key, value)
}
} else {
for _, rawChild := range children {
n.AddChild(rawChild)
}
}
}
func (n *CandidateNode) CreateChildInArray(index int, node *yaml.Node) *CandidateNode {
return &CandidateNode{
Node: node,
Path: n.createChildPath(index),
Parent: n,
Key: &yaml.Node{Kind: yaml.ScalarNode, Value: fmt.Sprintf("%v", index), Tag: "!!int"},
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
func (n *CandidateNode) GetValueRep() (interface{}, error) {
log.Debugf("GetValueRep for %v value: %v", n.GetNicePath(), n.Value)
realTag := n.guessTagFromCustomType()
switch realTag {
case "!!int":
_, val, err := parseInt64(n.Value)
return val, err
case "!!float":
// need to test this
return strconv.ParseFloat(n.Value, 64)
case "!!bool":
return isTruthyNode(n), nil
case "!!null":
return nil, nil
}
return n.Value, nil
}
func (n *CandidateNode) CreateReplacement(node *yaml.Node) *CandidateNode {
return &CandidateNode{
Node: node,
Path: n.createChildPath(nil),
Parent: n.Parent,
Key: n.Key,
IsMapKey: n.IsMapKey,
Document: n.Document,
Filename: n.Filename,
FileIndex: n.FileIndex,
func (n *CandidateNode) guessTagFromCustomType() string {
if strings.HasPrefix(n.Tag, "!!") {
return n.Tag
} else if n.Value == "" {
log.Debug("guessTagFromCustomType: node has no value to guess the type with")
return n.Tag
}
dataBucket, errorReading := parseSnippet(n.Value)
if errorReading != nil {
log.Debug("guessTagFromCustomType: could not guess underlying tag type %v", errorReading)
return n.Tag
}
guessedTag := dataBucket.Tag
log.Info("im guessing the tag %v is a %v", n.Tag, guessedTag)
return guessedTag
}
func (n *CandidateNode) CreateReplacementWithDocWrappers(node *yaml.Node) *CandidateNode {
replacement := n.CreateReplacement(node)
func (n *CandidateNode) CreateReplacement(kind Kind, tag string, value string) *CandidateNode {
node := &CandidateNode{
Kind: kind,
Tag: tag,
Value: value,
}
return n.CopyAsReplacement(node)
}
func (n *CandidateNode) CopyAsReplacement(replacement *CandidateNode) *CandidateNode {
newCopy := replacement.Copy()
newCopy.Parent = n.Parent
if n.IsMapKey {
newCopy.Key = n
} else {
newCopy.Key = n.Key
}
return newCopy
}
func (n *CandidateNode) CreateReplacementWithComments(kind Kind, tag string, style Style) *CandidateNode {
replacement := n.CreateReplacement(kind, tag, "")
replacement.LeadingContent = n.LeadingContent
replacement.TrailingContent = n.TrailingContent
replacement.HeadComment = n.HeadComment
replacement.LineComment = n.LineComment
replacement.FootComment = n.FootComment
replacement.Style = style
return replacement
}
func (n *CandidateNode) createChildPath(path interface{}) []interface{} {
if path == nil {
newPath := make([]interface{}, len(n.Path))
copy(newPath, n.Path)
return newPath
}
//don't use append as they may actually modify the path of the original node!
newPath := make([]interface{}, len(n.Path)+1)
copy(newPath, n.Path)
newPath[len(n.Path)] = path
return newPath
func (n *CandidateNode) Copy() *CandidateNode {
return n.doCopy(true)
}
func (n *CandidateNode) Copy() (*CandidateNode, error) {
clone := &CandidateNode{}
err := copier.Copy(clone, n)
if err != nil {
return nil, err
func (n *CandidateNode) CopyWithoutContent() *CandidateNode {
return n.doCopy(false)
}
func (n *CandidateNode) doCopy(cloneContent bool) *CandidateNode {
var content []*CandidateNode
var copyKey *CandidateNode
if n.Key != nil {
copyKey = n.Key.Copy()
}
clone.Node = deepClone(n.Node)
return clone, nil
clone := &CandidateNode{
Kind: n.Kind,
Style: n.Style,
Tag: n.Tag,
Value: n.Value,
Anchor: n.Anchor,
// ok not to clone this,
// as its a reference to somewhere else.
Alias: n.Alias,
Content: content,
HeadComment: n.HeadComment,
LineComment: n.LineComment,
FootComment: n.FootComment,
Parent: n.Parent,
Key: copyKey,
LeadingContent: n.LeadingContent,
document: n.document,
filename: n.filename,
fileIndex: n.fileIndex,
Line: n.Line,
Column: n.Column,
EvaluateTogether: n.EvaluateTogether,
IsMapKey: n.IsMapKey,
}
if cloneContent {
clone.AddChildren(n.Content)
}
return clone
}
// updates this candidate from the given candidate node
func (n *CandidateNode) UpdateFrom(other *CandidateNode, prefs assignPreferences) {
if n == other {
log.Debugf("UpdateFrom, no need to update from myself.")
return
}
// if this is an empty map or empty array, use the style of other node.
if (n.Node.Kind != yaml.ScalarNode && len(n.Node.Content) == 0) ||
if (n.Kind != ScalarNode && len(n.Content) == 0) ||
// if the tag has changed (e.g. from str to bool)
(guessTagFromCustomType(n.Node) != guessTagFromCustomType(other.Node)) {
n.Node.Style = other.Node.Style
(n.guessTagFromCustomType() != other.guessTagFromCustomType()) {
n.Style = other.Style
}
n.Node.Content = deepCloneContent(other.Node.Content)
n.Node.Kind = other.Node.Kind
n.Node.Value = other.Node.Value
n.Content = make([]*CandidateNode, 0)
n.Kind = other.Kind
n.AddChildren(other.Content)
n.Value = other.Value
n.UpdateAttributesFrom(other, prefs)
}
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode, prefs assignPreferences) {
log.Debug("UpdateAttributesFrom: n: %v other: %v", n.GetKey(), other.GetKey())
if n.Node.Kind != other.Node.Kind {
log.Debug("UpdateAttributesFrom: n: %v other: %v", NodeToString(n), NodeToString(other))
if n.Kind != other.Kind {
// clear out the contents when switching to a different type
// e.g. map to array
n.Node.Content = make([]*yaml.Node, 0)
n.Node.Value = ""
n.Content = make([]*CandidateNode, 0)
n.Value = ""
}
n.Node.Kind = other.Node.Kind
n.Kind = other.Kind
// don't clobber custom tags...
if prefs.ClobberCustomTags || strings.HasPrefix(n.Node.Tag, "!!") || n.Node.Tag == "" {
n.Node.Tag = other.Node.Tag
if prefs.ClobberCustomTags || strings.HasPrefix(n.Tag, "!!") || n.Tag == "" {
n.Tag = other.Tag
}
n.Node.Alias = other.Node.Alias
n.Alias = other.Alias
if !prefs.DontOverWriteAnchor {
n.Node.Anchor = other.Node.Anchor
n.Anchor = other.Anchor
}
// merge will pickup the style of the new thing
// when autocreating nodes
if n.Node.Style == 0 {
n.Node.Style = other.Node.Style
if n.Style == 0 {
n.Style = other.Style
}
if other.Node.FootComment != "" {
n.Node.FootComment = other.Node.FootComment
if other.FootComment != "" {
n.FootComment = other.FootComment
}
if other.TrailingContent != "" {
n.TrailingContent = other.TrailingContent
if other.HeadComment != "" {
n.HeadComment = other.HeadComment
}
if other.Node.HeadComment != "" {
n.Node.HeadComment = other.Node.HeadComment
}
if other.Node.LineComment != "" {
n.Node.LineComment = other.Node.LineComment
if other.LineComment != "" {
n.LineComment = other.LineComment
}
}
func (n *CandidateNode) ConvertToNodeInfo() *NodeInfo {
info := &NodeInfo{
Kind: kindToString(n.Kind),
Style: styleToString(n.Style),
Anchor: n.Anchor,
Tag: n.Tag,
HeadComment: n.HeadComment,
LineComment: n.LineComment,
FootComment: n.FootComment,
Value: n.Value,
Line: n.Line,
Column: n.Column,
}
if len(n.Content) > 0 {
info.Content = make([]*NodeInfo, len(n.Content))
for i, child := range n.Content {
info.Content[i] = child.ConvertToNodeInfo()
}
}
return info
}
// Helper functions to convert Kind and Style to string for NodeInfo
func kindToString(k Kind) string {
switch k {
case SequenceNode:
return "SequenceNode"
case MappingNode:
return "MappingNode"
case ScalarNode:
return "ScalarNode"
case AliasNode:
return "AliasNode"
default:
return "Unknown"
}
}
func styleToString(s Style) string {
var styles []string
if s&TaggedStyle != 0 {
styles = append(styles, "TaggedStyle")
}
if s&DoubleQuotedStyle != 0 {
styles = append(styles, "DoubleQuotedStyle")
}
if s&SingleQuotedStyle != 0 {
styles = append(styles, "SingleQuotedStyle")
}
if s&LiteralStyle != 0 {
styles = append(styles, "LiteralStyle")
}
if s&FoldedStyle != 0 {
styles = append(styles, "FoldedStyle")
}
if s&FlowStyle != 0 {
styles = append(styles, "FlowStyle")
}
return strings.Join(styles, ",")
}
+210
View File
@@ -0,0 +1,210 @@
package yqlib
import (
"fmt"
"strings"
yaml "github.com/goccy/go-yaml"
"github.com/goccy/go-yaml/ast"
goccyToken "github.com/goccy/go-yaml/token"
)
func (o *CandidateNode) goccyDecodeIntoChild(childNode ast.Node, cm yaml.CommentMap, anchorMap map[string]*CandidateNode) (*CandidateNode, error) {
newChild := o.CreateChild()
err := newChild.UnmarshalGoccyYAML(childNode, cm, anchorMap)
return newChild, err
}
func (o *CandidateNode) UnmarshalGoccyYAML(node ast.Node, cm yaml.CommentMap, anchorMap map[string]*CandidateNode) error {
log.Debugf("UnmarshalYAML %v", node)
log.Debugf("UnmarshalYAML %v", node.Type().String())
log.Debugf("UnmarshalYAML Node Value: %v", node.String())
log.Debugf("UnmarshalYAML Node GetComment: %v", node.GetComment())
if node.GetComment() != nil {
commentMapComments := cm[node.GetPath()]
for _, comment := range node.GetComment().Comments {
// need to use the comment map to find the position :/
log.Debugf("%v has a comment of [%v]", node.GetPath(), comment.Token.Value)
for _, commentMapComment := range commentMapComments {
commentMapValue := strings.Join(commentMapComment.Texts, "\n")
if commentMapValue == comment.Token.Value {
log.Debug("found a matching entry in comment map")
// we found the comment in the comment map,
// now we can process the position
switch commentMapComment.Position {
case yaml.CommentHeadPosition:
o.HeadComment = comment.String()
log.Debug("its a head comment %v", comment.String())
case yaml.CommentLinePosition:
o.LineComment = comment.String()
log.Debug("its a line comment %v", comment.String())
case yaml.CommentFootPosition:
o.FootComment = comment.String()
log.Debug("its a foot comment %v", comment.String())
}
}
}
}
}
o.Value = node.String()
o.Line = node.GetToken().Position.Line
o.Column = node.GetToken().Position.Column
switch node.Type() {
case ast.IntegerType:
o.Kind = ScalarNode
o.Tag = "!!int"
case ast.FloatType:
o.Kind = ScalarNode
o.Tag = "!!float"
case ast.BoolType:
o.Kind = ScalarNode
o.Tag = "!!bool"
case ast.NullType:
log.Debugf("its a null type with value %v", node.GetToken().Value)
o.Kind = ScalarNode
o.Tag = "!!null"
o.Value = node.GetToken().Value
if node.GetToken().Type == goccyToken.ImplicitNullType {
o.Value = ""
}
case ast.StringType:
o.Kind = ScalarNode
o.Tag = "!!str"
switch node.GetToken().Type {
case goccyToken.SingleQuoteType:
o.Style = SingleQuotedStyle
case goccyToken.DoubleQuoteType:
o.Style = DoubleQuotedStyle
}
o.Value = node.(*ast.StringNode).Value
log.Debugf("string value %v", node.(*ast.StringNode).Value)
case ast.LiteralType:
o.Kind = ScalarNode
o.Tag = "!!str"
o.Style = LiteralStyle
astLiteral := node.(*ast.LiteralNode)
log.Debugf("astLiteral.Start.Type %v", astLiteral.Start.Type)
if astLiteral.Start.Type == goccyToken.FoldedType {
log.Debugf("folded Type %v", astLiteral.Start.Type)
o.Style = FoldedStyle
}
log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Value)
log.Debug("start value: %v ", node.(*ast.LiteralNode).Start.Type)
// TODO: here I could put the original value with line breaks
// to solve the multiline > problem
o.Value = astLiteral.Value.Value
case ast.TagType:
if err := o.UnmarshalGoccyYAML(node.(*ast.TagNode).Value, cm, anchorMap); err != nil {
return err
}
o.Tag = node.(*ast.TagNode).Start.Value
case ast.MappingType:
log.Debugf("UnmarshalYAML - a mapping node")
o.Kind = MappingNode
o.Tag = "!!map"
mappingNode := node.(*ast.MappingNode)
if mappingNode.IsFlowStyle {
o.Style = FlowStyle
}
for _, mappingValueNode := range mappingNode.Values {
err := o.goccyProcessMappingValueNode(mappingValueNode, cm, anchorMap)
if err != nil {
return err
}
}
if mappingNode.FootComment != nil {
log.Debugf("mapping node has a foot comment of: %v", mappingNode.FootComment)
o.FootComment = mappingNode.FootComment.String()
}
case ast.MappingValueType:
log.Debugf("UnmarshalYAML - a mapping node")
o.Kind = MappingNode
o.Tag = "!!map"
mappingValueNode := node.(*ast.MappingValueNode)
err := o.goccyProcessMappingValueNode(mappingValueNode, cm, anchorMap)
if err != nil {
return err
}
case ast.SequenceType:
log.Debugf("UnmarshalYAML - a sequence node")
o.Kind = SequenceNode
o.Tag = "!!seq"
sequenceNode := node.(*ast.SequenceNode)
if sequenceNode.IsFlowStyle {
o.Style = FlowStyle
}
astSeq := sequenceNode.Values
o.Content = make([]*CandidateNode, len(astSeq))
for i := 0; i < len(astSeq); i++ {
keyNode := o.CreateChild()
keyNode.IsMapKey = true
keyNode.Tag = "!!int"
keyNode.Kind = ScalarNode
keyNode.Value = fmt.Sprintf("%v", i)
valueNode, err := o.goccyDecodeIntoChild(astSeq[i], cm, anchorMap)
if err != nil {
return err
}
valueNode.Key = keyNode
o.Content[i] = valueNode
}
case ast.AnchorType:
log.Debugf("UnmarshalYAML - an anchor node")
anchorNode := node.(*ast.AnchorNode)
err := o.UnmarshalGoccyYAML(anchorNode.Value, cm, anchorMap)
if err != nil {
return err
}
o.Anchor = anchorNode.Name.String()
anchorMap[o.Anchor] = o
case ast.AliasType:
log.Debugf("UnmarshalYAML - an alias node")
aliasNode := node.(*ast.AliasNode)
o.Kind = AliasNode
o.Value = aliasNode.Value.String()
o.Alias = anchorMap[o.Value]
case ast.MergeKeyType:
log.Debugf("UnmarshalYAML - a merge key")
o.Kind = ScalarNode
o.Tag = "!!merge" // note - I should be able to get rid of this.
o.Value = "<<"
default:
log.Debugf("UnmarshalYAML - no idea of the type!!\n%v: %v", node.Type(), node.String())
}
log.Debugf("KIND: %v", o.Kind)
return nil
}
func (o *CandidateNode) goccyProcessMappingValueNode(mappingEntry *ast.MappingValueNode, cm yaml.CommentMap, anchorMap map[string]*CandidateNode) error {
log.Debug("UnmarshalYAML MAP KEY entry %v", mappingEntry.Key)
// AddKeyValueFirst because it clones the nodes, and we want to have the real refs when Unmarshalling
// particularly for the anchorMap
keyNode, valueNode := o.AddKeyValueChild(&CandidateNode{}, &CandidateNode{})
if err := keyNode.UnmarshalGoccyYAML(mappingEntry.Key, cm, anchorMap); err != nil {
return err
}
log.Debug("UnmarshalYAML MAP VALUE entry %v", mappingEntry.Value)
if err := valueNode.UnmarshalGoccyYAML(mappingEntry.Value, cm, anchorMap); err != nil {
return err
}
if mappingEntry.FootComment != nil {
valueNode.FootComment = mappingEntry.FootComment.String()
}
return nil
}
+206
View File
@@ -0,0 +1,206 @@
package yqlib
import (
"fmt"
"testing"
"github.com/mikefarah/yq/v4/test"
)
type valueRepScenario struct {
input string
tag string
expected interface{}
}
var valueRepScenarios = []valueRepScenario{
{
input: `"cat"`,
expected: `"cat"`,
},
{
input: `3`,
expected: int64(3),
},
{
input: `3.1`,
expected: float64(3.1),
},
{
input: `true`,
expected: true,
},
{
input: `y`,
tag: "!!bool",
expected: true,
},
{
tag: "!!null",
expected: nil,
},
}
func TestCandidateNodeGetValueRepScenarios(t *testing.T) {
for _, tt := range valueRepScenarios {
node := CandidateNode{Value: tt.input, Tag: tt.tag}
actual, err := node.GetValueRep()
if err != nil {
t.Error(err)
return
}
test.AssertResult(t, tt.expected, actual)
}
}
func TestCandidateNodeChildWhenParentUpdated(t *testing.T) {
parent := CandidateNode{}
child := parent.CreateChild()
parent.SetDocument(1)
parent.SetFileIndex(2)
parent.SetFilename("meow")
test.AssertResultWithContext(t, "meow", child.GetFilename(), "filename")
test.AssertResultWithContext(t, 2, child.GetFileIndex(), "file index")
test.AssertResultWithContext(t, uint(1), child.GetDocument(), "document index")
}
type createScalarNodeScenario struct {
value interface{}
stringValue string
expectedTag string
}
var createScalarScenarios = []createScalarNodeScenario{
{
value: "mike",
stringValue: "mike",
expectedTag: "!!str",
},
{
value: 3,
stringValue: "3",
expectedTag: "!!int",
},
{
value: 3.1,
stringValue: "3.1",
expectedTag: "!!float",
},
{
value: true,
stringValue: "true",
expectedTag: "!!bool",
},
{
value: nil,
stringValue: "~",
expectedTag: "!!null",
},
}
func TestCreateScalarNodeScenarios(t *testing.T) {
for _, tt := range createScalarScenarios {
actual := createScalarNode(tt.value, tt.stringValue)
test.AssertResultWithContext(t, tt.stringValue, actual.Value, fmt.Sprintf("Value for: Value: [%v], String: %v", tt.value, tt.stringValue))
test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, fmt.Sprintf("Value for: Value: [%v], String: %v", tt.value, tt.stringValue))
}
}
func TestGetKeyForMapValue(t *testing.T) {
key := createStringScalarNode("yourKey")
n := CandidateNode{Key: key, Value: "meow", document: 3}
test.AssertResult(t, "3 - yourKey", n.GetKey())
}
func TestGetKeyForMapKey(t *testing.T) {
key := createStringScalarNode("yourKey")
key.IsMapKey = true
key.document = 3
test.AssertResult(t, "key-yourKey-3 - ", key.GetKey())
}
func TestGetKeyForValue(t *testing.T) {
n := CandidateNode{Value: "meow", document: 3}
test.AssertResult(t, "3 - ", n.GetKey())
}
func TestGetParsedKeyForMapKey(t *testing.T) {
key := createStringScalarNode("yourKey")
key.IsMapKey = true
key.document = 3
test.AssertResult(t, "yourKey", key.getParsedKey())
}
func TestGetParsedKeyForLooseValue(t *testing.T) {
n := CandidateNode{Value: "meow", document: 3}
test.AssertResult(t, nil, n.getParsedKey())
}
func TestGetParsedKeyForMapValue(t *testing.T) {
key := createStringScalarNode("yourKey")
n := CandidateNode{Key: key, Value: "meow", document: 3}
test.AssertResult(t, "yourKey", n.getParsedKey())
}
func TestGetParsedKeyForArrayValue(t *testing.T) {
key := createScalarNode(4, "4")
n := CandidateNode{Key: key, Value: "meow", document: 3}
test.AssertResult(t, 4, n.getParsedKey())
}
func TestCandidateNodeAddKeyValueChild(t *testing.T) {
key := CandidateNode{Value: "cool", IsMapKey: true}
node := CandidateNode{}
// if we use a key in a new node as a value, it should no longer be marked as a key
_, keyIsValueNow := node.AddKeyValueChild(&CandidateNode{Value: "newKey"}, &key)
test.AssertResult(t, keyIsValueNow.IsMapKey, false)
test.AssertResult(t, key.IsMapKey, true)
}
func TestConvertToNodeInfo(t *testing.T) {
child := &CandidateNode{
Kind: ScalarNode,
Style: DoubleQuotedStyle,
Tag: "!!str",
Value: "childValue",
Line: 2,
Column: 3,
}
parent := &CandidateNode{
Kind: MappingNode,
Style: TaggedStyle,
Tag: "!!map",
Value: "",
Line: 1,
Column: 1,
Content: []*CandidateNode{child},
HeadComment: "head",
LineComment: "line",
FootComment: "foot",
Anchor: "anchor",
}
info := parent.ConvertToNodeInfo()
test.AssertResult(t, "MappingNode", info.Kind)
test.AssertResult(t, "TaggedStyle", info.Style)
test.AssertResult(t, "!!map", info.Tag)
test.AssertResult(t, "head", info.HeadComment)
test.AssertResult(t, "line", info.LineComment)
test.AssertResult(t, "foot", info.FootComment)
test.AssertResult(t, "anchor", info.Anchor)
test.AssertResult(t, 1, info.Line)
test.AssertResult(t, 1, info.Column)
if len(info.Content) != 1 {
t.Fatalf("Expected 1 child, got %d", len(info.Content))
}
childInfo := info.Content[0]
test.AssertResult(t, "ScalarNode", childInfo.Kind)
test.AssertResult(t, "DoubleQuotedStyle", childInfo.Style)
test.AssertResult(t, "!!str", childInfo.Tag)
test.AssertResult(t, "childValue", childInfo.Value)
test.AssertResult(t, 2, childInfo.Line)
test.AssertResult(t, 3, childInfo.Column)
}
+215
View File
@@ -0,0 +1,215 @@
package yqlib
import (
"fmt"
yaml "go.yaml.in/yaml/v3"
)
func MapYamlStyle(original yaml.Style) Style {
switch original {
case yaml.TaggedStyle:
return TaggedStyle
case yaml.DoubleQuotedStyle:
return DoubleQuotedStyle
case yaml.SingleQuotedStyle:
return SingleQuotedStyle
case yaml.LiteralStyle:
return LiteralStyle
case yaml.FoldedStyle:
return FoldedStyle
case yaml.FlowStyle:
return FlowStyle
case 0:
return 0
}
return Style(original)
}
func MapToYamlStyle(original Style) yaml.Style {
switch original {
case TaggedStyle:
return yaml.TaggedStyle
case DoubleQuotedStyle:
return yaml.DoubleQuotedStyle
case SingleQuotedStyle:
return yaml.SingleQuotedStyle
case LiteralStyle:
return yaml.LiteralStyle
case FoldedStyle:
return yaml.FoldedStyle
case FlowStyle:
return yaml.FlowStyle
case 0:
return 0
}
return yaml.Style(original)
}
func (o *CandidateNode) copyFromYamlNode(node *yaml.Node, anchorMap map[string]*CandidateNode) {
o.Style = MapYamlStyle(node.Style)
o.Tag = node.Tag
o.Value = node.Value
o.Anchor = node.Anchor
if o.Anchor != "" {
anchorMap[o.Anchor] = o
log.Debug("set anchor %v to %v", o.Anchor, NodeToString(o))
}
// its a single alias
if node.Alias != nil && node.Alias.Anchor != "" {
o.Alias = anchorMap[node.Alias.Anchor]
log.Debug("set alias to %v", NodeToString(anchorMap[node.Alias.Anchor]))
}
o.HeadComment = node.HeadComment
o.LineComment = node.LineComment
o.FootComment = node.FootComment
o.Line = node.Line
o.Column = node.Column
}
func (o *CandidateNode) copyToYamlNode(node *yaml.Node) {
node.Style = MapToYamlStyle(o.Style)
node.Tag = o.Tag
node.Value = o.Value
node.Anchor = o.Anchor
node.HeadComment = o.HeadComment
node.LineComment = o.LineComment
node.FootComment = o.FootComment
node.Line = o.Line
node.Column = o.Column
}
func (o *CandidateNode) decodeIntoChild(childNode *yaml.Node, anchorMap map[string]*CandidateNode) (*CandidateNode, error) {
newChild := o.CreateChild()
// null yaml.Nodes to not end up calling UnmarshalYAML
// so we call it explicitly
if childNode.Tag == "!!null" {
newChild.Kind = ScalarNode
newChild.copyFromYamlNode(childNode, anchorMap)
return newChild, nil
}
err := newChild.UnmarshalYAML(childNode, anchorMap)
return newChild, err
}
func (o *CandidateNode) UnmarshalYAML(node *yaml.Node, anchorMap map[string]*CandidateNode) error {
log.Debugf("UnmarshalYAML %v", node.Tag)
switch node.Kind {
case yaml.AliasNode:
log.Debug("UnmarshalYAML - alias from yaml: %v", o.Tag)
o.Kind = AliasNode
o.copyFromYamlNode(node, anchorMap)
return nil
case yaml.ScalarNode:
log.Debugf("UnmarshalYAML - a scalar")
o.Kind = ScalarNode
o.copyFromYamlNode(node, anchorMap)
return nil
case yaml.MappingNode:
log.Debugf("UnmarshalYAML - a mapping node")
o.Kind = MappingNode
o.copyFromYamlNode(node, anchorMap)
o.Content = make([]*CandidateNode, len(node.Content))
for i := 0; i < len(node.Content); i += 2 {
keyNode, err := o.decodeIntoChild(node.Content[i], anchorMap)
if err != nil {
return err
}
keyNode.IsMapKey = true
valueNode, err := o.decodeIntoChild(node.Content[i+1], anchorMap)
if err != nil {
return err
}
valueNode.Key = keyNode
o.Content[i] = keyNode
o.Content[i+1] = valueNode
}
log.Debugf("UnmarshalYAML - finished mapping node")
return nil
case yaml.SequenceNode:
log.Debugf("UnmarshalYAML - a sequence: %v", len(node.Content))
o.Kind = SequenceNode
o.copyFromYamlNode(node, anchorMap)
log.Debugf("node Style: %v", node.Style)
log.Debugf("o Style: %v", o.Style)
o.Content = make([]*CandidateNode, len(node.Content))
for i := 0; i < len(node.Content); i++ {
keyNode := o.CreateChild()
keyNode.IsMapKey = true
keyNode.Tag = "!!int"
keyNode.Kind = ScalarNode
keyNode.Value = fmt.Sprintf("%v", i)
valueNode, err := o.decodeIntoChild(node.Content[i], anchorMap)
if err != nil {
return err
}
valueNode.Key = keyNode
o.Content[i] = valueNode
}
return nil
case 0:
// not sure when this happens
o.copyFromYamlNode(node, anchorMap)
log.Debugf("UnmarshalYAML - err.. %v", NodeToString(o))
return nil
default:
return fmt.Errorf("orderedMap: invalid yaml node")
}
}
func (o *CandidateNode) MarshalYAML() (*yaml.Node, error) {
log.Debug("MarshalYAML to yaml: %v", o.Tag)
switch o.Kind {
case AliasNode:
log.Debug("MarshalYAML - alias to yaml: %v", o.Tag)
target := &yaml.Node{Kind: yaml.AliasNode}
o.copyToYamlNode(target)
return target, nil
case ScalarNode:
log.Debug("MarshalYAML - scalar: %v", o.Value)
target := &yaml.Node{Kind: yaml.ScalarNode}
o.copyToYamlNode(target)
return target, nil
case MappingNode, SequenceNode:
targetKind := yaml.MappingNode
if o.Kind == SequenceNode {
targetKind = yaml.SequenceNode
}
target := &yaml.Node{Kind: targetKind}
o.copyToYamlNode(target)
log.Debugf("original style: %v", o.Style)
log.Debugf("original: %v, tag: %v, style: %v, kind: %v", NodeToString(o), target.Tag, target.Style, target.Kind == yaml.SequenceNode)
target.Content = make([]*yaml.Node, len(o.Content))
for i := 0; i < len(o.Content); i++ {
child, err := o.Content[i].MarshalYAML()
if err != nil {
return nil, err
}
target.Content[i] = child
}
return target, nil
}
target := &yaml.Node{}
o.copyToYamlNode(target)
return target, nil
}
+179
View File
@@ -0,0 +1,179 @@
//go:build !yq_nojson
package yqlib
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/goccy/go-json"
)
func (o *CandidateNode) setScalarFromJson(value interface{}) error {
o.Kind = ScalarNode
switch rawData := value.(type) {
case nil:
o.Tag = "!!null"
o.Value = "null"
case float64, float32:
o.Value = fmt.Sprintf("%v", value)
o.Tag = "!!float"
// json decoder returns ints as float.
if value == float64(int64(rawData.(float64))) {
// aha it's an int disguised as a float
o.Tag = "!!int"
o.Value = fmt.Sprintf("%v", int64(value.(float64)))
}
case int, int64, int32:
o.Value = fmt.Sprintf("%v", value)
o.Tag = "!!int"
case bool:
o.Value = fmt.Sprintf("%v", value)
o.Tag = "!!bool"
case string:
o.Value = rawData
o.Tag = "!!str"
default:
return fmt.Errorf("unrecognised type :( %v", rawData)
}
return nil
}
func (o *CandidateNode) UnmarshalJSON(data []byte) error {
log.Debug("UnmarshalJSON")
switch data[0] {
case '{':
log.Debug("UnmarshalJSON - its a map!")
// its a map
o.Kind = MappingNode
o.Tag = "!!map"
dec := json.NewDecoder(bytes.NewReader(data))
_, err := dec.Token() // open object
if err != nil {
return err
}
// cycle through k/v
var tok json.Token
for tok, err = dec.Token(); err == nil; tok, err = dec.Token() {
// we can expect two types: string or Delim. Delim automatically means
// that it is the closing bracket of the object, whereas string means
// that there is another key.
if _, ok := tok.(json.Delim); ok {
break
}
childKey := o.CreateChild()
childKey.IsMapKey = true
childKey.Value = tok.(string)
childKey.Kind = ScalarNode
childKey.Tag = "!!str"
childValue := o.CreateChild()
childValue.Key = childKey
if err := dec.Decode(childValue); err != nil {
return err
}
o.Content = append(o.Content, childKey, childValue)
}
// unexpected error
if err != nil && !errors.Is(err, io.EOF) {
return err
}
return nil
case '[':
o.Kind = SequenceNode
o.Tag = "!!seq"
log.Debug("UnmarshalJSON - its an array!")
var children []*CandidateNode
if err := json.Unmarshal(data, &children); err != nil {
return err
}
// now we put the children into the content, and set a key value for them
for i, child := range children {
if child == nil {
// need to represent it as a null scalar
child = createScalarNode(nil, "null")
}
childKey := o.CreateChild()
childKey.Kind = ScalarNode
childKey.Tag = "!!int"
childKey.Value = fmt.Sprintf("%v", i)
childKey.IsMapKey = true
child.Parent = o
child.Key = childKey
o.Content = append(o.Content, child)
}
return nil
}
log.Debug("UnmarshalJSON - its a scalar!")
// otherwise, must be a scalar
var scalar interface{}
err := json.Unmarshal(data, &scalar)
if err != nil {
return err
}
log.Debug("UnmarshalJSON - scalar is %v", scalar)
return o.setScalarFromJson(scalar)
}
func (o *CandidateNode) MarshalJSON() ([]byte, error) {
log.Debugf("MarshalJSON %v", NodeToString(o))
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
enc.SetIndent("", " ")
enc.SetEscapeHTML(false) // do not escape html chars e.g. &, <, >
switch o.Kind {
case AliasNode:
log.Debugf("MarshalJSON AliasNode")
err := enc.Encode(o.Alias)
return buf.Bytes(), err
case ScalarNode:
log.Debugf("MarshalJSON ScalarNode")
value, err := o.GetValueRep()
if err != nil {
return buf.Bytes(), err
}
err = enc.Encode(value)
return buf.Bytes(), err
case MappingNode:
log.Debugf("MarshalJSON MappingNode")
buf.WriteByte('{')
for i := 0; i < len(o.Content); i += 2 {
if err := enc.Encode(o.Content[i].Value); err != nil {
return nil, err
}
buf.WriteByte(':')
if err := enc.Encode(o.Content[i+1]); err != nil {
return nil, err
}
if i != len(o.Content)-2 {
buf.WriteByte(',')
}
}
buf.WriteByte('}')
return buf.Bytes(), nil
case SequenceNode:
log.Debugf("MarshalJSON SequenceNode, %v, len: %v", o.Content, len(o.Content))
var err error
if len(o.Content) == 0 {
buf.WriteString("[]")
} else {
err = enc.Encode(o.Content)
}
return buf.Bytes(), err
default:
err := enc.Encode(nil)
return buf.Bytes(), err
}
}
+1 -1
View File
@@ -7,6 +7,6 @@ import (
"os"
)
func changeOwner(info fs.FileInfo, file *os.File) error {
func changeOwner(_ fs.FileInfo, _ *os.File) error {
return nil
}
+6
View File
@@ -56,6 +56,12 @@ func colorizeAndPrint(yamlBytes []byte, writer io.Writer) error {
Suffix: format(color.Reset),
}
}
p.Comment = func() *printer.Property {
return &printer.Property{
Prefix: format(color.FgHiBlack),
Suffix: format(color.Reset),
}
}
_, err := writer.Write([]byte(p.PrintTokens(tokens) + "\n"))
return err
}
+17 -29
View File
@@ -5,7 +5,6 @@ import (
"fmt"
"time"
"github.com/jinzhu/copier"
logging "gopkg.in/op/go-logging.v1"
)
@@ -58,13 +57,19 @@ func (n *Context) SetVariable(name string, value *list.List) {
func (n *Context) ChildContext(results *list.List) Context {
clone := Context{DontAutoCreate: n.DontAutoCreate, datetimeLayout: n.datetimeLayout}
clone.Variables = make(map[string]*list.List)
if len(n.Variables) > 0 {
err := copier.Copy(&clone.Variables, n.Variables)
if err != nil {
log.Error("Error cloning context :(")
panic(err)
for variableKey, originalValueList := range n.Variables {
variableCopyList := list.New()
for el := originalValueList.Front(); el != nil; el = el.Next() {
// note that we dont make a copy of the candidate node
// this is so the 'ref' operator can work correctly.
clonedNode := el.Value.(*CandidateNode)
variableCopyList.PushBack(clonedNode)
}
clone.Variables[variableKey] = variableCopyList
}
clone.MatchingNodes = results
return clone
}
@@ -78,35 +83,18 @@ func (n *Context) ToString() string {
}
func (n *Context) DeepClone() Context {
clone := Context{}
err := copier.Copy(&clone, n)
// copier doesn't do lists properly for some reason
clone.MatchingNodes = list.New()
clonedContent := list.New()
for el := n.MatchingNodes.Front(); el != nil; el = el.Next() {
clonedNode, err := el.Value.(*CandidateNode).Copy()
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
clone.MatchingNodes.PushBack(clonedNode)
clonedNode := el.Value.(*CandidateNode).Copy()
clonedContent.PushBack(clonedNode)
}
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
return clone
return n.ChildContext(clonedContent)
}
func (n *Context) Clone() Context {
clone := Context{}
err := copier.Copy(&clone, n)
if err != nil {
log.Error("Error cloning context :(")
panic(err)
}
return clone
return n.ChildContext(n.MatchingNodes)
}
func (n *Context) ReadOnlyClone() Context {
+261
View File
@@ -0,0 +1,261 @@
package yqlib
import (
"container/list"
"strings"
"testing"
"github.com/mikefarah/yq/v4/test"
logging "gopkg.in/op/go-logging.v1"
)
func TestChildContext(t *testing.T) {
expectedOriginal := make(map[string]*list.List)
expectedOriginal["dog"] = list.New()
expectedOriginal["dog"].PushBack(&CandidateNode{Value: "woof"})
originalVariables := make(map[string]*list.List)
originalVariables["dog"] = list.New()
originalVariables["dog"].PushBack(&CandidateNode{Value: "woof"})
original := Context{
DontAutoCreate: true,
datetimeLayout: "cat",
Variables: originalVariables,
}
newResults := list.New()
newResults.PushBack(&CandidateNode{Value: "bar"})
clone := original.ChildContext(newResults)
test.AssertResultComplex(t, originalVariables, clone.Variables)
clone.Variables["dog"].PushBack("bark")
// ensure this is a separate copy
test.AssertResultComplex(t, 1, originalVariables["dog"].Len())
}
func TestChildContextNoVariables(t *testing.T) {
original := Context{
DontAutoCreate: true,
datetimeLayout: "cat",
}
newResults := list.New()
newResults.PushBack(&CandidateNode{Value: "bar"})
clone := original.ChildContext(newResults)
test.AssertResultComplex(t, make(map[string]*list.List), clone.Variables)
}
func TestSingleReadonlyChildContext(t *testing.T) {
original := Context{
DontAutoCreate: false,
datetimeLayout: "2006-01-02",
}
candidate := &CandidateNode{Value: "test"}
clone := original.SingleReadonlyChildContext(candidate)
// Should have DontAutoCreate set to true
test.AssertResultComplex(t, true, clone.DontAutoCreate)
// Should have the candidate node in MatchingNodes
test.AssertResultComplex(t, 1, clone.MatchingNodes.Len())
test.AssertResultComplex(t, candidate, clone.MatchingNodes.Front().Value)
}
func TestSingleChildContext(t *testing.T) {
original := Context{
DontAutoCreate: true,
datetimeLayout: "2006-01-02",
}
candidate := &CandidateNode{Value: "test"}
clone := original.SingleChildContext(candidate)
// Should preserve DontAutoCreate
test.AssertResultComplex(t, true, clone.DontAutoCreate)
// Should have the candidate node in MatchingNodes
test.AssertResultComplex(t, 1, clone.MatchingNodes.Len())
test.AssertResultComplex(t, candidate, clone.MatchingNodes.Front().Value)
}
func TestSetDateTimeLayout(t *testing.T) {
context := Context{}
// Test setting datetime layout
context.SetDateTimeLayout("2006-01-02T15:04:05Z07:00")
test.AssertResultComplex(t, "2006-01-02T15:04:05Z07:00", context.datetimeLayout)
}
func TestGetDateTimeLayout(t *testing.T) {
// Test with custom layout
context := Context{datetimeLayout: "2006-01-02"}
result := context.GetDateTimeLayout()
test.AssertResultComplex(t, "2006-01-02", result)
// Test with empty layout (should return default)
context = Context{}
result = context.GetDateTimeLayout()
test.AssertResultComplex(t, "2006-01-02T15:04:05Z07:00", result)
}
func TestGetVariable(t *testing.T) {
// Test with nil Variables
context := Context{}
result := context.GetVariable("nonexistent")
test.AssertResultComplex(t, (*list.List)(nil), result)
// Test with existing variable
variables := make(map[string]*list.List)
variables["test"] = list.New()
variables["test"].PushBack(&CandidateNode{Value: "value"})
context = Context{Variables: variables}
result = context.GetVariable("test")
test.AssertResultComplex(t, variables["test"], result)
// Test with non-existent variable
result = context.GetVariable("nonexistent")
test.AssertResultComplex(t, (*list.List)(nil), result)
}
func TestSetVariable(t *testing.T) {
// Test setting variable when Variables is nil
context := Context{}
value := list.New()
value.PushBack(&CandidateNode{Value: "test"})
context.SetVariable("key", value)
test.AssertResultComplex(t, value, context.Variables["key"])
// Test setting variable when Variables already exists
context.SetVariable("key2", value)
test.AssertResultComplex(t, value, context.Variables["key2"])
}
func TestToString(t *testing.T) {
context := Context{
DontAutoCreate: true,
MatchingNodes: list.New(),
}
// Add a node to test the full string representation
node := &CandidateNode{Value: "test"}
context.MatchingNodes.PushBack(node)
// Test with debug logging disabled (default)
result := context.ToString()
test.AssertResultComplex(t, "", result)
// Test with debug logging enabled
logging.SetLevel(logging.DEBUG, "")
defer logging.SetLevel(logging.INFO, "") // Reset to default
result2 := context.ToString()
test.AssertResultComplex(t, true, len(result2) > 0)
test.AssertResultComplex(t, true, strings.Contains(result2, "Context"))
test.AssertResultComplex(t, true, strings.Contains(result2, "DontAutoCreate: true"))
}
func TestDeepClone(t *testing.T) {
// Create original context with variables and matching nodes
originalVariables := make(map[string]*list.List)
originalVariables["test"] = list.New()
originalVariables["test"].PushBack(&CandidateNode{Value: "original"})
original := Context{
DontAutoCreate: true,
datetimeLayout: "2006-01-02",
Variables: originalVariables,
MatchingNodes: list.New(),
}
// Add a node to MatchingNodes
node := &CandidateNode{Value: "test"}
original.MatchingNodes.PushBack(node)
clone := original.DeepClone()
// Should preserve DontAutoCreate and datetimeLayout
test.AssertResultComplex(t, original.DontAutoCreate, clone.DontAutoCreate)
test.AssertResultComplex(t, original.datetimeLayout, clone.datetimeLayout)
// Should have copied variables
test.AssertResultComplex(t, 1, len(clone.Variables))
test.AssertResultComplex(t, "original", clone.Variables["test"].Front().Value.(*CandidateNode).Value)
// Should have deep copied MatchingNodes
test.AssertResultComplex(t, 1, clone.MatchingNodes.Len())
// Verify it's a deep copy by modifying the original
original.MatchingNodes.Front().Value.(*CandidateNode).Value = "modified"
test.AssertResultComplex(t, "test", clone.MatchingNodes.Front().Value.(*CandidateNode).Value)
}
func TestClone(t *testing.T) {
// Create original context
original := Context{
DontAutoCreate: true,
datetimeLayout: "2006-01-02",
MatchingNodes: list.New(),
}
node := &CandidateNode{Value: "test"}
original.MatchingNodes.PushBack(node)
clone := original.Clone()
// Should preserve DontAutoCreate and datetimeLayout
test.AssertResultComplex(t, original.DontAutoCreate, clone.DontAutoCreate)
test.AssertResultComplex(t, original.datetimeLayout, clone.datetimeLayout)
// Should have the same MatchingNodes reference
test.AssertResultComplex(t, original.MatchingNodes, clone.MatchingNodes)
}
func TestReadOnlyClone(t *testing.T) {
original := Context{
DontAutoCreate: false,
datetimeLayout: "2006-01-02",
MatchingNodes: list.New(),
}
node := &CandidateNode{Value: "test"}
original.MatchingNodes.PushBack(node)
clone := original.ReadOnlyClone()
// Should set DontAutoCreate to true
test.AssertResultComplex(t, true, clone.DontAutoCreate)
// Should preserve other fields
test.AssertResultComplex(t, original.datetimeLayout, clone.datetimeLayout)
test.AssertResultComplex(t, original.MatchingNodes, clone.MatchingNodes)
}
func TestWritableClone(t *testing.T) {
original := Context{
DontAutoCreate: true,
datetimeLayout: "2006-01-02",
MatchingNodes: list.New(),
}
node := &CandidateNode{Value: "test"}
original.MatchingNodes.PushBack(node)
clone := original.WritableClone()
// Should set DontAutoCreate to false
test.AssertResultComplex(t, false, clone.DontAutoCreate)
// Should preserve other fields
test.AssertResultComplex(t, original.datetimeLayout, clone.datetimeLayout)
test.AssertResultComplex(t, original.MatchingNodes, clone.MatchingNodes)
}
+23
View File
@@ -0,0 +1,23 @@
package yqlib
type CsvPreferences struct {
Separator rune
AutoParse bool
}
func NewDefaultCsvPreferences() CsvPreferences {
return CsvPreferences{
Separator: ',',
AutoParse: true,
}
}
func NewDefaultTsvPreferences() CsvPreferences {
return CsvPreferences{
Separator: '\t',
AutoParse: true,
}
}
var ConfiguredCsvPreferences = NewDefaultCsvPreferences()
var ConfiguredTsvPreferences = NewDefaultTsvPreferences()
+123 -16
View File
@@ -12,6 +12,11 @@ const csvSimple = `name,numberOfCats,likesApples,height
Gary,1,true,168.8
Samantha's Rabbit,2,false,-188.8
`
const csvSimpleWithObject = `name,numberOfCats,likesApples,height,facts
Gary,1,true,168.8,cool: true
Samantha's Rabbit,2,false,-188.8,tall: indeed
`
const csvMissing = `name,numberOfCats,likesApples,height
,null,,168.8
`
@@ -39,6 +44,31 @@ const expectedYamlFromCSV = `- name: Gary
likesApples: false
height: -188.8
`
const expectedYamlFromCSVWithObject = `- name: Gary
numberOfCats: 1
likesApples: true
height: 168.8
facts:
cool: true
- name: Samantha's Rabbit
numberOfCats: 2
likesApples: false
height: -188.8
facts:
tall: indeed
`
const expectedYamlFromCSVNoParsing = `- name: Gary
numberOfCats: 1
likesApples: true
height: 168.8
facts: 'cool: true'
- name: Samantha's Rabbit
numberOfCats: 2
likesApples: false
height: -188.8
facts: 'tall: indeed'
`
const expectedYamlFromCSVMissingData = `- name: Gary
numberOfCats: 1
@@ -119,12 +149,56 @@ var csvScenarios = []formatScenario{
expected: csvMissing,
scenarioType: "roundtrip-csv",
},
{
description: "decode csv key",
skipDoc: true,
input: csvSimple,
expression: ".[0].name | key",
expected: "name\n",
scenarioType: "decode-csv",
},
{
description: "decode csv parent",
skipDoc: true,
input: csvSimple,
expression: ".[0].name | parent | .height",
expected: "168.8\n",
scenarioType: "decode-csv",
},
{
description: "Parse CSV into an array of objects",
subdescription: "First row is assumed to be the header row.",
input: csvSimple,
expected: expectedYamlFromCSV,
scenarioType: "decode-csv-object",
subdescription: "First row is assumed to be the header row. By default, entries with YAML/JSON formatting will be parsed!",
input: csvSimpleWithObject,
expected: expectedYamlFromCSVWithObject,
scenarioType: "decode-csv",
},
{
description: "Decode CSV line breaks",
skipDoc: true,
input: "heading1\n\"some data\nwith a line break\"\n",
expected: "- heading1: |-\n some data\n with a line break\n",
scenarioType: "decode-csv",
},
{
description: "Parse CSV into an array of objects, no auto-parsing",
subdescription: "First row is assumed to be the header row. Entries with YAML/JSON will be left as strings.",
input: csvSimpleWithObject,
expected: expectedYamlFromCSVNoParsing,
scenarioType: "decode-csv-no-auto",
},
{
description: "values starting with #, no auto parse",
skipDoc: true,
input: "value\n#ffff",
expected: "- value: '#ffff'\n",
scenarioType: "decode-csv-no-auto",
},
{
description: "values starting with #",
skipDoc: true,
input: "value\n#ffff",
expected: "- value: #ffff\n",
scenarioType: "decode-csv",
},
{
description: "Scalar roundtrip",
@@ -153,15 +227,17 @@ 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, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(ConfiguredCsvPreferences)), s.description)
case "encode-tsv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(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, mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(ConfiguredTsvPreferences)), s.description)
case "decode-csv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(ConfiguredCsvPreferences), NewYamlEncoder(ConfiguredYamlPreferences)), s.description)
case "decode-csv-no-auto":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(CsvPreferences{Separator: ',', AutoParse: false}), NewYamlEncoder(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, mustProcessFormatScenario(s, NewCSVObjectDecoder(ConfiguredTsvPreferences), NewYamlEncoder(ConfiguredYamlPreferences)), s.description)
case "roundtrip-csv":
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(','), NewCsvEncoder(',')), s.description)
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewCSVObjectDecoder(ConfiguredCsvPreferences), NewCsvEncoder(ConfiguredCsvPreferences)), s.description)
default:
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
}
@@ -188,7 +264,32 @@ 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))),
mustProcessFormatScenario(s, NewCSVObjectDecoder(CsvPreferences{Separator: separator, AutoParse: true}), NewYamlEncoder(ConfiguredYamlPreferences))),
)
}
func documentCSVDecodeObjectNoAutoScenario(w *bufio.Writer, s formatScenario, formatType string) {
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
if s.subdescription != "" {
writeOrPanic(w, s.subdescription)
writeOrPanic(w, "\n\n")
}
writeOrPanic(w, fmt.Sprintf("Given a sample.%v file of:\n", formatType))
writeOrPanic(w, fmt.Sprintf("```%v\n%v\n```\n", formatType, s.input))
writeOrPanic(w, "then\n")
writeOrPanic(w, fmt.Sprintf("```bash\nyq -p=%v --csv-auto-parse=f sample.%v\n```\n", formatType, formatType))
writeOrPanic(w, "will output\n")
separator := ','
if formatType == "tsv" {
separator = '\t'
}
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n",
mustProcessFormatScenario(s, NewCSVObjectDecoder(CsvPreferences{Separator: separator, AutoParse: false}), NewYamlEncoder(ConfiguredYamlPreferences))),
)
}
@@ -218,9 +319,10 @@ func documentCSVEncodeScenario(w *bufio.Writer, s formatScenario, formatType str
if formatType == "tsv" {
separator = '\t'
}
csvPrefs := NewDefaultCsvPreferences()
csvPrefs.Separator = separator
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(separator))),
mustProcessFormatScenario(s, NewYamlDecoder(ConfiguredYamlPreferences), NewCsvEncoder(csvPrefs))),
)
}
@@ -251,12 +353,15 @@ func documentCSVRoundTripScenario(w *bufio.Writer, s formatScenario, formatType
separator = '\t'
}
csvPrefs := NewDefaultCsvPreferences()
csvPrefs.Separator = separator
writeOrPanic(w, fmt.Sprintf("```%v\n%v```\n\n", formatType,
mustProcessFormatScenario(s, NewCSVObjectDecoder(separator), NewCsvEncoder(separator))),
mustProcessFormatScenario(s, NewCSVObjectDecoder(CsvPreferences{Separator: separator, AutoParse: true}), NewCsvEncoder(csvPrefs))),
)
}
func documentCSVScenario(t *testing.T, w *bufio.Writer, i interface{}) {
func documentCSVScenario(_ *testing.T, w *bufio.Writer, i interface{}) {
s := i.(formatScenario)
if s.skipDoc {
return
@@ -266,8 +371,10 @@ func documentCSVScenario(t *testing.T, w *bufio.Writer, i interface{}) {
documentCSVEncodeScenario(w, s, "csv")
case "encode-tsv":
documentCSVEncodeScenario(w, s, "tsv")
case "decode-csv-object":
case "decode-csv":
documentCSVDecodeObjectScenario(w, s, "csv")
case "decode-csv-no-auto":
documentCSVDecodeObjectNoAutoScenario(w, s, "csv")
case "decode-tsv-object":
documentCSVDecodeObjectScenario(w, s, "tsv")
case "roundtrip-csv":
+15 -11
View File
@@ -4,16 +4,15 @@ import (
"fmt"
logging "gopkg.in/op/go-logging.v1"
yaml "gopkg.in/yaml.v3"
)
type DataTreeNavigator interface {
// given the context and a expressionNode,
// given the context and an expressionNode,
// 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
DeeplyAssign(context Context, path []interface{}, rhsNode *CandidateNode) error
}
type dataTreeNavigator struct {
@@ -23,15 +22,21 @@ func NewDataTreeNavigator() DataTreeNavigator {
return &dataTreeNavigator{}
}
func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsNode *yaml.Node) error {
rhsCandidateNode := &CandidateNode{
Path: path,
Node: rhsNode,
}
func (d *dataTreeNavigator) DeeplyAssign(context Context, path []interface{}, rhsCandidateNode *CandidateNode) error {
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
if rhsCandidateNode.Kind == MappingNode {
log.Debug("DeeplyAssign: deeply merging object")
// if the rhs is a map, we need to deeply merge it in.
// otherwise we'll clobber any existing fields
assignmentOp = &Operation{OperationType: multiplyAssignOpType, Preferences: multiplyPreferences{
AppendArrays: true,
TraversePrefs: traversePreferences{DontFollowAlias: true},
AssignPrefs: assignPreferences{},
}}
}
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhsCandidateNode}
assignmentOpNode := &ExpressionNode{
@@ -55,11 +60,10 @@ func (d *dataTreeNavigator) GetMatchingNodes(context Context, expressionNode *Ex
log.Debug(NodeToString(el.Value.(*CandidateNode)))
}
}
log.Debug(">>")
handler := expressionNode.Operation.OperationType.Handler
if handler != nil {
return handler(d, context, expressionNode)
}
return Context{}, fmt.Errorf("Unknown operator %v", expressionNode.Operation.OperationType)
return Context{}, fmt.Errorf("unknown operator %v", expressionNode.Operation.OperationType.Type)
}
+437
View File
@@ -0,0 +1,437 @@
package yqlib
import (
"container/list"
"testing"
"github.com/mikefarah/yq/v4/test"
)
func TestGetMatchingNodes_NilExpressionNode(t *testing.T) {
navigator := NewDataTreeNavigator()
context := Context{
MatchingNodes: list.New(),
}
result, err := navigator.GetMatchingNodes(context, nil)
test.AssertResult(t, nil, err)
test.AssertResultComplex(t, context, result)
}
func TestGetMatchingNodes_UnknownOperator(t *testing.T) {
navigator := NewDataTreeNavigator()
context := Context{
MatchingNodes: list.New(),
}
// Create an expression node with an unknown operation type
unknownOpType := &operationType{Type: "UNKNOWN", Handler: nil}
expressionNode := &ExpressionNode{
Operation: &Operation{OperationType: unknownOpType},
}
result, err := navigator.GetMatchingNodes(context, expressionNode)
test.AssertResult(t, "unknown operator UNKNOWN", err.Error())
test.AssertResultComplex(t, Context{}, result)
}
func TestGetMatchingNodes_ValidOperator(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a simple context with a scalar node
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "test",
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(scalarNode)
// Create an expression node with a valid operation (self reference)
expressionNode := &ExpressionNode{
Operation: &Operation{OperationType: selfReferenceOpType},
}
result, err := navigator.GetMatchingNodes(context, expressionNode)
test.AssertResult(t, nil, err)
test.AssertResult(t, 1, result.MatchingNodes.Len())
// Verify the result contains the same node
resultNode := result.MatchingNodes.Front().Value.(*CandidateNode)
test.AssertResult(t, scalarNode, resultNode)
}
func TestDeeplyAssign_ScalarNode(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "existing", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "old_value"},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a scalar node to assign
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "new_value",
}
// Assign to path ["new_key"]
path := []interface{}{"new_key"}
err := navigator.DeeplyAssign(context, path, scalarNode)
test.AssertResult(t, nil, err)
// Verify the assignment was made
// The root node should now have the new key-value pair
test.AssertResult(t, 4, len(rootNode.Content)) // 2 original + 2 new
// Find the new key-value pair
found := false
for i := 0; i < len(rootNode.Content)-1; i += 2 {
key := rootNode.Content[i]
value := rootNode.Content[i+1]
if key.Value == "new_key" && value.Value == "new_value" {
found = true
break
}
}
test.AssertResult(t, true, found)
}
func TestDeeplyAssign_MappingNode(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "existing", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "old_value"},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a mapping node to assign (this should trigger deep merge)
mappingNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "nested_key", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "nested_value"},
},
}
// Assign to path ["new_map"]
path := []interface{}{"new_map"}
err := navigator.DeeplyAssign(context, path, mappingNode)
test.AssertResult(t, nil, err)
// Verify the assignment was made
// The root node should now have the new mapping
test.AssertResult(t, 4, len(rootNode.Content)) // 2 original + 2 new
// Find the new mapping
found := false
for i := 0; i < len(rootNode.Content); i += 2 {
if i+1 < len(rootNode.Content) {
key := rootNode.Content[i]
value := rootNode.Content[i+1]
if key.Value == "new_map" && value.Kind == MappingNode {
found = true
// Verify the nested content
test.AssertResult(t, 2, len(value.Content))
test.AssertResult(t, "nested_key", value.Content[0].Value)
test.AssertResult(t, "nested_value", value.Content[1].Value)
break
}
}
}
test.AssertResult(t, true, found)
}
func TestDeeplyAssign_DeepPath(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "level1", IsMapKey: true},
{Kind: MappingNode, Tag: "!!map", Content: []*CandidateNode{}},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a scalar node to assign
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "deep_value",
}
// Assign to deep path ["level1", "level2", "level3"]
path := []interface{}{"level1", "level2", "level3"}
err := navigator.DeeplyAssign(context, path, scalarNode)
test.AssertResult(t, nil, err)
// Verify the deep assignment was made
level1Node := rootNode.Content[1] // The mapping node
test.AssertResult(t, 2, len(level1Node.Content)) // Should have level2 key-value
level2Key := level1Node.Content[0]
level2Value := level1Node.Content[1]
test.AssertResult(t, "level2", level2Key.Value)
test.AssertResult(t, MappingNode, level2Value.Kind)
level3Key := level2Value.Content[0]
level3Value := level2Value.Content[1]
test.AssertResult(t, "level3", level3Key.Value)
test.AssertResult(t, "deep_value", level3Value.Value)
}
func TestDeeplyAssign_ArrayPath(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node containing an array
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "array", IsMapKey: true},
{Kind: SequenceNode, Tag: "!!seq", Content: []*CandidateNode{}},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a scalar node to assign
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "array_value",
}
// Assign to array path ["array", 0]
path := []interface{}{"array", 0}
err := navigator.DeeplyAssign(context, path, scalarNode)
test.AssertResult(t, nil, err)
// Verify the array assignment was made
arrayNode := rootNode.Content[1] // The sequence node
test.AssertResult(t, 1, len(arrayNode.Content)) // Should have one element
arrayElement := arrayNode.Content[0]
test.AssertResult(t, "array_value", arrayElement.Value)
}
func TestDeeplyAssign_OverwriteExisting(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "key", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "old_value"},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a scalar node to assign
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "new_value",
}
// Assign to existing path ["key"]
path := []interface{}{"key"}
err := navigator.DeeplyAssign(context, path, scalarNode)
test.AssertResult(t, nil, err)
// Verify the value was overwritten
test.AssertResult(t, 2, len(rootNode.Content)) // Should still have 2 elements
key := rootNode.Content[0]
value := rootNode.Content[1]
test.AssertResult(t, "key", key.Value)
test.AssertResult(t, "new_value", value.Value) // Should be overwritten
}
func TestDeeplyAssign_ErrorHandling(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a scalar node (not a mapping)
scalarNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "not_a_map",
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(scalarNode)
// Create a scalar node to assign
assignNode := &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: "value",
}
// Try to assign to a path on a scalar (should fail)
path := []interface{}{"key"}
err := navigator.DeeplyAssign(context, path, assignNode)
// Print the actual error for debugging
if err != nil {
t.Logf("Actual error: %v", err)
}
// This should fail because we can't assign to a scalar
test.AssertResult(t, nil, err)
}
func TestGetMatchingNodes_WithVariables(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with variables
variables := make(map[string]*list.List)
varList := list.New()
varList.PushBack(&CandidateNode{Kind: ScalarNode, Tag: "!!str", Value: "var_value"})
variables["test_var"] = varList
context := Context{
MatchingNodes: list.New(),
Variables: variables,
}
// Create an expression node that gets a variable
expressionNode := &ExpressionNode{
Operation: &Operation{OperationType: getVariableOpType, StringValue: "test_var"},
}
result, err := navigator.GetMatchingNodes(context, expressionNode)
test.AssertResult(t, nil, err)
test.AssertResult(t, 1, result.MatchingNodes.Len())
// Verify the variable was retrieved
resultNode := result.MatchingNodes.Front().Value.(*CandidateNode)
test.AssertResult(t, "var_value", resultNode.Value)
}
func TestGetMatchingNodes_EmptyContext(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create an empty context
context := Context{
MatchingNodes: list.New(),
}
// Create an expression node with self reference
expressionNode := &ExpressionNode{
Operation: &Operation{OperationType: selfReferenceOpType},
}
result, err := navigator.GetMatchingNodes(context, expressionNode)
test.AssertResult(t, nil, err)
test.AssertResult(t, 0, result.MatchingNodes.Len())
}
func TestDeeplyAssign_ComplexMappingMerge(t *testing.T) {
navigator := NewDataTreeNavigator()
// Create a context with a root mapping node containing nested data
rootNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "config", IsMapKey: true},
{Kind: MappingNode, Tag: "!!map", Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "existing_key", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "existing_value"},
}},
},
}
context := Context{
MatchingNodes: list.New(),
}
context.MatchingNodes.PushBack(rootNode)
// Create a mapping node to merge
mappingNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: []*CandidateNode{
{Kind: ScalarNode, Tag: "!!str", Value: "new_key", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "new_value"},
{Kind: ScalarNode, Tag: "!!str", Value: "existing_key", IsMapKey: true},
{Kind: ScalarNode, Tag: "!!str", Value: "updated_value"},
},
}
// Assign to path ["config"] (should merge with existing mapping)
path := []interface{}{"config"}
err := navigator.DeeplyAssign(context, path, mappingNode)
test.AssertResult(t, nil, err)
// Verify the merge was successful
configNode := rootNode.Content[1] // The config mapping node
test.AssertResult(t, 4, len(configNode.Content)) // Should have 2 key-value pairs
// Check that both existing and new keys are present
foundExisting := false
foundNew := false
for i := 0; i < len(configNode.Content); i += 2 {
if i+1 < len(configNode.Content) {
key := configNode.Content[i]
value := configNode.Content[i+1]
switch key.Value {
case "existing_key":
foundExisting = true
test.AssertResult(t, "updated_value", value.Value) // Should be updated
case "new_key":
foundNew = true
test.AssertResult(t, "new_value", value.Value)
}
}
}
test.AssertResult(t, true, foundExisting)
test.AssertResult(t, true, foundNew)
}
-56
View File
@@ -1,66 +1,10 @@
package yqlib
import (
"fmt"
"io"
"strings"
)
type InputFormat uint
const (
YamlInputFormat = 1 << iota
XMLInputFormat
PropertiesInputFormat
Base64InputFormat
JsonInputFormat
CSVObjectInputFormat
TSVObjectInputFormat
TomlInputFormat
UriInputFormat
LuaInputFormat
)
type Decoder interface {
Init(reader io.Reader) error
Decode() (*CandidateNode, error)
}
func InputFormatFromString(format string) (InputFormat, error) {
switch format {
case "yaml", "yml", "y":
return YamlInputFormat, nil
case "xml", "x":
return XMLInputFormat, nil
case "properties", "props", "p":
return PropertiesInputFormat, nil
case "json", "ndjson", "j":
return JsonInputFormat, nil
case "csv", "c":
return CSVObjectInputFormat, nil
case "tsv", "t":
return TSVObjectInputFormat, nil
case "toml":
return TomlInputFormat, nil
case "lua", "l":
return LuaInputFormat, nil
default:
return 0, fmt.Errorf("unknown format '%v' please use [yaml|json|props|csv|tsv|xml|toml]", 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"
}
+7 -13
View File
@@ -1,3 +1,5 @@
//go:build !yq_nobase64
package yqlib
import (
@@ -5,25 +7,23 @@ import (
"encoding/base64"
"io"
"strings"
yaml "gopkg.in/yaml.v3"
)
type base64Padder struct {
count uint64
count int
io.Reader
}
func (c *base64Padder) pad(buf []byte) (int, error) {
pad := strings.Repeat("=", int(4-c.count%4))
pad := strings.Repeat("=", (4 - c.count%4))
n, err := strings.NewReader(pad).Read(buf)
c.count += uint64(n)
c.count += n
return n, err
}
func (c *base64Padder) Read(buf []byte) (int, error) {
n, err := c.Reader.Read(buf)
c.count += uint64(n)
c.count += n
if err == io.EOF && c.count%4 != 0 {
return c.pad(buf)
@@ -70,11 +70,5 @@ func (dec *base64Decoder) Decode() (*CandidateNode, error) {
}
}
dec.readAnything = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: buf.String(),
},
}, nil
return createStringScalarNode(buf.String()), nil
}
+18 -23
View File
@@ -1,3 +1,5 @@
//go:build !yq_nocsv
package yqlib
import (
@@ -6,44 +8,42 @@ import (
"io"
"github.com/dimchansky/utfbom"
yaml "gopkg.in/yaml.v3"
)
type csvObjectDecoder struct {
separator rune
reader csv.Reader
finished bool
prefs CsvPreferences
reader csv.Reader
finished bool
}
func NewCSVObjectDecoder(separator rune) Decoder {
return &csvObjectDecoder{separator: separator}
func NewCSVObjectDecoder(prefs CsvPreferences) Decoder {
return &csvObjectDecoder{prefs: prefs}
}
func (dec *csvObjectDecoder) Init(reader io.Reader) error {
cleanReader, enc := utfbom.Skip(reader)
log.Debugf("Detected encoding: %s\n", enc)
dec.reader = *csv.NewReader(cleanReader)
dec.reader.Comma = dec.separator
dec.reader.Comma = dec.prefs.Separator
dec.finished = false
return nil
}
func (dec *csvObjectDecoder) convertToYamlNode(content string) *yaml.Node {
func (dec *csvObjectDecoder) convertToNode(content string) *CandidateNode {
node, err := parseSnippet(content)
if err != nil {
// if we're not auto-parsing, then we wont put in parsed objects or arrays
// but we still parse scalars
if err != nil || (!dec.prefs.AutoParse && (node.Kind != ScalarNode || node.Value != content)) {
return createScalarNode(content, content)
}
return node
}
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *yaml.Node {
objectNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *CandidateNode {
objectNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"}
for i, header := range headerRow {
objectNode.Content = append(
objectNode.Content,
createScalarNode(header, header),
dec.convertToYamlNode(contentRow[i]))
objectNode.AddKeyValueChild(createScalarNode(header, header), dec.convertToNode(contentRow[i]))
}
return objectNode
}
@@ -58,13 +58,13 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
rootArray := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
rootArray := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
contentRow, err := dec.reader.Read()
for err == nil && len(contentRow) > 0 {
log.Debugf("Adding contentRow: %v", contentRow)
rootArray.Content = append(rootArray.Content, dec.createObject(headerRow, contentRow))
rootArray.AddChild(dec.createObject(headerRow, contentRow))
contentRow, err = dec.reader.Read()
log.Debugf("Read next contentRow: %v, %v", contentRow, err)
}
@@ -72,10 +72,5 @@ func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{rootArray},
},
}, nil
return rootArray, nil
}
+49
View File
@@ -0,0 +1,49 @@
//go:build !yq_noyaml
//
// NOTE this is still a WIP - not yet ready.
//
package yqlib
import (
"io"
yaml "github.com/goccy/go-yaml"
"github.com/goccy/go-yaml/ast"
)
type goccyYamlDecoder struct {
decoder yaml.Decoder
cm yaml.CommentMap
// anchor map persists over multiple documents for convenience.
anchorMap map[string]*CandidateNode
}
func NewGoccyYAMLDecoder() Decoder {
return &goccyYamlDecoder{}
}
func (dec *goccyYamlDecoder) Init(reader io.Reader) error {
dec.cm = yaml.CommentMap{}
dec.decoder = *yaml.NewDecoder(reader, yaml.CommentToMap(dec.cm), yaml.UseOrderedMap())
dec.anchorMap = make(map[string]*CandidateNode)
return nil
}
func (dec *goccyYamlDecoder) Decode() (*CandidateNode, error) {
var ast ast.Node
err := dec.decoder.Decode(&ast)
if err != nil {
return nil, err
}
candidateNode := &CandidateNode{}
if err := candidateNode.UnmarshalGoccyYAML(ast, dec.cm, dec.anchorMap); err != nil {
return nil, err
}
return candidateNode, nil
}
+106
View File
@@ -0,0 +1,106 @@
//go:build !yq_noini
package yqlib
import (
"fmt"
"io"
"github.com/go-ini/ini"
)
type iniDecoder struct {
reader io.Reader
finished bool // Flag to signal completion of processing
}
func NewINIDecoder() Decoder {
return &iniDecoder{
finished: false, // Initialize the flag as false
}
}
func (dec *iniDecoder) Init(reader io.Reader) error {
// Store the reader for use in Decode
dec.reader = reader
return nil
}
func (dec *iniDecoder) Decode() (*CandidateNode, error) {
// If processing is already finished, return io.EOF
if dec.finished {
return nil, io.EOF
}
// Read all content from the stored reader
content, err := io.ReadAll(dec.reader)
if err != nil {
return nil, fmt.Errorf("failed to read INI content: %w", err)
}
// Parse the INI content
cfg, err := ini.Load(content)
if err != nil {
return nil, fmt.Errorf("failed to parse INI content: %w", err)
}
// Create a root CandidateNode as a MappingNode (since INI is key-value based)
root := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Value: "",
}
// Process each section in the INI file
for _, section := range cfg.Sections() {
sectionName := section.Name()
if sectionName == ini.DefaultSection {
// For the default section, add key-value pairs directly to the root node
for _, key := range section.Keys() {
keyName := key.Name()
keyValue := key.String()
// Create a key node (scalar for the key name)
keyNode := createStringScalarNode(keyName)
// Create a value node (scalar for the value)
valueNode := createStringScalarNode(keyValue)
// Add key-value pair to the root node
root.AddKeyValueChild(keyNode, valueNode)
}
} else {
// For named sections, create a nested map
sectionNode := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Value: "",
}
// Add key-value pairs to the section node
for _, key := range section.Keys() {
keyName := key.Name()
keyValue := key.String()
// Create a key node (scalar for the key name)
keyNode := createStringScalarNode(keyName)
// Create a value node (scalar for the value)
valueNode := createStringScalarNode(keyValue)
// Add key-value pair to the section node
sectionNode.AddKeyValueChild(keyNode, valueNode)
}
// Create a key node for the section name
sectionKeyNode := createStringScalarNode(sectionName)
// Add the section as a nested map to the root node
root.AddKeyValueChild(sectionKeyNode, sectionNode)
}
}
// Set the finished flag to true to prevent further Decode calls
dec.finished = true
// Return the root node
return root, nil
}
+2 -69
View File
@@ -3,11 +3,9 @@
package yqlib
import (
"fmt"
"io"
"github.com/goccy/go-json"
yaml "gopkg.in/yaml.v3"
)
type jsonDecoder struct {
@@ -25,76 +23,11 @@ func (dec *jsonDecoder) Init(reader io.Reader) error {
func (dec *jsonDecoder) Decode() (*CandidateNode, error) {
var dataBucket orderedMap
log.Debug("going to decode")
var dataBucket CandidateNode
err := dec.decoder.Decode(&dataBucket)
if err != nil {
return nil, err
}
node, err := dec.convertToYamlNode(&dataBucket)
if err != nil {
return nil, err
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{node},
},
}, nil
}
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
case int, int64, int32, string, bool:
return createScalarNode(rawData, fmt.Sprintf("%v", rawData)), nil
case []*orderedMap:
return dec.parseArray(rawData)
default:
return nil, fmt.Errorf("unrecognised type :( %v", rawData)
}
}
var yamlMap = &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
for i, keyValuePair := range data.kv {
yamlValue, err := dec.convertToYamlNode(&data.kv[i].V)
if err != nil {
return nil, err
}
yamlMap.Content = append(yamlMap.Content, createScalarNode(keyValuePair.K, keyValuePair.K), yamlValue)
}
return yamlMap, nil
}
func (dec *jsonDecoder) parseArray(dataArray []*orderedMap) (*yaml.Node, error) {
var yamlMap = &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
for _, value := range dataArray {
yamlValue, err := dec.convertToYamlNode(value)
if err != nil {
return nil, err
}
yamlMap.Content = append(yamlMap.Content, yamlValue)
}
return yamlMap, nil
return &dataBucket, nil
}
+32 -36
View File
@@ -8,7 +8,6 @@ import (
"math"
lua "github.com/yuin/gopher-lua"
yaml "gopkg.in/yaml.v3"
)
type luaDecoder struct {
@@ -28,17 +27,17 @@ func (dec *luaDecoder) Init(reader io.Reader) error {
return nil
}
func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.Node {
func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *CandidateNode {
switch lv.Type() {
case lua.LTNil:
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!null",
Value: "",
}
case lua.LTBool:
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!bool",
Value: lv.String(),
}
@@ -46,22 +45,22 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
n := float64(lua.LVAsNumber(lv))
// various special case floats
if math.IsNaN(n) {
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!float",
Value: ".nan",
}
}
if math.IsInf(n, 1) {
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!float",
Value: ".inf",
}
}
if math.IsInf(n, -1) {
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!float",
Value: "-.inf",
}
@@ -69,27 +68,27 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
// does it look like an integer?
if n == float64(int(n)) {
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!int",
Value: lv.String(),
}
}
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!float",
Value: lv.String(),
}
case lua.LTString:
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "!!str",
Value: lv.String(),
}
case lua.LTFunction:
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
Tag: "tag:lua.org,2006,function",
Value: lv.String(),
}
@@ -97,12 +96,12 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
// Simultaneously create a sequence and a map, pick which one to return
// based on whether all keys were consecutive integers
i := 1
yaml_sequence := &yaml.Node{
Kind: yaml.SequenceNode,
yaml_sequence := &CandidateNode{
Kind: SequenceNode,
Tag: "!!seq",
}
yaml_map := &yaml.Node{
Kind: yaml.MappingNode,
yaml_map := &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
}
t := lv.(*lua.LTable)
@@ -113,11 +112,13 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
} else {
i = 0
}
yaml_map.Content = append(yaml_map.Content, dec.convertToYamlNode(ls, k))
newKey := dec.convertToYamlNode(ls, k)
yv := dec.convertToYamlNode(ls, v)
yaml_map.Content = append(yaml_map.Content, yv)
yaml_map.AddKeyValueChild(newKey, yv)
if i != 0 {
yaml_sequence.Content = append(yaml_sequence.Content, yv)
yaml_sequence.AddChild(yv)
}
k, v = ls.Next(t, k)
}
@@ -126,8 +127,8 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
}
return yaml_map
default:
return &yaml.Node{
Kind: yaml.ScalarNode,
return &CandidateNode{
Kind: ScalarNode,
LineComment: fmt.Sprintf("Unhandled Lua type: %s", lv.Type().String()),
Tag: "!!null",
Value: lv.String(),
@@ -135,7 +136,7 @@ func (dec *luaDecoder) convertToYamlNode(ls *lua.LState, lv lua.LValue) *yaml.No
}
}
func (dec *luaDecoder) decideTopLevelNode(ls *lua.LState) *yaml.Node {
func (dec *luaDecoder) decideTopLevelNode(ls *lua.LState) *CandidateNode {
if ls.GetTop() == 0 {
// no items were explicitly returned, encode the globals table instead
return dec.convertToYamlNode(ls, ls.Get(lua.GlobalsIndex))
@@ -160,10 +161,5 @@ func (dec *luaDecoder) Decode() (*CandidateNode, error) {
}
firstNode := dec.decideTopLevelNode(ls)
dec.finished = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{firstNode},
},
}, nil
return firstNode, nil
}
+12 -26
View File
@@ -1,3 +1,5 @@
//go:build !yq_noprops
package yqlib
import (
@@ -8,7 +10,6 @@ import (
"strings"
"github.com/magiconair/properties"
"gopkg.in/yaml.v3"
)
type propertiesDecoder struct {
@@ -52,16 +53,13 @@ func (dec *propertiesDecoder) applyPropertyComments(context Context, path []inte
assignmentOp := &Operation{OperationType: assignOpType, Preferences: assignPreferences{}}
rhsCandidateNode := &CandidateNode{
Path: path,
Node: &yaml.Node{
Tag: "!!str",
Value: fmt.Sprintf("%v", path[len(path)-1]),
HeadComment: dec.processComment(strings.Join(comments, "\n")),
Kind: yaml.ScalarNode,
},
Tag: "!!str",
Value: fmt.Sprintf("%v", path[len(path)-1]),
HeadComment: dec.processComment(strings.Join(comments, "\n")),
Kind: ScalarNode,
}
rhsCandidateNode.Node.Tag = guessTagFromCustomType(rhsCandidateNode.Node)
rhsCandidateNode.Tag = rhsCandidateNode.guessTagFromCustomType()
rhsOp := &Operation{OperationType: referenceOpType, CandidateNode: rhsCandidateNode}
@@ -87,13 +85,8 @@ func (dec *propertiesDecoder) applyProperty(context Context, properties *propert
}
}
rhsNode := &yaml.Node{
Value: value,
Tag: "!!str",
Kind: yaml.ScalarNode,
}
rhsNode.Tag = guessTagFromCustomType(rhsNode)
rhsNode := createStringScalarNode(value)
rhsNode.Tag = rhsNode.guessTagFromCustomType()
return dec.d.DeeplyAssign(context, path, rhsNode)
}
@@ -118,10 +111,8 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) {
properties.DisableExpansion = true
rootMap := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
}
context := Context{}
@@ -135,11 +126,6 @@ func (dec *propertiesDecoder) Decode() (*CandidateNode, error) {
}
dec.finished = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{rootMap.Node},
},
}, nil
return rootMap, nil
}
+7 -1
View File
@@ -27,11 +27,14 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) (
decoder = NewYamlDecoder(ConfiguredYamlPreferences)
}
log.Debugf("reading docs")
inputs, err := readDocuments(strings.NewReader(s.input), "sample.yml", 0, decoder)
if err != nil {
return "", err
}
log.Debugf("done reading the documents")
expression := s.expression
if expression == "" {
expression = "."
@@ -45,6 +48,8 @@ func processFormatScenario(s formatScenario, decoder Decoder, encoder Encoder) (
context, err := NewDataTreeNavigator().GetMatchingNodes(Context{MatchingNodes: inputs}, exp)
log.Debugf("Going to print: %v", NodesToString(context.MatchingNodes))
if err != nil {
return "", err
}
@@ -63,7 +68,8 @@ func mustProcessFormatScenario(s formatScenario, decoder Decoder, encoder Encode
result, err := processFormatScenario(s, decoder, encoder)
if err != nil {
panic(fmt.Errorf("Bad scenario %v: %w", s.description, err))
log.Error("Bad scenario %v: %w", s.description, err)
return fmt.Sprintf("Bad scenario %v: %v", s.description, err.Error())
}
return result
+71 -82
View File
@@ -11,7 +11,6 @@ import (
"time"
toml "github.com/pelletier/go-toml/v2/unstable"
yaml "gopkg.in/yaml.v3"
)
type tomlDecoder struct {
@@ -37,10 +36,9 @@ func (dec *tomlDecoder) Init(reader io.Reader) error {
}
dec.parser.Reset(buf.Bytes())
dec.rootMap = &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
}}
Kind: MappingNode,
Tag: "!!map",
}
return nil
}
@@ -58,12 +56,13 @@ func (dec *tomlDecoder) getFullPath(tomlNode *toml.Node) []interface{} {
func (dec *tomlDecoder) processKeyValueIntoMap(rootMap *CandidateNode, tomlNode *toml.Node) error {
value := tomlNode.Value()
path := dec.getFullPath(value.Next())
log.Debug("!!!processKeyValueIntoMap: %v", path)
log.Debug("processKeyValueIntoMap: %v", path)
valueNode, err := dec.decodeNode(value)
if err != nil {
return err
}
context := Context{}
context = context.SingleChildContext(rootMap)
@@ -71,14 +70,14 @@ func (dec *tomlDecoder) processKeyValueIntoMap(rootMap *CandidateNode, tomlNode
}
func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode *toml.Node) (bool, error) {
log.Debug("!! DECODE_KV_INTO_MAP -- processing first (current) entry")
log.Debug("decodeKeyValuesIntoMap -- 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)
log.Debug("decodeKeyValuesIntoMap -- next exp, its a %v", nextItem.Kind)
if nextItem.Kind == toml.KeyValue {
if err := dec.processKeyValueIntoMap(rootMap, nextItem); err != nil {
@@ -86,18 +85,17 @@ func (dec *tomlDecoder) decodeKeyValuesIntoMap(rootMap *CandidateNode, tomlNode
}
} 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!")
log.Debug("done in decodeKeyValuesIntoMap, gota a %v", nextItem.Kind)
return true, nil
}
}
log.Debug("! DECODE_KV_INTO_MAP - no more things to read in")
log.Debug("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")
func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNode, error) {
content := make([]*CandidateNode, 0)
log.Debug("createInlineTableMap")
iterator := tomlNode.Children()
for iterator.Next() {
@@ -107,28 +105,26 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*yaml.Node, e
}
keyValues := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
}
if err := dec.processKeyValueIntoMap(keyValues, child); err != nil {
return nil, err
}
content = append(content, keyValues.Node.Content...)
content = append(content, keyValues.Content...)
}
return &yaml.Node{
Kind: yaml.MappingNode,
return &CandidateNode{
Kind: MappingNode,
Tag: "!!map",
Content: content,
}, nil
}
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) {
content := make([]*yaml.Node, 0)
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error) {
content := make([]*CandidateNode, 0)
iterator := tomlNode.Children()
for iterator.Next() {
child := iterator.Node()
@@ -139,43 +135,43 @@ func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*yaml.Node, error) {
content = append(content, yamlNode)
}
return &yaml.Node{
Kind: yaml.SequenceNode,
return &CandidateNode{
Kind: SequenceNode,
Tag: "!!seq",
Content: content,
}, nil
}
func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createStringScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
return createScalarNode(content, content), nil
}
func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createBoolScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
return createScalarNode(content == "true", content), nil
}
func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createIntegerScalar(tomlNode *toml.Node) (*CandidateNode, error) {
content := string(tomlNode.Data)
_, num, err := parseInt64(content)
return createScalarNode(num, content), err
}
func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*yaml.Node, error) {
func (dec *tomlDecoder) createDateTimeScalar(tomlNode *toml.Node) (*CandidateNode, 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) {
func (dec *tomlDecoder) createFloatScalar(tomlNode *toml.Node) (*CandidateNode, 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) {
func (dec *tomlDecoder) decodeNode(tomlNode *toml.Node) (*CandidateNode, error) {
switch tomlNode.Kind {
case toml.Key, toml.String:
return dec.createStringScalar(tomlNode)
@@ -241,81 +237,76 @@ func (dec *tomlDecoder) Decode() (*CandidateNode, error) {
// must have finished
dec.finished = true
if len(dec.rootMap.Node.Content) == 0 {
if len(dec.rootMap.Content) == 0 {
return nil, io.EOF
}
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{dec.rootMap.Node},
},
}, deferredError
return dec.rootMap, 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 {
log.Debug("processTopLevelNode: Going to process %v state is current %v", currentNode.Kind, NodeToString(dec.rootMap))
switch currentNode.Kind {
case toml.Table:
runAgainstCurrentExp, err = dec.processTable(currentNode)
case toml.ArrayTable:
runAgainstCurrentExp, err = dec.processArrayTable(currentNode)
default:
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(dec.rootMap, currentNode)
}
log.Debug("!!!!!!!!!!!!DONE Processing state is now %v", NodeToString(dec.rootMap))
log.Debug("processTopLevelNode: 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")
log.Debug("Enter processTable")
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())
}
log.Debug("fullpath: %v", fullPath)
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: MappingNode,
Tag: "!!map",
Content: make([]*CandidateNode, 0),
}
tableValue := dec.parser.Expression()
if tableValue.Kind != toml.KeyValue {
log.Debug("got an empty table, returning")
return true, nil
var tableValue *toml.Node
runAgainstCurrentExp := false
var err error
hasValue := dec.parser.NextExpression()
// check to see if there is any table data
if hasValue {
tableValue = dec.parser.Expression()
// next expression is not table data, so we are done
if tableValue.Kind != toml.KeyValue {
log.Debug("got an empty table, returning")
return true, nil
}
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
if err != nil && !errors.Is(err, io.EOF) {
return false, err
}
}
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)
err = dec.d.DeeplyAssign(c, fullPath, tableNodeValue)
if err != nil {
return false, err
}
return runAgainstCurrentExp, nil
}
func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *yaml.Node) error {
func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode *CandidateNode) error {
log.Debug("arrayAppend to path: %v,%v", path, NodeToString(rhsNode))
rhsCandidateNode := &CandidateNode{
Path: path,
Node: &yaml.Node{
Kind: yaml.SequenceNode,
Tag: "!!seq",
Content: []*yaml.Node{rhsNode},
},
Kind: SequenceNode,
Tag: "!!seq",
Content: []*CandidateNode{rhsNode},
}
assignmentOp := &Operation{OperationType: addAssignOpType}
@@ -333,9 +324,9 @@ func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode
}
func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) {
log.Debug("!!! processing table")
log.Debug("Entering processArrayTable")
fullPath := dec.getFullPath(currentNode.Child())
log.Debug("!!!fullpath: %v", fullPath)
log.Debug("Fullpath: %v", fullPath)
// need to use the array append exp to add another entry to
// this array: fullpath += [ thing ]
@@ -346,16 +337,14 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error)
}
tableNodeValue := &CandidateNode{
Node: &yaml.Node{
Kind: yaml.MappingNode,
Tag: "!!map",
},
Kind: 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) {
if err != nil && !errors.Is(err, io.EOF) {
return false, err
}
c := Context{}
@@ -363,7 +352,7 @@ func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error)
c = c.SingleChildContext(dec.rootMap)
// += function
err = dec.arrayAppend(c, fullPath, tableNodeValue.Node)
err = dec.arrayAppend(c, fullPath, tableNodeValue)
return runAgainstCurrentExp, err
}
+3 -9
View File
@@ -1,11 +1,11 @@
//go:build !yq_nouri
package yqlib
import (
"bytes"
"io"
"net/url"
yaml "gopkg.in/yaml.v3"
)
type uriDecoder struct {
@@ -50,11 +50,5 @@ func (dec *uriDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
dec.readAnything = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.ScalarNode,
Tag: "!!str",
Value: newValue,
},
}, nil
return createStringScalarNode(newValue), nil
}
+22 -23
View File
@@ -12,7 +12,6 @@ import (
"unicode"
"golang.org/x/net/html/charset"
yaml "gopkg.in/yaml.v3"
)
type xmlDecoder struct {
@@ -36,14 +35,14 @@ func (dec *xmlDecoder) Init(reader io.Reader) error {
return nil
}
func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*yaml.Node, error) {
yamlNode := &yaml.Node{Kind: yaml.SequenceNode, Tag: "!!seq"}
func (dec *xmlDecoder) createSequence(nodes []*xmlNode) (*CandidateNode, error) {
yamlNode := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
for _, child := range nodes {
yamlChild, err := dec.convertToYamlNode(child)
if err != nil {
return nil, err
}
yamlNode.Content = append(yamlNode.Content, yamlChild)
yamlNode.AddChild(yamlChild)
}
return yamlNode, nil
@@ -64,9 +63,9 @@ func (dec *xmlDecoder) processComment(c string) string {
return replacement
}
func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
func (dec *xmlDecoder) createMap(n *xmlNode) (*CandidateNode, error) {
log.Debug("createMap: headC: %v, lineC: %v, footC: %v", n.HeadComment, n.LineComment, n.FootComment)
yamlNode := &yaml.Node{Kind: yaml.MappingNode, Tag: "!!map"}
yamlNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"}
if len(n.Data) > 0 {
log.Debugf("creating content node for map: %v", dec.prefs.ContentName)
@@ -75,14 +74,14 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
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.AddKeyValueChild(labelNode, dec.createValueNodeFromData(n.Data))
}
for i, keyValuePair := range n.Children {
label := keyValuePair.K
children := keyValuePair.V
labelNode := createScalarNode(label, label)
var valueNode *yaml.Node
var valueNode *CandidateNode
var err error
if i == 0 {
@@ -120,32 +119,32 @@ func (dec *xmlDecoder) createMap(n *xmlNode) (*yaml.Node, error) {
return nil, err
}
}
yamlNode.Content = append(yamlNode.Content, labelNode, valueNode)
yamlNode.AddKeyValueChild(labelNode, valueNode)
}
return yamlNode, nil
}
func (dec *xmlDecoder) createValueNodeFromData(values []string) *yaml.Node {
func (dec *xmlDecoder) createValueNodeFromData(values []string) *CandidateNode {
switch len(values) {
case 0:
return createScalarNode(nil, "")
case 1:
return createScalarNode(values[0], values[0])
default:
content := make([]*yaml.Node, 0)
content := make([]*CandidateNode, 0)
for _, value := range values {
content = append(content, createScalarNode(value, value))
}
return &yaml.Node{
Kind: yaml.SequenceNode,
return &CandidateNode{
Kind: SequenceNode,
Tag: "!!seq",
Content: content,
}
}
}
func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*yaml.Node, error) {
func (dec *xmlDecoder) convertToYamlNode(n *xmlNode) (*CandidateNode, error) {
if len(n.Children) > 0 {
return dec.createMap(n)
}
@@ -189,12 +188,7 @@ func (dec *xmlDecoder) Decode() (*CandidateNode, error) {
dec.readAnything = true
dec.finished = true
return &CandidateNode{
Node: &yaml.Node{
Kind: yaml.DocumentNode,
Content: []*yaml.Node{firstNode},
},
}, nil
return firstNode, nil
}
type xmlNode struct {
@@ -305,6 +299,10 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
log.Debug("chardata [%v] for %v", elem.n.Data, elem.label)
}
case xml.EndElement:
if elem == nil {
log.Debug("no element, probably bad xml")
continue
}
log.Debug("end element %v", elem.label)
elem.state = "finished"
// And add it to its parent list
@@ -317,13 +315,14 @@ func (dec *xmlDecoder) decodeXML(root *xmlNode) error {
case xml.Comment:
commentStr := string(xml.CharData(se))
if elem.state == "started" {
switch elem.state {
case "started":
applyFootComment(elem, commentStr)
} else if elem.state == "chardata" {
case "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}, " ")
} else {
default:
log.Debug("got a head comment for (%v) %v: [%v]", elem.state, elem.label, commentStr)
elem.n.HeadComment = joinComments([]string{elem.n.HeadComment, commentStr}, " ")
}
+35 -21
View File
@@ -8,7 +8,7 @@ import (
"regexp"
"strings"
yaml "gopkg.in/yaml.v3"
yaml "go.yaml.in/yaml/v3"
)
type yamlDecoder struct {
@@ -20,8 +20,12 @@ type yamlDecoder struct {
leadingContent string
bufferRead bytes.Buffer
readAnything bool
firstFile bool
// anchor map persists over multiple documents for convenience.
anchorMap map[string]*CandidateNode
readAnything bool
firstFile bool
documentIndex uint
}
func NewYamlDecoder(prefs YamlPreferences) Decoder {
@@ -33,7 +37,7 @@ func (dec *yamlDecoder) processReadStream(reader *bufio.Reader) (io.Reader, stri
var yamlDirectiveLineRegEx = regexp.MustCompile(`^\s*%YA`)
var sb strings.Builder
for {
peekBytes, err := reader.Peek(3)
peekBytes, err := reader.Peek(4)
if errors.Is(err, io.EOF) {
// EOF are handled else where..
return reader, sb.String(), nil
@@ -47,7 +51,15 @@ func (dec *yamlDecoder) processReadStream(reader *bufio.Reader) (io.Reader, stri
} else if err != nil {
return reader, sb.String(), err
}
} else if string(peekBytes) == "---" {
} else if string(peekBytes) == "--- " {
_, err := reader.ReadString(' ')
sb.WriteString("$yqDocSeparator$\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) == "---\n" {
_, err := reader.ReadString('\n')
sb.WriteString("$yqDocSeparator$\n")
if errors.Is(err, io.EOF) {
@@ -93,12 +105,15 @@ func (dec *yamlDecoder) Init(reader io.Reader) error {
dec.readAnything = false
dec.decoder = *yaml.NewDecoder(readerToUse)
dec.firstFile = false
dec.documentIndex = 0
dec.anchorMap = make(map[string]*CandidateNode)
return nil
}
func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
var dataBucket yaml.Node
err := dec.decoder.Decode(&dataBucket)
var yamlNode yaml.Node
err := dec.decoder.Decode(&yamlNode)
if errors.Is(err, io.EOF) && dec.leadingContent != "" && !dec.readAnything {
// force returning an empty node with a comment.
dec.readAnything = true
@@ -116,28 +131,27 @@ func (dec *yamlDecoder) Decode() (*CandidateNode, error) {
return nil, err
}
candidateNode := &CandidateNode{
Node: &dataBucket,
candidateNode := CandidateNode{document: dec.documentIndex}
// don't bother with the DocumentNode
err = candidateNode.UnmarshalYAML(yamlNode.Content[0], dec.anchorMap)
if err != nil {
return nil, err
}
candidateNode.HeadComment = yamlNode.HeadComment + candidateNode.HeadComment
candidateNode.FootComment = yamlNode.FootComment + candidateNode.FootComment
if dec.leadingContent != "" {
candidateNode.LeadingContent = dec.leadingContent
dec.leadingContent = ""
}
dec.readAnything = true
// move document comments into candidate node
// otherwise unwrap drops them.
candidateNode.TrailingContent = dataBucket.FootComment
dataBucket.FootComment = ""
return candidateNode, nil
dec.documentIndex++
return &candidateNode, nil
}
func (dec *yamlDecoder) blankNodeWithComment() *CandidateNode {
return &CandidateNode{
Document: 0,
Filename: "",
Node: &yaml.Node{Kind: yaml.DocumentNode, Content: []*yaml.Node{{Tag: "!!null", Kind: yaml.ScalarNode}}},
FileIndex: 0,
LeadingContent: dec.leadingContent,
}
node := createScalarNode(nil, "")
node.LeadingContent = dec.leadingContent
return node
}
@@ -34,68 +34,6 @@ y: 2
r: 10
```
## Merge multiple maps
see https://yaml.org/type/merge.html
Given a sample.yml file of:
```yaml
- &CENTER
x: 1
y: 2
- &LEFT
x: 0
y: 2
- &BIG
r: 10
- &SMALL
r: 1
- !!merge <<:
- *CENTER
- *BIG
```
then
```bash
yq '.[4] | explode(.)' sample.yml
```
will output
```yaml
r: 10
x: 1
y: 2
```
## Override
see https://yaml.org/type/merge.html
Given a sample.yml file of:
```yaml
- &CENTER
x: 1
y: 2
- &LEFT
x: 0
y: 2
- &BIG
r: 10
- &SMALL
r: 1
- !!merge <<:
- *BIG
- *LEFT
- *SMALL
x: 1
```
then
```bash
yq '.[4] | explode(.)' sample.yml
```
will output
```yaml
r: 10
x: 1
y: 2
```
## Get anchor
Given a sample.yml file of:
```yaml
@@ -254,7 +192,101 @@ f:
cat: b
```
## Explode with merge anchors
## Dereference and update a field
Use explode with multiply to dereference an object
Given a sample.yml file of:
```yaml
item_value: &item_value
value: true
thingOne:
name: item_1
!!merge <<: *item_value
thingTwo:
name: item_2
!!merge <<: *item_value
```
then
```bash
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
```
will output
```yaml
item_value: &item_value
value: true
thingOne:
name: item_1
value: false
thingTwo:
name: item_2
!!merge <<: *item_value
```
## Merge multiple maps
see https://yaml.org/type/merge.html
Given a sample.yml file of:
```yaml
- &CENTER
x: 1
y: 2
- &LEFT
x: 0
y: 2
- &BIG
r: 10
- &SMALL
r: 1
- !!merge <<:
- *CENTER
- *BIG
```
then
```bash
yq '.[4] | explode(.)' sample.yml
```
will output
```yaml
r: 10
x: 1
y: 2
```
## Override
see https://yaml.org/type/merge.html
Given a sample.yml file of:
```yaml
- &CENTER
x: 1
y: 2
- &LEFT
x: 0
y: 2
- &BIG
r: 10
- &SMALL
r: 1
- !!merge <<:
- *BIG
- *LEFT
- *SMALL
x: 1
```
then
```bash
yq '.[4] | explode(.)' sample.yml
```
will output
```yaml
r: 10
x: 1
y: 2
```
## LEGACY: Explode with merge anchors
Caution: this is for when --yaml-fix-merge-anchor-to-spec=false; it's not to YAML spec because the merge anchors incorrectly override the object values. Flag will default to true in late 2025
Given a sample.yml file of:
```yaml
foo: &foo
@@ -301,33 +333,52 @@ foobar:
thing: foobar_thing
```
## Dereference and update a field
Use explode with multiply to dereference an object
## FIXED: Explode with merge anchors
Set `--yaml-fix-merge-anchor-to-spec=true` to get this correct merge behaviour. Flag will default to true in late 2025
Given a sample.yml file of:
```yaml
item_value: &item_value
value: true
thingOne:
name: item_1
!!merge <<: *item_value
thingTwo:
name: item_2
!!merge <<: *item_value
foo: &foo
a: foo_a
thing: foo_thing
c: foo_c
bar: &bar
b: bar_b
thing: bar_thing
c: bar_c
foobarList:
b: foobarList_b
!!merge <<:
- *foo
- *bar
c: foobarList_c
foobar:
c: foobar_c
!!merge <<: *foo
thing: foobar_thing
```
then
```bash
yq '.thingOne |= explode(.) * {"value": false}' sample.yml
yq 'explode(.)' sample.yml
```
will output
```yaml
item_value: &item_value
value: true
thingOne:
name: item_1
value: false
thingTwo:
name: item_2
!!merge <<: *item_value
foo:
a: foo_a
thing: foo_thing
c: foo_c
bar:
b: bar_b
thing: bar_thing
c: bar_c
foobarList:
b: foobarList_b
a: foo_a
thing: foo_thing
c: foobarList_c
foobar:
c: foobar_c
a: foo_a
thing: foobar_thing
```
+1 -1
View File
@@ -4,7 +4,7 @@ The `or` and `and` operators take two parameters and return a boolean result.
`not` flips a boolean from true to false, or vice versa.
`any` will return `true` if there are any `true` values in a array sequence, and `all` will return true if _all_ elements in an array are true.
`any` will return `true` if there are any `true` values in an array sequence, and `all` will return true if _all_ elements in an array are true.
`any_c(condition)` and `all_c(condition)` are like `any` and `all` but they take a condition expression that is used against each element to determine if it's `true`. Note: in `jq` you can simply pass a condition to `any` or `all` and it simply works - `yq` isn't that clever..yet
+2
View File
@@ -2,6 +2,8 @@
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
Column is the number of characters that precede that node on the line it starts.
## Returns column of _value_ node
Given a sample.yml file of:
```yaml
@@ -187,7 +187,6 @@ yq '. head_comment="single"' sample.yml
will output
```yaml
# single
a: cat
```
@@ -66,6 +66,7 @@ will output
```yaml
Mike: cat
Mike: dog
---
Rosey: monkey
Rosey: sheep
```
@@ -85,6 +85,7 @@ will output
```yaml
match: cat
doc: 0
---
match: frog
doc: 1
```
+24
View File
@@ -2,6 +2,8 @@
Similar to the same named functions in `jq` these functions convert to/from an object and an array of key-value pairs. This is most useful for performing operations on keys of maps.
Use `with_entries(op)` as a syntactic sugar for doing `to_entries | op | from_entries`.
## to_entries Map
Given a sample.yml file of:
```yaml
@@ -101,6 +103,28 @@ KEY_a: 1
KEY_b: 2
```
## Use with_entries to update keys recursively
We use (.. | select(tag="map")) to find all the maps in the doc, then |= to update each one of those maps. In the update, with_entries is used.
Given a sample.yml file of:
```yaml
a: 1
b:
b_a: nested
b_b: thing
```
then
```bash
yq '(.. | select(tag=="!!map")) |= with_entries(.key |= "KEY_" + .)' sample.yml
```
will output
```yaml
KEY_a: 1
KEY_b:
KEY_b_a: nested
KEY_b_b: thing
```
## Custom sort map keys
Use to_entries to convert to an array of key/value pairs, sort the array using sort/sort_by/etc, and convert it back.
@@ -54,7 +54,6 @@ yq eval-all 'file_index' sample.yml another.yml
will output
```yaml
0
---
1
```
+2 -2
View File
@@ -1,5 +1,5 @@
# NAME
*yq* is a portable command-line YAML processor
*yq* is a portable command-line data file processor
# SYNOPSIS
@@ -11,7 +11,7 @@ eval-all/ea - Loads all yaml documents of all yaml files and runs expression onc
# DESCRIPTION
a lightweight and portable command-line YAML processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml files as well as json. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
a lightweight and portable command-line data file processor. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml, json, xml, csv, properties and TOML files. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
This documentation is also available at https://mikefarah.gitbook.io/yq/
# QUICK GUIDE
@@ -4,7 +4,7 @@ The `or` and `and` operators take two parameters and return a boolean result.
`not` flips a boolean from true to false, or vice versa.
`any` will return `true` if there are any `true` values in a array sequence, and `all` will return true if _all_ elements in an array are true.
`any` will return `true` if there are any `true` values in an array sequence, and `all` will return true if _all_ elements in an array are true.
`any_c(condition)` and `all_c(condition)` are like `any` and `all` but they take a condition expression that is used against each element to determine if it's `true`. Note: in `jq` you can simply pass a condition to `any` or `all` and it simply works - `yq` isn't that clever..yet
@@ -1,3 +1,5 @@
# Column
Returns the column of the matching node. Starts from 1, 0 indicates there was no column data.
Column is the number of characters that precede that node on the line it starts.
@@ -1,3 +1,5 @@
# Entries
Similar to the same named functions in `jq` these functions convert to/from an object and an array of key-value pairs. This is most useful for performing operations on keys of maps.
Use `with_entries(op)` as a syntactic sugar for doing `to_entries | op | from_entries`.
+7
View File
@@ -0,0 +1,7 @@
# Kind
The `kind` operator identifies the type of a node as either `scalar`, `map`, or `seq`.
This can be used for filtering or transforming nodes based on their type.
Note that `null` values are treated as `scalar`.
+3
View File
@@ -0,0 +1,3 @@
# Max
Computes the maximum among an incoming sequence of scalar values.
+3
View File
@@ -0,0 +1,3 @@
# Min
Computes the minimum among an incoming sequence of scalar values.
@@ -3,7 +3,9 @@
Like the multiple operator in jq, depending on the operands, this multiply operator will do different things. Currently numbers, arrays and objects are supported.
## Objects and arrays - merging
Objects are merged deeply matching on matching keys. By default, array values override and are not deeply merged.
Objects are merged _deeply_ matching on matching keys. By default, array values override and are not deeply merged.
You can use the add operator `+`, to shallow merge objects, see more info [here](https://mikefarah.gitbook.io/yq/operators/add).
Note that when merging objects, this operator returns the merged object (not the parent). This will be clearer in the examples below.
@@ -16,6 +18,7 @@ You can control how objects are merged by using one or more of the following fla
- `n` only merge _new_ fields
- `c` clobber custom tags
To perform a shallow merge only, use the add operator `+`, see more info [here](https://mikefarah.gitbook.io/yq/operators/add).
### Merge two files together
This uses the load operator to merge file2 into file1.
+3
View File
@@ -0,0 +1,3 @@
# Omit
Works like `pick`, but instead you specify the keys/indices that you _don't_ want included.
+3
View File
@@ -0,0 +1,3 @@
# Pivot
Emulates the `PIVOT` function supported by several popular RDBMS systems.
@@ -2,4 +2,4 @@
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.
You may leave out the first or second number, which will refer to the start or end of the array respectively.
+2 -2
View File
@@ -12,5 +12,5 @@ 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.
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.
For more advanced sorting, you can use the [sort_by](https://mikefarah.gitbook.io/yq/operators/sort) function on a map, and give it a custom function like `sort_by(key | downcase)`.
@@ -3,7 +3,7 @@
## 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.
Case insensitive tip: prefix the regex with `(?i)` - e.g. `test("(?i)cats)"`.
Case insensitive tip: prefix the regex with `(?i)` - e.g. `test("(?i)cats")`.
### match(regEx)
This operator returns the substring match details of the given regEx.
+3 -1
View File
@@ -1,3 +1,5 @@
# Style
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style)
The style operator can be used to get or set the style of nodes (e.g. string style, yaml style).
Use this to control the formatting of the document in yaml.
+7
View File
@@ -1,3 +1,10 @@
# Kind
The `kind` operator identifies the type of a node as either `scalar`, `map`, or `seq`.
This can be used for filtering or transforming nodes based on their type.
Note that `null` values are treated as `scalar`.
## Get kind
Given a sample.yml file of:
+51
View File
@@ -0,0 +1,51 @@
# Max
Computes the maximum among an incoming sequence of scalar values.
## Maximum int
Given a sample.yml file of:
```yaml
- 99
- 16
- 12
- 6
- 66
```
then
```bash
yq 'max' sample.yml
```
will output
```yaml
99
```
## Maximum string
Given a sample.yml file of:
```yaml
- foo
- bar
- baz
```
then
```bash
yq 'max' sample.yml
```
will output
```yaml
foo
```
## Maximum of empty
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'max' sample.yml
```
will output
```yaml
```
+51
View File
@@ -0,0 +1,51 @@
# Min
Computes the minimum among an incoming sequence of scalar values.
## Minimum int
Given a sample.yml file of:
```yaml
- 99
- 16
- 12
- 6
- 66
```
then
```bash
yq 'min' sample.yml
```
will output
```yaml
6
```
## Minimum string
Given a sample.yml file of:
```yaml
- foo
- bar
- baz
```
then
```bash
yq 'min' sample.yml
```
will output
```yaml
bar
```
## Minimum of empty
Given a sample.yml file of:
```yaml
[]
```
then
```bash
yq 'min' sample.yml
```
will output
```yaml
```

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