Jsonnet Rules
Jsonnet rules for Bazel
README
Jsonnet Rules
Rules
-
jsonnet_library
-
jsonnet_to_json
-
jsonnet_to_json_test
Overview
These are build rules for working with Jsonnet files with Bazel.
Setup
To use the Jsonnet rules, add the following to your WORKSPACE file to add the
external repositories for Jsonnet:
http_archive(
name = "io_bazel_rules_jsonnet",
sha256 = "d20270872ba8d4c108edecc9581e2bb7f320afab71f8caa2f6394b5202e8a2c3",
strip_prefix = "rules_jsonnet-0.4.0",
urls = ["https://github.com/bazelbuild/rules_jsonnet/archive/0.4.0.tar.gz"],
)
load("@io_bazel_rules_jsonnet//jsonnet:jsonnet.bzl", "jsonnet_repositories")
jsonnet_repositories()
load("@google_jsonnet_go//bazel:repositories.bzl", "jsonnet_go_repositories")
jsonnet_go_repositories()
load("@google_jsonnet_go//bazel:deps.bzl", "jsonnet_go_dependencies")
jsonnet_go_dependencies()
Jsonnet Port Selection
By default, Bazel will use the Go port of Jsonnet. To use the C++ port of Jsonnet instead, invoke Bazel with the --define jsonnet_port=cpp command-line flag. To select the Go port explicitly, invoke Bazel with the --define jsonnet_port=go command-line flag.
| bazel Flag | Jsonnet Port |
|---|---|
| (none) | Go |
--define jsonnet_port=cpp |
C++ |
--define jsonnet_port=go |
Go |
Note that the primary development focus of the Jsonnet project is now with the Go port. This repository's support for using the C++ port is deprecated, and may be removed in a future release.
jsonnet_library
jsonnet_library(name, srcs, deps, imports)
Attributes
name
Name, required
A unique name for this rule.
srcs
List of Labels, required
List of .jsonnet files that comprises this Jsonnet
library.
deps
List of labels, optional
List of targets that are required by the srcs Jsonnet
files.
imports
List of strings, optional
List of import -J flags to be passed to the
jsonnet compiler.
Example
Suppose you have the following directory structure:
[workspace]/
WORKSPACE
configs/
BUILD
backend.jsonnet
frontend.jsonnet
You can use the jsonnet_library rule to build a collection of .jsonnet
files that can be imported by other .jsonnet files as dependencies:
configs/BUILD:
load("@io_bazel_rules_jsonnet//jsonnet:jsonnet.bzl", "jsonnet_library")
jsonnet_library(
name = "configs",
srcs = [
"backend.jsonnet",
"frontend.jsonnet",
],
)
jsonnet_to_json
jsonnet_to_json(name, src, deps, outs, multiple_outputs, imports, stamp_keys, ext_strs, ext_str_envs, ext_code, ext_code_envs ext_str_files, ext_str_file_vars, ext_code_files, ext_code_file_vars, yaml_stream)
Attributes
name
Name, required
A unique name for this rule.
This name will be used as the name of the JSON file generated by this
rule.
src
Label, required
The .jsonnet file to convert to JSON.
deps
List of labels, optional
List of targets that are required by the src Jsonnet
file.
outs
List of Filenames, required
Names of the output .json files to be generated by this rule.
If you are generating only a single JSON file and are not using
jsonnet multiple output files, then this attribute should only
contain the file name of the JSON file you are generating.
If you are generating multiple JSON files using jsonnet multiple file
output (jsonnet -m), then list the file names of all the
JSON files to be generated. The file names specified here must match
the file names specified in your src Jsonnet file.
For the case where multiple file output is used but only for
generating one output file, set the multiple_outputs
attribute to 1 to explicitly enable the -m flag for
multiple file output.
multiple_outputs
bool, optional, default 0
Set to 1 to explicitly enable multiple file output via the
jsonnet -m flag.
This is used for the case where multiple file output is used but only
for generating a single output file. For example:
local foo = import "foo.jsonnet";
{
"foo.json": foo,
}
imports
List of strings, optional
List of import -J flags to be passed to the
jsonnet compiler.
stamp_keys
List of strings, optional
Specify which variables in ext_strs and ext_code should get stamped by listing the matching dict keys.
To get outside variables provided by a script invoked via --workspace_status_command into the build. For example:
jsonnet_to_json(
name = "...",
ext_strs = {
"cluster": "{CLUSTER}"
},
stamp_keys = ["cluster"]
)
$ cat .bazelrc
build --workspace_status_command=./print-workspace-status.sh
$ cat print-workspace-status.sh
cat <<EOF
VAR1 value1
This can be overridden by users if they "export CLUSTER_OVERRIDE"
CLUSTER ${CLUSTER_OVERRIDE:-default-value2}
EOF
ext_strs
String dict, optional
Map of strings to pass to jsonnet as external variables via --ext-str key=value.
ext_str_envs
String list, optional
List of env var names containing strings to pass to jsonnet as external variables via --ext-str key.
ext_code
String dict, optional
Map of code to pass to jsonnet as external variables via
--ext-code key=value.
ext_code_envs
String list, optional
List of env var names containing jsonnet code to pass to jsonnet as external variables via
--ext-code key.
ext_str_files
List of labels, optional but needed together with file_vars
List of string files that map to the var name defined in file_vars at the same index and together are passed to jsonnet via
--ext-str-file var=file.
ext_str_file_vars
List of string, optional but needed together with files
List of var names that maps to the file defined in files at the same index and together are passed to jsonnet via
--ext-str-file var=file.
ext_code_files
String dict, optional
List of jsonnet code files that map to the var name defined in ext_code_file_vars at the same index and together are passed to jsonnet via
--ext-code-file var=file.
ext_code_file_vars
String dict, optional
List of var names that maps to the code file defined in code_files at the same index and together are passed to jsonnet via
--ext-code-file var=file.
tla_strs
String dict, optional
Map of strings to pass to jsonnet as top-level arguments via --tla-str key=value.
tla_str_envs
String list, optional
List of env var names containing strings to pass to jsonnet as top-level arguments via --tla-str key.
tla_code
String dict, optional
Map of code to pass to jsonnet as top-level arguments via
--tla-code key=value.
tla_code_envs
String list, optional
List of env var names containing jsonnet code to pass to jsonnet as top-level arguments via
--tla-code key.
tla_str_files
Label-keyed String dict, optional
Dict of labels referencing text files and a var name, passed to jsonnet via --tla-str-file var=file.
tla_code_files
Label-keyed String dict, optional
Dict of labels referencing code files and a var name, passed to jsonnet via --tla-code-file var=file.
yaml_stream
bool, optional, default is False
Set to 1 to write output as a YAML stream of JSON documents.
Example
Suppose you have the following directory structure:
[workspace]/
WORKSPACE
workflows/
BUILD
workflow.libsonnet
wordcount.jsonnet
intersection.jsonnet
Say that workflow.libsonnet is a base configuration library for a workflow
scheduling system and wordcount.jsonnet and intersection.jsonnet both
import workflow.libsonnet to define workflows for performing a wordcount and
intersection of two files, respectively.
First, create a jsonnet_library target with workflow.libsonnet:
workflows/BUILD:
load("@io_bazel_rules_jsonnet//jsonnet:jsonnet.bzl", "jsonnet_library")
jsonnet_library(
name = "workflow",
srcs = ["workflow.libsonnet"],
)
To compile wordcount.jsonnet and intersection.jsonnet to JSON, define two
jsonnet_to_json targets:
jsonnet_to_json(
name = "wordcount",
src = "wordcount.jsonnet",
outs = ["wordcount.json"],
deps = [":workflow"],
)
jsonnet_to_json(
name = "intersection",
src = "intersection.jsonnet",
outs = ["intersection.json"],
deps = [":workflow"],
)
Example: Multiple output files
To use Jsonnet's multiple output files, suppose you
add a file shell-workflows.jsonnet that imports wordcount.jsonnet and
intersection.jsonnet:
workflows/shell-workflows.jsonnet:
local wordcount = import "workflows/wordcount.jsonnet";
local intersection = import "workflows/intersection.jsonnet";
{
"wordcount-workflow.json": wordcount,
"intersection-workflow.json": intersection,
}
To compile shell-workflows.jsonnet into the two JSON files,
wordcount-workflow.json and intersection-workflow.json, first create a
jsonnet_library target containing the two files that
shell-workflows.jsonnet depends on:
jsonnet_library(
name = "shell-workflows-lib",
srcs = [
"wordcount.jsonnet",
"intersection.jsonnet",
],
deps = [":workflow"],
)
Then, create a jsonnet_to_json target and set outs to the list of output
files to indicate that multiple output JSON files are generated:
jsonnet_to_json(
name = "shell-workflows",
src = "shell-workflows.jsonnet",
deps = [":shell-workflows-lib"],
outs = [
"wordcount-workflow.json",
"intersection-workflow.json",
],
)
jsonnet_to_json_test
jsonnet_to_json_test(name, src, deps, imports, golden, error=0, regex=False, yaml_stream=False, stamp_keys, ext_strs, ext_str_envs, ext_code, ext_code_envs ext_str_files, ext_str_file_vars, ext_code_files, ext_code_file_vars)
Attributes
name
Name, required
A unique name for this rule.
This name will be used as the name of the JSON file generated by this
rule.
src
Label, required
The .jsonnet file to convert to JSON.
deps
List of labels, optional
List of targets that are required by the src Jsonnet
file.
imports
codefileList of strings, optional
List of import -J flags to be passed to the
jsonnet compiler.
stamp_keys
List of strings, optional
Specify which variables in ext_strs and ext_code should get stamped by listing the matching dict keys.
To get outside variables provided by a script invoked via --workspace_status_command into the build.
ext_strs
String dict, optional
Map of strings to pass to jsonnet as external variables via --ext-str key=value.
ext_str_envs
String list, optional
List of env var names containing strings to pass to jsonnet as external variables via --ext-str key.
ext_code
String dict, optional
Map of code to pass to jsonnet as external variables via
--ext-code key=value.
ext_code_envs
String list, optional
List of env var names containing jsonnet code to pass to jsonnet as external variables via
--ext-code key.
ext_str_files
List of labels, optional but needed together with file_vars
List of string files that map to the var name defined in file_vars at the same index and together are passed to jsonnet via
--ext-str-file var=file.
ext_str_file_vars
List of string, optional but needed together with files
List of var names that maps to the file defined in files at the same index and together are passed to jsonnet via
--ext-str-file var=file.
ext_code_files
String dict, optional
List of jsonnet code files that map to the var name defined in ext_code_file_vars at the same index and together are passed to jsonnet via
--ext-code-file var=file.
ext_code_file_vars
String dict, optional
List of var names that maps to the code file defined in code_files at the same index and together are passed to jsonnet via
--ext-code-file var=file.
golden
Label, optional
The expected (combined stdout and stderr) output to compare to the
output of running jsonnet on src.
error
Integer, optional, default is 0
The expected error code from running jsonnet on
src.
regex
bool, optional, default is False
Set to 1 if golden contains a regex used to match
the output of running jsonnet on src.
yaml_stream
bool, optional, default is False
Set to 1 to write output as a YAML stream of JSON documents.
Example
Suppose you have the following directory structure:
[workspace]/
WORKSPACE
config/
BUILD
base_config.libsonnet
test_config.jsonnet
test_config.json
Suppose that base_config.libsonnet is a library Jsonnet file, containing the
base configuration for a service. Suppose that test_config.jsonnet is a test
configuration file that is used to test base_config.jsonnet, and
test_config.json is the expected JSON output from compiling
test_config.jsonnet.
The jsonnet_to_json_test rule can be used to verify that compiling a Jsonnet
file produces the expected JSON output. Simply define a jsonnet_to_json_test
target and provide the input test Jsonnet file and the golden file containing
the expected JSON output:
config/BUILD:
load(
"@io_bazel_rules_jsonnet//jsonnet:jsonnet.bzl",
"jsonnet_library",
"jsonnet_to_json_test",
)
jsonnet_library(
name = "base_config",
srcs = ["base_config.libsonnet"],
)
jsonnet_to_json_test(
name = "test_config_test",
src = "test_config",
deps = [":base_config"],
golden = "test_config.json",
)
To run the test: bazel test //config:test_config_test
Example: Negative tests
Suppose you have the following directory structure:
[workspace]/
WORKSPACE
config/
BUILD
base_config.libsonnet
invalid_config.jsonnet
invalid_config.output
Suppose that invalid_config.jsonnet is a Jsonnet file used to verify that
an invalid config triggers an assertion in base_config.jsonnet, and
invalid_config.output is the expected error output.
The jsonnet_to_json_test rule can be used to verify that compiling a Jsonnet
file results in an expected error code and error output. Simply define a
jsonnet_to_json_test target and provide the input test Jsonnet file, the
expected error code in the error attribute, and the golden file containing
the expected error output:
config/BUILD:
load(
"@io_bazel_rules_jsonnet//jsonnet:jsonnet.bzl",
"jsonnet_library",
"jsonnet_to_json_test",
)
jsonnet_library(
name = "base_config",
srcs = ["base_config.libsonnet"],
)
jsonnet_to_json_test(
name = "invalid_config_test",
src = "invalid_config",
deps = [":base_config"],
golden = "invalid_config.output",
error = 1,
)
To run the test: bazel test //config:invalid_config_test
