2024-08-08 19:56:11 +00:00
|
|
|
"""Wrapper rule around the popular `jq` utility.
|
|
|
|
|
|
|
|
For jq documentation, see https://stedolan.github.io/jq/.
|
|
|
|
|
|
|
|
## Usage examples
|
|
|
|
|
|
|
|
```starlark
|
|
|
|
load("@aspect_bazel_lib//lib:jq.bzl", "jq")
|
|
|
|
```
|
|
|
|
|
|
|
|
Create a new file `bazel-out/.../no_srcs.json` containing some JSON data:
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "no_srcs",
|
|
|
|
srcs = [],
|
|
|
|
filter = ".name = \"Alice\"",
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Remove a field from `package.json`:
|
|
|
|
|
|
|
|
> The output path `bazel-out/.../package.json` matches the path of the source file,
|
|
|
|
> which means you must refer to the label `:no_dev_deps` to reference the output,
|
|
|
|
> since Bazel doesn't provide a label for an output file that collides with an input file.
|
|
|
|
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "no_dev_deps",
|
|
|
|
srcs = ["package.json"],
|
2024-08-11 22:56:06 +00:00
|
|
|
out = "package.json",
|
2024-08-08 19:56:11 +00:00
|
|
|
filter = "del(.devDependencies)",
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Merge data from `bar.json` on top of `foo.json`, producing `foobar.json`:
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "merged",
|
|
|
|
srcs = ["foo.json", "bar.json"],
|
|
|
|
filter = ".[0] * .[1]",
|
|
|
|
args = ["--slurp"],
|
|
|
|
out = "foobar.json",
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Long filters can be split over several lines with comments:
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "complex",
|
|
|
|
srcs = ["a.json", "b.json"],
|
|
|
|
filter = \"\"\"
|
|
|
|
.[0] as $a
|
|
|
|
# Take select fields from b.json
|
|
|
|
| (.[1] | {foo, bar, tags}) as $b
|
|
|
|
# Merge b onto a
|
|
|
|
| ($a * $b)
|
|
|
|
# Combine 'tags' array from both
|
|
|
|
| .tags = ($a.tags + $b.tags)
|
|
|
|
# Add new field
|
|
|
|
+ {\\\"aspect_is_cool\\\": true}
|
|
|
|
\"\"\",
|
|
|
|
args = ["--slurp"],
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Load filter from a file `filter.jq`, making it easier to edit complex filters:
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "merged",
|
|
|
|
srcs = ["foo.json", "bar.json"],
|
|
|
|
filter_file = "filter.jq",
|
|
|
|
args = ["--slurp"],
|
|
|
|
out = "foobar.json",
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
Convert [genquery](https://bazel.build/reference/be/general#genquery) output to JSON.
|
|
|
|
```starlark
|
|
|
|
genquery(
|
|
|
|
name = "deps",
|
|
|
|
expression = "deps(//some:target)",
|
|
|
|
scope = ["//some:target"],
|
|
|
|
)
|
|
|
|
|
|
|
|
jq(
|
|
|
|
name = "deps_json",
|
|
|
|
srcs = [":deps"],
|
|
|
|
args = [
|
|
|
|
"--raw-input",
|
|
|
|
"--slurp",
|
|
|
|
],
|
|
|
|
filter = "{ deps: split(\"\\n\") | map(select(. | length > 0)) }",
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
When Bazel is run with `--stamp`, replace some properties with version control info:
|
|
|
|
```starlark
|
|
|
|
jq(
|
|
|
|
name = "stamped",
|
|
|
|
srcs = ["package.json"],
|
|
|
|
filter = "|".join([
|
|
|
|
# Don't directly reference $STAMP as it's only set when stamping
|
|
|
|
# This 'as' syntax results in $stamp being null in unstamped builds.
|
|
|
|
"$ARGS.named.STAMP as $stamp",
|
|
|
|
# Provide a default using the "alternative operator" in case $stamp is null.
|
|
|
|
".version = ($stamp[0].BUILD_EMBED_LABEL // \"<unstamped>\")",
|
|
|
|
]),
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
jq is exposed as a "Make variable", so you could use it directly from a `genrule` by referencing the toolchain.
|
|
|
|
|
|
|
|
```starlark
|
|
|
|
genrule(
|
|
|
|
name = "case_genrule",
|
|
|
|
srcs = ["a.json"],
|
|
|
|
outs = ["genrule_output.json"],
|
|
|
|
cmd = "$(JQ_BIN) '.' $(location a.json) > $@",
|
|
|
|
toolchains = ["@jq_toolchains//:resolved_toolchain"],
|
|
|
|
)
|
|
|
|
```
|
|
|
|
"""
|
2021-12-09 00:47:45 +00:00
|
|
|
|
|
|
|
load("//lib/private:jq.bzl", _jq_lib = "jq_lib")
|
|
|
|
|
|
|
|
_jq_rule = rule(
|
|
|
|
attrs = _jq_lib.attrs,
|
|
|
|
implementation = _jq_lib.implementation,
|
|
|
|
toolchains = ["@aspect_bazel_lib//lib:jq_toolchain_type"],
|
|
|
|
)
|
|
|
|
|
2024-02-27 01:43:56 +00:00
|
|
|
def jq(name, srcs, filter = None, filter_file = None, args = [], out = None, data = [], expand_args = False, **kwargs):
|
2021-12-09 00:47:45 +00:00
|
|
|
"""Invoke jq with a filter on a set of json input files.
|
|
|
|
|
|
|
|
Args:
|
|
|
|
name: Name of the rule
|
2023-04-19 13:45:24 +00:00
|
|
|
srcs: List of input files. May be empty.
|
2024-02-27 01:43:56 +00:00
|
|
|
data: List of additional files. May be empty.
|
2022-08-22 17:59:38 +00:00
|
|
|
filter: Filter expression (https://stedolan.github.io/jq/manual/#Basicfilters).
|
|
|
|
Subject to stamp variable replacements, see [Stamping](./stamping.md).
|
|
|
|
When stamping is enabled, a variable named "STAMP" will be available in the filter.
|
|
|
|
|
|
|
|
Be careful to write the filter so that it handles unstamped builds, as in the example above.
|
|
|
|
|
2021-12-20 20:47:39 +00:00
|
|
|
filter_file: File containing filter expression (alternative to `filter`)
|
|
|
|
args: Additional args to pass to jq
|
2024-02-27 01:43:56 +00:00
|
|
|
expand_args: Run bazel's location-expansion on the args.
|
2021-12-09 00:47:45 +00:00
|
|
|
out: Name of the output json file; defaults to the rule name plus ".json"
|
2021-12-20 20:47:39 +00:00
|
|
|
**kwargs: Other common named parameters such as `tags` or `visibility`
|
2021-12-09 00:47:45 +00:00
|
|
|
"""
|
2022-06-22 01:27:49 +00:00
|
|
|
default_name = name + ".json"
|
|
|
|
if not out and not default_name in srcs:
|
|
|
|
out = default_name
|
2021-12-09 00:47:45 +00:00
|
|
|
|
|
|
|
_jq_rule(
|
|
|
|
name = name,
|
|
|
|
srcs = srcs,
|
|
|
|
filter = filter,
|
2021-12-20 20:47:39 +00:00
|
|
|
filter_file = filter_file,
|
2021-12-09 00:47:45 +00:00
|
|
|
args = args,
|
|
|
|
out = out,
|
2024-02-27 01:43:56 +00:00
|
|
|
expand_args = expand_args,
|
|
|
|
data = data,
|
2021-12-18 00:55:00 +00:00
|
|
|
**kwargs
|
2021-12-09 00:47:45 +00:00
|
|
|
)
|