add documentation pages for rules/ and lib/ (#119)

This commit is contained in:
c-parsons 2019-02-28 17:43:57 -05:00 committed by GitHub
parent e171ec16d8
commit 9630853eeb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 3495 additions and 12 deletions

View File

@ -6,6 +6,8 @@ tasks:
bazel: latest
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -17,6 +19,8 @@ tasks:
bazel: latest
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -28,6 +32,8 @@ tasks:
bazel: latest
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -39,6 +45,8 @@ tasks:
bazel: latest
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "--"
- "..."
@ -52,6 +60,8 @@ tasks:
bazel: last_green
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -63,6 +73,8 @@ tasks:
bazel: last_green
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -74,6 +86,8 @@ tasks:
bazel: last_green
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "..."
test_flags:
@ -85,6 +99,8 @@ tasks:
bazel: last_green
build_targets:
- "..."
build_flags:
- "--incompatible_remap_main_repo"
test_targets:
- "--"
- "..."

View File

@ -56,22 +56,24 @@ s = shell.quote(p)
## List of modules (in lib/)
* [collections](lib/collections.bzl)
* [dicts](lib/dicts.bzl)
* [partial](lib/partial.bzl)
* [paths](lib/paths.bzl)
* [selects](lib/selects.bzl)
* [collections](docs/collections_doc.md)
* [dicts](docs/dicts_doc.md)
* [partial](docs/partial_doc.md)
* [paths](docs/paths_doc.md)
* [selects](docs/selects_doc.md)
* [sets](lib/sets.bzl) - _deprecated_, use `new_sets`
* [new_sets](lib/new_sets.bzl)
* [shell](lib/shell.bzl)
* [structs](lib/structs.bzl)
* [types](lib/types.bzl)
* [unittest](lib/unittest.bzl)
* [versions](lib/versions.bzl)
* [new_sets](docs/new_sets.md)
* [shell](docs/shell_doc.md)
* [structs](docs/structs_doc.md)
* [types](docs/types_doc.md)
* [unittest](docs/unittest_doc.md)
* [versions](docs/versions_doc.md)
## List of rules (in rules/)
* [`cmd_maprule` and `bash_maprule`](lib/maprule.bzl)
* [analysis_test](docs/analysis_test_doc.md)
* [build_test](docs/build_test_doc.md)
* [`cmd_maprule` and `bash_maprule`](docs/maprule_doc.md)
## Writing a new module

View File

@ -3,3 +3,16 @@ workspace(name = "bazel_skylib")
load(":workspace.bzl", "bazel_skylib_workspace")
bazel_skylib_workspace()
# Below this line is for documentation generation only,
# and should thus not be included by dependencies on
# bazel-skylib.
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "io_bazel_skydoc",
remote = "https://github.com/bazelbuild/skydoc.git",
commit = "ac5c106412697ffb9364864070bac796b9bb63d3", # Feb 27, 2019
)
load("@io_bazel_skydoc//skylark:skylark.bzl", "skydoc_repositories")
skydoc_repositories()

101
docs/BUILD Normal file
View File

@ -0,0 +1,101 @@
load("@io_bazel_skydoc//stardoc:stardoc.bzl", "stardoc")
# Note that due to a bug in Bazel 0.22.0, these targets cannot be built without
# the --incompatible_remap_main_repo flag.
stardoc(
name = "build_test_docs",
input = "//rules:build_test.bzl",
out = "build_test_doc_gen.md",
deps = ["//rules:build_test"],
)
stardoc(
name = "analysis_test_docs",
input = "//rules:analysis_test.bzl",
out = "analysis_test_doc_gen.md",
)
stardoc(
name = "collections_docs",
input = "//lib:collections.bzl",
out = "collections_doc_gen.md",
deps = ["//lib:collections"],
)
stardoc(
name = "dicts_docs",
input = "//lib:dicts.bzl",
out = "dicts_doc_gen.md",
deps = ["//lib:dicts"],
)
stardoc(
name = "partial_docs",
input = "//lib:partial.bzl",
out = "partial_doc_gen.md",
deps = ["//lib:partial"],
)
stardoc(
name = "paths_docs",
input = "//lib:paths.bzl",
out = "paths_doc_gen.md",
deps = ["//lib:paths"],
)
stardoc(
name = "selects_docs",
input = "//lib:selects.bzl",
out = "selects_doc_gen.md",
deps = ["//lib:selects"],
)
stardoc(
name = "new_sets_docs",
input = "//lib:new_sets.bzl",
out = "new_sets_doc_gen.md",
deps = ["//lib:new_sets"],
)
stardoc(
name = "shell_docs",
input = "//lib:shell.bzl",
out = "shell_doc_gen.md",
deps = ["//lib:shell"],
)
stardoc(
name = "structs_docs",
input = "//lib:structs.bzl",
out = "structs_doc_gen.md",
deps = ["//lib:structs"],
)
stardoc(
name = "types_docs",
input = "//lib:types.bzl",
out = "types_doc_gen.md",
deps = ["//lib:types"],
)
stardoc(
name = "unittest_docs",
input = "//lib:unittest.bzl",
out = "unittest_doc_gen.md",
deps = ["//lib:unittest"],
)
stardoc(
name = "versions_docs",
input = "//lib:versions.bzl",
out = "versions_doc_gen.md",
deps = ["//lib:versions"],
)
stardoc(
name = "maprule_docs",
input = "//rules:maprule.bzl",
out = "maprule_doc_gen.md",
deps = ["//rules:maprule"],
)

62
docs/analysis_test_doc.md Executable file
View File

@ -0,0 +1,62 @@
<a name="#analysis_test"></a>
## analysis_test
<pre>
analysis_test(<a href="#analysis_test-name">name</a>, <a href="#analysis_test-targets">targets</a>)
</pre>
Test rule checking that other targets can be successfully analyzed.
This rule essentially verifies that all targets under `targets` would
generate no errors when analyzed with `bazel build [targets] --nobuild`.
Action success/failure for the targets and their transitive dependencies
are not verified. An analysis test simply ensures that each target in the transitive
dependencies propagate providers appropriately and register actions for their outputs
appropriately.
NOTE: If the targets fail to analyze, instead of the analysis_test failing, the analysis_test
will fail to build. Ideally, it would instead result in a test failure. This is a current
infrastructure limitation that may be fixed in the future.
Typical usage:
load("@bazel_skylib//rules:analysis_test.bzl", "analysis_test")
analysis_test(
name = "my_analysis_test",
targets = [
"//some/package:rule",
],
)
Args:
name: The name of the test rule.
targets: A list of targets to ensure build.
### Attributes
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysis_test-name">
<td><code>name</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
<p>
A unique name for this target.
</p>
</td>
</tr>
<tr id="analysis_test-targets">
<td><code>targets</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; required
</td>
</tr>
</tbody>
</table>

67
docs/build_test_doc.md Executable file
View File

@ -0,0 +1,67 @@
## build_test
<pre>
build_test(<a href="#build_test-name">name</a>, <a href="#build_test-targets">targets</a>, <a href="#build_test-kwargs">kwargs</a>)
</pre>
Test rule checking that other targets build.
This works not by an instance of this test failing, but instead by
the targets it depends on failing to build, and hence failing
the attempt to run this test.
NOTE: At the moment, this won't work on Windows; but someone adding
support would be welcomed.
Typical usage:
```
load("@bazel_skylib//rules:build_test.bzl", "build_test")
build_test(
name = "my_build_test",
targets = [
"//some/package:rule",
],
)
```
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="build_test-name">
<td><code>name</code></td>
<td>
required.
<p>
The name of the test rule.
</p>
</td>
</tr>
<tr id="build_test-targets">
<td><code>targets</code></td>
<td>
required.
<p>
A list of targets to ensure build.
</p>
</td>
</tr>
<tr id="build_test-kwargs">
<td><code>kwargs</code></td>
<td>
optional.
<p>
The <a href="https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes-tests">common attributes for tests</a>.
</p>
</td>
</tr>
</tbody>
</table>

108
docs/collections_doc.md Executable file
View File

@ -0,0 +1,108 @@
## collections.after_each
<pre>
collections.after_each(<a href="#collections.after_each-separator">separator</a>, <a href="#collections.after_each-iterable">iterable</a>)
</pre>
Inserts `separator` after each item in `iterable`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="collections.after_each-separator">
<td><code>separator</code></td>
<td>
required.
<p>
The value to insert after each item in `iterable`.
</p>
</td>
</tr>
<tr id="collections.after_each-iterable">
<td><code>iterable</code></td>
<td>
required.
<p>
The list into which to intersperse the separator.
</p>
</td>
</tr>
</tbody>
</table>
## collections.before_each
<pre>
collections.before_each(<a href="#collections.before_each-separator">separator</a>, <a href="#collections.before_each-iterable">iterable</a>)
</pre>
Inserts `separator` before each item in `iterable`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="collections.before_each-separator">
<td><code>separator</code></td>
<td>
required.
<p>
The value to insert before each item in `iterable`.
</p>
</td>
</tr>
<tr id="collections.before_each-iterable">
<td><code>iterable</code></td>
<td>
required.
<p>
The list into which to intersperse the separator.
</p>
</td>
</tr>
</tbody>
</table>
## collections.uniq
<pre>
collections.uniq(<a href="#collections.uniq-iterable">iterable</a>)
</pre>
Returns a list of unique elements in `iterable`.
Requires all the elements to be hashable.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="collections.uniq-iterable">
<td><code>iterable</code></td>
<td>
required.
<p>
An iterable to filter.
</p>
</td>
</tr>
</tbody>
</table>

38
docs/dicts_doc.md Executable file
View File

@ -0,0 +1,38 @@
## dicts.add
<pre>
dicts.add(<a href="#dicts.add-dictionaries">dictionaries</a>)
</pre>
Returns a new `dict` that has all the entries of the given dictionaries.
If the same key is present in more than one of the input dictionaries, the
last of them in the argument list overrides any earlier ones.
This function is designed to take zero or one arguments as well as multiple
dictionaries, so that it follows arithmetic identities and callers can avoid
special cases for their inputs: the sum of zero dictionaries is the empty
dictionary, and the sum of a single dictionary is a copy of itself.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="dicts.add-dictionaries">
<td><code>dictionaries</code></td>
<td>
optional.
<p>
Zero or more dictionaries to be added.
</p>
</td>
</tr>
</tbody>
</table>

573
docs/maprule_doc.md Executable file
View File

@ -0,0 +1,573 @@
<a name="#bash_maprule"></a>
## bash_maprule
<pre>
bash_maprule(<a href="#bash_maprule-name">name</a>, <a href="#bash_maprule-add_env">add_env</a>, <a href="#bash_maprule-cmd">cmd</a>, <a href="#bash_maprule-foreach_srcs">foreach_srcs</a>, <a href="#bash_maprule-message">message</a>, <a href="#bash_maprule-outs_templates">outs_templates</a>, <a href="#bash_maprule-srcs">srcs</a>, <a href="#bash_maprule-tools">tools</a>)
</pre>
Maprule that runs a Bash command.
This rule is the same as `cmd_maprule` except this one uses Bash to run the command, therefore the
`cmd` attribute must use Bash syntax. `bash_maprule` rules can only be built if Bash is installed on
the build machine.
Maprule runs a specific command for each of the "foreach" source files. This allows processing
source files in parallel, to produce some outputs for each of them.
The name "maprule" indicates that this rule can be used to map source files to output files, and is
also a reference to "genrule" that inspired this rule's design (though there are significant
differences).
Below you will find an Example, Tips and Tricks, and an FAQ.
### Example
# This file is //projects/game:BUILD
load("@bazel_skylib//rules:maprule.bzl", "bash_maprule")
bash_maprule(
name = "process_assets",
foreach_srcs = [
"rust.png",
"teapot.3ds",
"//assets:wood.jpg",
"//assets:models",
],
outs_templates = {
"TAGS": "{src}.tags",
"DIGEST": "digests/{src_name_noext}.md5",
},
tools = [
"//bin:asset-tagger",
"//util:md5sum",
],
add_env = {
"ASSET_TAGGER": "$(location //bin:asset-tagger)",
"MD5SUM": "$(location //util:md5sum)",
},
# Note: this command should live in a script file, we only inline it in the `cmd` attribute
# for the sake of demonstration. See Tips and Tricks section.
cmd = '"$MAPRULE_ASSET_TAGGER" --input="$MAPRULE_SRC" --output="$MAPRULE_TAGS" && ' +
'"$MAPRULE_MD5SUM" "$MAPRULE_SRC" &gt; "$MAPRULE_DIGEST"',
)
The "process_assets" rule above will execute the command in the `cmd` to process "rust.png",
"teapot.3ds", "//assets:wood.jpg", and every file in the "//assets:models" rule, producing the
corresponding .tags and .md5 files for each of them, under the following paths:
bazel-bin/projects/game/process_assets_out/projects/game/rust.png.tags
bazel-bin/projects/game/process_assets_out/digests/rust.md5
bazel-bin/projects/game/process_assets_out/projects/game/teapot.3ds.tags
bazel-bin/projects/game/process_assets_out/digests/teapot.md5
bazel-bin/projects/game/process_assets_out/assets/wood.jpg.tags
bazel-bin/projects/game/process_assets_out/digests/wood.md5
...
You can create downstream rules, for example a filegroup or genrule (or another maprule) that put
this rule in their `srcs` attribute and get all the .tags and .md5 files.
## Tips and Tricks
*(The Tips and Tricks section is the same for `cmd_maprule` and `bash_maprule`.)*
### Use script files instead of inlining commands in the `cmd` attribute.
Unless the command is trivial, don't try to write it in `cmd`.
Properly quoting parts of the command is challenging enough, add to that escaping for the BUILD
file's syntax and the `cmd` attribute quickly gets unmaintainably complex.
It's a lot easier and maintainable to create a script file such as "foo.sh" in `bash_maprule` or
"foo.bat" in `cmd_maprule` for the commands. To do that:
1. move the commands to a script file
2. add the script file to the `tools` attribute
3. add an entry to the `add_env` attribute, e.g. "`TOOL:&nbsp;"$(location :tool.sh)"`"
4. replace the `cmd` with just "$MAPRULE_FOO" (in `bash_maprule`) or "%MAPRULE_FOO%" (in
`cmd_maprule`).
Doing this also avoids hitting command line length limits.
Example:
cmd_maprule(
...
srcs = ["//data:temperatures.txt"],
tools = [
"command.bat",
":weather-stats",
],
add_env = {
"COMMAND": "$(location :command.bat)",
"STATS_TOOL": "$(location :weather-stats-computer)",
"TEMPERATURES": "$(location //data:temperatures.txt)",
},
cmd = "%MAPRULE_COMMAND%",
)
### Use the `add_env` attribute to pass tool locations to the command.
Entries in the `add_env` attribute may use "$(location)" references and may also use the same
placeholders as the `outs_templates` attribute. For example you can use this mechanism to pass extra
"$(location)" references of `tools` or `srcs` to the actions.
Example:
cmd_maprule(
...
foreach_srcs = [...],
outs_templates = {"STATS_OUT": "{src}-stats.txt"},
srcs = ["//data:temperatures.txt"],
tools = [":weather-stats"],
add_env = {
"STATS_TOOL": "$(location :weather-stats-computer)",
"TEMPERATURES": "$(location //data:temperatures.txt)",
},
cmd = "%MAPRULE_STATS_TOOL% --src=%MAPRULE_SRC% --data=%MAPRULE_TEMPERATURES% > %MAPRULE_STATS_OUT%",
)
cc_binary(
name = "weather-stats",
...
)
## Environment Variables
*(The Environment Variables section is the same for `cmd_maprule` and `bash_maprule`.)*
The rule defines several environment variables available to the command may reference. All of these
envvars names start with "MAPRULE_". You can add your own envvars with the `add_env` attribute.
The command can use some envvars, all named "MAPRULE_*&lt;something&gt;*".
The complete list of environment variables is:
- "MAPRULE_SRC": the path of the current file from `foreach_srcs`
- "MAPRULE_SRCS": the space-separated paths of all files in the `srcs` attribute
- "MAPRULE_*&lt;OUT&gt;*": for each key name *&lt;OUT&gt;* in the `outs_templates` attribute, this
is the path of the respective output file for the current source
- "MAPRULE_*&lt;ENV&gt;*": for each key name *&lt;ENV&gt;* in the `add_env` attribute
## FAQ
*(The FAQ section is the same for `cmd_maprule` and `bash_maprule`.)*
### What's the motivation for maprule? What's wrong with genrule?
genrule creates a single action for all of its inputs. It requires specifying all output files.
Finally, it can only create Bash commands.
Maprule supports parallel processing of its inputs and doesn't require specifying all outputs, just
templates for the outputs. And not only Bash is supported (via `bash_maprule`) but so are
cmd.exe-style commands via `cmd_maprule`.
### `genrule.cmd` supports "$(location)" expressions, how come `*_maprule.cmd` doesn't?
Maprule deliberately omits support for this feature to avoid pitfalls with quoting and escaping, and
potential issues with paths containing spaces. Instead, maprule exports environment variables for
the input and outputs of the action, and allows the user to define extra envvars. These extra
envvars do support "$(location)" expressions, so you can pass paths of labels in `srcs` and `tools`.
### Why are all envvars exported with the "MAPRULE_" prefix?
To avoid conflicts with other envvars, whose names could also be attractive outs_templates names.
### Why do `outs_templates` and `add_env` keys have to be uppercase?
Because they are exported as all-uppercase envvars, so requiring that they be declared as uppercase
gives a visual cue of that. It also avoids clashes resulting from mixed lower-upper-case names like
"foo" and "Foo".
### Why don't `outs_templates` and `add_env` keys have to start with "MAPRULE_" even though they are exported as such?
For convenience. It seems to bring no benefit to have the user always type "MAPRULE_" in front of
the name when the rule itself could as well add it.
### Why are all outputs relative to "*&lt;maprule_pkg&gt;*/*&lt;maprule_name&gt;*_out/" ?
To ensure that maprules in the same package and with the same outs_templates produce distinct output
files.
### Why aren't `outs_templates` keys available as placeholders in the values of `add_env`?
Because `add_env` is meant to be used for passing extra "$(location)" information to the action, and
the output paths are already available as envvars for the action.
### Attributes
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="bash_maprule-name">
<td><code>name</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
<p>
A unique name for this target.
</p>
</td>
</tr>
<tr id="bash_maprule-add_env">
<td><code>add_env</code></td>
<td>
<a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a>; optional
<p>
Extra environment variables to define for the actions. Every variable's name must be uppercase. Bazel will automatically prepend "MAPRULE_" to the name when exporting the variable for the action. The values may use "$(location)" expressions for labels declared in the `srcs` and `tools` attribute, and may reference the same placeholders as the values of the `outs_templates` attribute.
</p>
</td>
</tr>
<tr id="bash_maprule-cmd">
<td><code>cmd</code></td>
<td>
String; required
<p>
The command to execute. It must be in the syntax corresponding to this maprule type, e.g. for `bash_maprule` this must be a Bash command, and for `cmd_maprule` a Windows Command Prompt (cmd.exe) command. Several environment variables are available for this command, storing values like the paths of the input and output files of the action. See the "Environment Variables" section for the complete list of environment variables available to this command.
</p>
</td>
</tr>
<tr id="bash_maprule-foreach_srcs">
<td><code>foreach_srcs</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; required
<p>
The set of sources that will be processed one by one in parallel, to produce the templated outputs. Each of these source files will will be processed individually by its own action.
</p>
</td>
</tr>
<tr id="bash_maprule-message">
<td><code>message</code></td>
<td>
String; optional
<p>
A custom progress message to display as the actions are executed.
</p>
</td>
</tr>
<tr id="bash_maprule-outs_templates">
<td><code>outs_templates</code></td>
<td>
<a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a>; required
<p>
<p>Templates for the output files. Each key defines a name for an output file and the value specifies a path template for that output. For each of the files in `foreach_srcs` this rule creates one action that produces all of these outputs. The paths of the particular output files for that input are computed from the template. The ensure the resolved templates yield unique paths, the following placeholders are supported in the path templates:</p><ul><li>"{src}": same as "{src_dir}/{src_name}"</li><li>"{src_dir}": package path of the source file, and a trailing "/"</li><li>"{src_name}": base name of the source file</li><li>"{src_name_noext}": same as "{src_name}" without the file extension</li></ul><p>You may also add extra path components to the templates, as long as the path template is relative and does not contain uplevel references (".."). Placeholders will be replaced by the values corresponding to the respective input file in `foreach_srcs`. Every output file is generated under &lt;bazel_bin&gt;/path/to/maprule/&lt;maprule_name&gt; + "_outs/".</p>
</p>
</td>
</tr>
<tr id="bash_maprule-srcs">
<td><code>srcs</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; optional
<p>
The set of source files common to all actions of this rule.
</p>
</td>
</tr>
<tr id="bash_maprule-tools">
<td><code>tools</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; optional
<p>
Tools used by the command. The `cmd` attribute, and the values of the `add_env` attribute may reference these tools in "$(location)" expressions, similar to the genrule rule.
</p>
</td>
</tr>
</tbody>
</table>
<a name="#cmd_maprule"></a>
## cmd_maprule
<pre>
cmd_maprule(<a href="#cmd_maprule-name">name</a>, <a href="#cmd_maprule-add_env">add_env</a>, <a href="#cmd_maprule-cmd">cmd</a>, <a href="#cmd_maprule-foreach_srcs">foreach_srcs</a>, <a href="#cmd_maprule-message">message</a>, <a href="#cmd_maprule-outs_templates">outs_templates</a>, <a href="#cmd_maprule-srcs">srcs</a>, <a href="#cmd_maprule-tools">tools</a>)
</pre>
Maprule that runs a Windows Command Prompt (`cmd.exe`) command.
This rule is the same as `bash_maprule`, but uses `cmd.exe` instead of Bash, therefore the `cmd`
attribute must use Command Prompt syntax. `cmd_maprule` rules can only be built on Windows.
Maprule runs a specific command for each of the "foreach" source files. This allows processing
source files in parallel, to produce some outputs for each of them.
The name "maprule" indicates that this rule can be used to map source files to output files, and is
also a reference to "genrule" that inspired this rule's design (though there are significant
differences).
Below you will find an Example, Tips and Tricks, and an FAQ.
### Example
# This file is //projects/game:BUILD
load("@bazel_skylib//rules:maprule.bzl", "cmd_maprule")
cmd_maprule(
name = "process_assets",
foreach_srcs = [
"rust.png",
"teapot.3ds",
"//assets:wood.jpg",
"//assets:models",
],
outs_templates = {
"TAGS": "{src}.tags",
"DIGEST": "digests/{src_name_noext}.md5",
},
tools = [
"//bin:asset-tagger",
"//util:md5sum",
],
add_env = {
"ASSET_TAGGER": "$(location //bin:asset-tagger)",
"MD5SUM": "$(location //util:md5sum)",
},
# Note: this command should live in a script file, we only inline it in the `cmd` attribute
# for the sake of demonstration. See Tips and Tricks section.
cmd = "%MAPRULE_ASSET_TAGGER% --input=%MAPRULE_SRC% --output=%MAPRULE_TAGS% & " +
'IF /I "%ERRORLEVEL%" EQU "0" ( %MAPRULE_MD5SUM% %MAPRULE_SRC% &gt; %MAPRULE_DIGEST% )',
)
The "process_assets" rule above will execute the command in the `cmd` to process "rust.png",
"teapot.3ds", "//assets:wood.jpg", and every file in the "//assets:models" rule, producing the
corresponding .tags and .md5 files for each of them, under the following paths:
bazel-bin/projects/game/process_assets_out/projects/game/rust.png.tags
bazel-bin/projects/game/process_assets_out/digests/rust.md5
bazel-bin/projects/game/process_assets_out/projects/game/teapot.3ds.tags
bazel-bin/projects/game/process_assets_out/digests/teapot.md5
bazel-bin/projects/game/process_assets_out/assets/wood.jpg.tags
bazel-bin/projects/game/process_assets_out/digests/wood.md5
...
You can create downstream rules, for example a filegroup or genrule (or another maprule) that put
this rule in their `srcs` attribute and get all the .tags and .md5 files.
## Tips and Tricks
*(The Tips and Tricks section is the same for `cmd_maprule` and `bash_maprule`.)*
### Use script files instead of inlining commands in the `cmd` attribute.
Unless the command is trivial, don't try to write it in `cmd`.
Properly quoting parts of the command is challenging enough, add to that escaping for the BUILD
file's syntax and the `cmd` attribute quickly gets unmaintainably complex.
It's a lot easier and maintainable to create a script file such as "foo.sh" in `bash_maprule` or
"foo.bat" in `cmd_maprule` for the commands. To do that:
1. move the commands to a script file
2. add the script file to the `tools` attribute
3. add an entry to the `add_env` attribute, e.g. "`TOOL:&nbsp;"$(location :tool.sh)"`"
4. replace the `cmd` with just "$MAPRULE_FOO" (in `bash_maprule`) or "%MAPRULE_FOO%" (in
`cmd_maprule`).
Doing this also avoids hitting command line length limits.
Example:
cmd_maprule(
...
srcs = ["//data:temperatures.txt"],
tools = [
"command.bat",
":weather-stats",
],
add_env = {
"COMMAND": "$(location :command.bat)",
"STATS_TOOL": "$(location :weather-stats-computer)",
"TEMPERATURES": "$(location //data:temperatures.txt)",
},
cmd = "%MAPRULE_COMMAND%",
)
### Use the `add_env` attribute to pass tool locations to the command.
Entries in the `add_env` attribute may use "$(location)" references and may also use the same
placeholders as the `outs_templates` attribute. For example you can use this mechanism to pass extra
"$(location)" references of `tools` or `srcs` to the actions.
Example:
cmd_maprule(
...
foreach_srcs = [...],
outs_templates = {"STATS_OUT": "{src}-stats.txt"},
srcs = ["//data:temperatures.txt"],
tools = [":weather-stats"],
add_env = {
"STATS_TOOL": "$(location :weather-stats-computer)",
"TEMPERATURES": "$(location //data:temperatures.txt)",
},
cmd = "%MAPRULE_STATS_TOOL% --src=%MAPRULE_SRC% --data=%MAPRULE_TEMPERATURES% > %MAPRULE_STATS_OUT%",
)
cc_binary(
name = "weather-stats",
...
)
## Environment Variables
*(The Environment Variables section is the same for `cmd_maprule` and `bash_maprule`.)*
The rule defines several environment variables available to the command may reference. All of these
envvars names start with "MAPRULE_". You can add your own envvars with the `add_env` attribute.
The command can use some envvars, all named "MAPRULE_*&lt;something&gt;*".
The complete list of environment variables is:
- "MAPRULE_SRC": the path of the current file from `foreach_srcs`
- "MAPRULE_SRCS": the space-separated paths of all files in the `srcs` attribute
- "MAPRULE_*&lt;OUT&gt;*": for each key name *&lt;OUT&gt;* in the `outs_templates` attribute, this
is the path of the respective output file for the current source
- "MAPRULE_*&lt;ENV&gt;*": for each key name *&lt;ENV&gt;* in the `add_env` attribute
## FAQ
*(The FAQ section is the same for `cmd_maprule` and `bash_maprule`.)*
### What's the motivation for maprule? What's wrong with genrule?
genrule creates a single action for all of its inputs. It requires specifying all output files.
Finally, it can only create Bash commands.
Maprule supports parallel processing of its inputs and doesn't require specifying all outputs, just
templates for the outputs. And not only Bash is supported (via `bash_maprule`) but so are
cmd.exe-style commands via `cmd_maprule`.
### `genrule.cmd` supports "$(location)" expressions, how come `*_maprule.cmd` doesn't?
Maprule deliberately omits support for this feature to avoid pitfalls with quoting and escaping, and
potential issues with paths containing spaces. Instead, maprule exports environment variables for
the input and outputs of the action, and allows the user to define extra envvars. These extra
envvars do support "$(location)" expressions, so you can pass paths of labels in `srcs` and `tools`.
### Why are all envvars exported with the "MAPRULE_" prefix?
To avoid conflicts with other envvars, whose names could also be attractive outs_templates names.
### Why do `outs_templates` and `add_env` keys have to be uppercase?
Because they are exported as all-uppercase envvars, so requiring that they be declared as uppercase
gives a visual cue of that. It also avoids clashes resulting from mixed lower-upper-case names like
"foo" and "Foo".
### Why don't `outs_templates` and `add_env` keys have to start with "MAPRULE_" even though they are exported as such?
For convenience. It seems to bring no benefit to have the user always type "MAPRULE_" in front of
the name when the rule itself could as well add it.
### Why are all outputs relative to "*&lt;maprule_pkg&gt;*/*&lt;maprule_name&gt;*_out/" ?
To ensure that maprules in the same package and with the same outs_templates produce distinct output
files.
### Why aren't `outs_templates` keys available as placeholders in the values of `add_env`?
Because `add_env` is meant to be used for passing extra "$(location)" information to the action, and
the output paths are already available as envvars for the action.
### Attributes
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="cmd_maprule-name">
<td><code>name</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
<p>
A unique name for this target.
</p>
</td>
</tr>
<tr id="cmd_maprule-add_env">
<td><code>add_env</code></td>
<td>
<a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a>; optional
<p>
Extra environment variables to define for the actions. Every variable's name must be uppercase. Bazel will automatically prepend "MAPRULE_" to the name when exporting the variable for the action. The values may use "$(location)" expressions for labels declared in the `srcs` and `tools` attribute, and may reference the same placeholders as the values of the `outs_templates` attribute.
</p>
</td>
</tr>
<tr id="cmd_maprule-cmd">
<td><code>cmd</code></td>
<td>
String; required
<p>
The command to execute. It must be in the syntax corresponding to this maprule type, e.g. for `bash_maprule` this must be a Bash command, and for `cmd_maprule` a Windows Command Prompt (cmd.exe) command. Several environment variables are available for this command, storing values like the paths of the input and output files of the action. See the "Environment Variables" section for the complete list of environment variables available to this command.
</p>
</td>
</tr>
<tr id="cmd_maprule-foreach_srcs">
<td><code>foreach_srcs</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; required
<p>
The set of sources that will be processed one by one in parallel, to produce the templated outputs. Each of these source files will will be processed individually by its own action.
</p>
</td>
</tr>
<tr id="cmd_maprule-message">
<td><code>message</code></td>
<td>
String; optional
<p>
A custom progress message to display as the actions are executed.
</p>
</td>
</tr>
<tr id="cmd_maprule-outs_templates">
<td><code>outs_templates</code></td>
<td>
<a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a>; required
<p>
<p>Templates for the output files. Each key defines a name for an output file and the value specifies a path template for that output. For each of the files in `foreach_srcs` this rule creates one action that produces all of these outputs. The paths of the particular output files for that input are computed from the template. The ensure the resolved templates yield unique paths, the following placeholders are supported in the path templates:</p><ul><li>"{src}": same as "{src_dir}/{src_name}"</li><li>"{src_dir}": package path of the source file, and a trailing "/"</li><li>"{src_name}": base name of the source file</li><li>"{src_name_noext}": same as "{src_name}" without the file extension</li></ul><p>You may also add extra path components to the templates, as long as the path template is relative and does not contain uplevel references (".."). Placeholders will be replaced by the values corresponding to the respective input file in `foreach_srcs`. Every output file is generated under &lt;bazel_bin&gt;/path/to/maprule/&lt;maprule_name&gt; + "_outs/".</p>
</p>
</td>
</tr>
<tr id="cmd_maprule-srcs">
<td><code>srcs</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; optional
<p>
The set of source files common to all actions of this rule.
</p>
</td>
</tr>
<tr id="cmd_maprule-tools">
<td><code>tools</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a>; optional
<p>
Tools used by the command. The `cmd` attribute, and the values of the `add_env` attribute may reference these tools in "$(location)" expressions, similar to the genrule rule.
</p>
</td>
</tr>
</tbody>
</table>

519
docs/new_sets_doc.md Executable file
View File

@ -0,0 +1,519 @@
## sets.make
<pre>
sets.make(<a href="#sets.make-elements">elements</a>)
</pre>
Creates a new set.
All elements must be hashable.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.make-elements">
<td><code>elements</code></td>
<td>
optional. default is <code>None</code>
<p>
Optional sequence to construct the set out of.
</p>
</td>
</tr>
</tbody>
</table>
## sets.copy
<pre>
sets.copy(<a href="#sets.copy-s">s</a>)
</pre>
Creates a new set from another set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.copy-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.to_list
<pre>
sets.to_list(<a href="#sets.to_list-s">s</a>)
</pre>
Creates a list from the values in the set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.to_list-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.insert
<pre>
sets.insert(<a href="#sets.insert-s">s</a>, <a href="#sets.insert-e">e</a>)
</pre>
Inserts an element into the set.
Element must be hashable. This mutates the orginal set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.insert-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.insert-e">
<td><code>e</code></td>
<td>
required.
<p>
The element to be inserted.
</p>
</td>
</tr>
</tbody>
</table>
## sets.contains
<pre>
sets.contains(<a href="#sets.contains-a">a</a>, <a href="#sets.contains-e">e</a>)
</pre>
Checks for the existence of an element in a set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.contains-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.contains-e">
<td><code>e</code></td>
<td>
required.
<p>
The element to look for.
</p>
</td>
</tr>
</tbody>
</table>
## sets.is_equal
<pre>
sets.is_equal(<a href="#sets.is_equal-a">a</a>, <a href="#sets.is_equal-b">b</a>)
</pre>
Returns whether two sets are equal.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.is_equal-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.is_equal-b">
<td><code>b</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.is_subset
<pre>
sets.is_subset(<a href="#sets.is_subset-a">a</a>, <a href="#sets.is_subset-b">b</a>)
</pre>
Returns whether `a` is a subset of `b`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.is_subset-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.is_subset-b">
<td><code>b</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.disjoint
<pre>
sets.disjoint(<a href="#sets.disjoint-a">a</a>, <a href="#sets.disjoint-b">b</a>)
</pre>
Returns whether two sets are disjoint.
Two sets are disjoint if they have no elements in common.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.disjoint-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.disjoint-b">
<td><code>b</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.intersection
<pre>
sets.intersection(<a href="#sets.intersection-a">a</a>, <a href="#sets.intersection-b">b</a>)
</pre>
Returns the intersection of two sets.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.intersection-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.intersection-b">
<td><code>b</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.union
<pre>
sets.union(<a href="#sets.union-args">args</a>)
</pre>
Returns the union of several sets.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.union-args">
<td><code>args</code></td>
<td>
optional.
<p>
An arbitrary number of sets or lists.
</p>
</td>
</tr>
</tbody>
</table>
## sets.difference
<pre>
sets.difference(<a href="#sets.difference-a">a</a>, <a href="#sets.difference-b">b</a>)
</pre>
Returns the elements in `a` that are not in `b`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.difference-a">
<td><code>a</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.difference-b">
<td><code>b</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.length
<pre>
sets.length(<a href="#sets.length-s">s</a>)
</pre>
Returns the number of elements in a set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.length-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.remove
<pre>
sets.remove(<a href="#sets.remove-s">s</a>, <a href="#sets.remove-e">e</a>)
</pre>
Removes an element from the set.
Element must be hashable. This mutates the orginal set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.remove-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
<tr id="sets.remove-e">
<td><code>e</code></td>
<td>
required.
<p>
The element to be removed.
</p>
</td>
</tr>
</tbody>
</table>
## sets.repr
<pre>
sets.repr(<a href="#sets.repr-s">s</a>)
</pre>
Returns a string value representing the set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.repr-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>
## sets.str
<pre>
sets.str(<a href="#sets.str-s">s</a>)
</pre>
Returns a string value representing the set.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="sets.str-s">
<td><code>s</code></td>
<td>
required.
<p>
A set, as returned by `sets.make()`.
</p>
</td>
</tr>
</tbody>
</table>

171
docs/partial_doc.md Executable file
View File

@ -0,0 +1,171 @@
## partial.make
<pre>
partial.make(<a href="#partial.make-func">func</a>, <a href="#partial.make-args">args</a>, <a href="#partial.make-kwargs">kwargs</a>)
</pre>
Creates a partial that can be called using `call`.
A partial can have args assigned to it at the make site, and can have args
passed to it at the call sites.
A partial 'function' can be defined with positional args and kwargs:
# function with no args
def function1():
...
# function with 2 args
def function2(arg1, arg2):
...
# function with 2 args and keyword args
def function3(arg1, arg2, x, y):
...
The positional args passed to the function are the args passed into make
followed by any additional positional args given to call. The below example
illustrates a function with two positional arguments where one is supplied by
make and the other by call:
# function demonstrating 1 arg at make site, and 1 arg at call site
def _foo(make_arg1, func_arg1):
print(make_arg1 + " " + func_arg1 + "!")
For example:
hi_func = partial.make(_foo, "Hello")
bye_func = partial.make(_foo, "Goodbye")
partial.call(hi_func, "Jennifer")
partial.call(hi_func, "Dave")
partial.call(bye_func, "Jennifer")
partial.call(bye_func, "Dave")
prints:
"Hello, Jennifer!"
"Hello, Dave!"
"Goodbye, Jennifer!"
"Goodbye, Dave!"
The keyword args given to the function are the kwargs passed into make
unioned with the keyword args given to call. In case of a conflict, the
keyword args given to call take precedence. This allows you to set a default
value for keyword arguments and override it at the call site.
Example with a make site arg, a call site arg, a make site kwarg and a
call site kwarg:
def _foo(make_arg1, call_arg1, make_location, call_location):
print(make_arg1 + " is from " + make_location + " and " +
call_arg1 + " is from " + call_location + "!")
func = partial.make(_foo, "Ben", make_location="Hollywood")
partial.call(func, "Jennifer", call_location="Denver")
Prints "Ben is from Hollywood and Jennifer is from Denver!".
partial.call(func, "Jennifer", make_location="LA", call_location="Denver")
Prints "Ben is from LA and Jennifer is from Denver!".
Note that keyword args may not overlap with positional args, regardless of
whether they are given during the make or call step. For instance, you can't
do:
def foo(x):
pass
func = partial.make(foo, 1)
partial.call(func, x=2)
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="partial.make-func">
<td><code>func</code></td>
<td>
required.
<p>
The function to be called.
</p>
</td>
</tr>
<tr id="partial.make-args">
<td><code>args</code></td>
<td>
optional.
<p>
Positional arguments to be passed to function.
</p>
</td>
</tr>
<tr id="partial.make-kwargs">
<td><code>kwargs</code></td>
<td>
optional.
<p>
Keyword arguments to be passed to function. Note that these can
be overridden at the call sites.
</p>
</td>
</tr>
</tbody>
</table>
## partial.call
<pre>
partial.call(<a href="#partial.call-partial">partial</a>, <a href="#partial.call-args">args</a>, <a href="#partial.call-kwargs">kwargs</a>)
</pre>
Calls a partial created using `make`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="partial.call-partial">
<td><code>partial</code></td>
<td>
required.
<p>
The partial to be called.
</p>
</td>
</tr>
<tr id="partial.call-args">
<td><code>args</code></td>
<td>
optional.
<p>
Additional positional arguments to be appended to the ones given to
make.
</p>
</td>
</tr>
<tr id="partial.call-kwargs">
<td><code>kwargs</code></td>
<td>
optional.
<p>
Additional keyword arguments to augment and override the ones
given to make.
</p>
</td>
</tr>
</tbody>
</table>

311
docs/paths_doc.md Executable file
View File

@ -0,0 +1,311 @@
## paths.basename
<pre>
paths.basename(<a href="#paths.basename-p">p</a>)
</pre>
Returns the basename (i.e., the file portion) of a path.
Note that if `p` ends with a slash, this function returns an empty string.
This matches the behavior of Python's `os.path.basename`, but differs from
the Unix `basename` command (which would return the path segment preceding
the final slash).
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.basename-p">
<td><code>p</code></td>
<td>
required.
<p>
The path whose basename should be returned.
</p>
</td>
</tr>
</tbody>
</table>
## paths.dirname
<pre>
paths.dirname(<a href="#paths.dirname-p">p</a>)
</pre>
Returns the dirname of a path.
The dirname is the portion of `p` up to but not including the file portion
(i.e., the basename). Any slashes immediately preceding the basename are not
included, unless omitting them would make the dirname empty.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.dirname-p">
<td><code>p</code></td>
<td>
required.
<p>
The path whose dirname should be returned.
</p>
</td>
</tr>
</tbody>
</table>
## paths.is_absolute
<pre>
paths.is_absolute(<a href="#paths.is_absolute-path">path</a>)
</pre>
Returns `True` if `path` is an absolute path.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.is_absolute-path">
<td><code>path</code></td>
<td>
required.
<p>
A path (which is a string).
</p>
</td>
</tr>
</tbody>
</table>
## paths.join
<pre>
paths.join(<a href="#paths.join-path">path</a>, <a href="#paths.join-others">others</a>)
</pre>
Joins one or more path components intelligently.
This function mimics the behavior of Python's `os.path.join` function on POSIX
platform. It returns the concatenation of `path` and any members of `others`,
inserting directory separators before each component except the first. The
separator is not inserted if the path up until that point is either empty or
already ends in a separator.
If any component is an absolute path, all previous components are discarded.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.join-path">
<td><code>path</code></td>
<td>
required.
<p>
A path segment.
</p>
</td>
</tr>
<tr id="paths.join-others">
<td><code>others</code></td>
<td>
optional.
<p>
Additional path segments.
</p>
</td>
</tr>
</tbody>
</table>
## paths.normalize
<pre>
paths.normalize(<a href="#paths.normalize-path">path</a>)
</pre>
Normalizes a path, eliminating double slashes and other redundant segments.
This function mimics the behavior of Python's `os.path.normpath` function on
POSIX platforms; specifically:
- If the entire path is empty, "." is returned.
- All "." segments are removed, unless the path consists solely of a single
"." segment.
- Trailing slashes are removed, unless the path consists solely of slashes.
- ".." segments are removed as long as there are corresponding segments
earlier in the path to remove; otherwise, they are retained as leading ".."
segments.
- Single and double leading slashes are preserved, but three or more leading
slashes are collapsed into a single leading slash.
- Multiple adjacent internal slashes are collapsed into a single slash.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.normalize-path">
<td><code>path</code></td>
<td>
required.
<p>
A path.
</p>
</td>
</tr>
</tbody>
</table>
## paths.relativize
<pre>
paths.relativize(<a href="#paths.relativize-path">path</a>, <a href="#paths.relativize-start">start</a>)
</pre>
Returns the portion of `path` that is relative to `start`.
Because we do not have access to the underlying file system, this
implementation differs slightly from Python's `os.path.relpath` in that it
will fail if `path` is not beneath `start` (rather than use parent segments to
walk up to the common file system root).
Relativizing paths that start with parent directory references only works if
the path both start with the same initial parent references.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.relativize-path">
<td><code>path</code></td>
<td>
required.
<p>
The path to relativize.
</p>
</td>
</tr>
<tr id="paths.relativize-start">
<td><code>start</code></td>
<td>
required.
<p>
The ancestor path against which to relativize.
</p>
</td>
</tr>
</tbody>
</table>
## paths.replace_extension
<pre>
paths.replace_extension(<a href="#paths.replace_extension-p">p</a>, <a href="#paths.replace_extension-new_extension">new_extension</a>)
</pre>
Replaces the extension of the file at the end of a path.
If the path has no extension, the new extension is added to it.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.replace_extension-p">
<td><code>p</code></td>
<td>
required.
<p>
The path whose extension should be replaced.
</p>
</td>
</tr>
<tr id="paths.replace_extension-new_extension">
<td><code>new_extension</code></td>
<td>
required.
<p>
The new extension for the file. The new extension should
begin with a dot if you want the new filename to have one.
</p>
</td>
</tr>
</tbody>
</table>
## paths.split_extension
<pre>
paths.split_extension(<a href="#paths.split_extension-p">p</a>)
</pre>
Splits the path `p` into a tuple containing the root and extension.
Leading periods on the basename are ignored, so
`path.split_extension(".bashrc")` returns `(".bashrc", "")`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="paths.split_extension-p">
<td><code>p</code></td>
<td>
required.
<p>
The path whose root and extension should be split.
</p>
</td>
</tr>
</tbody>
</table>

27
docs/regenerate_docs.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
# Copyright 2019 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# A script to manually regenerate the documentation contained in the docs/ directory.
# Should be run from the WORKSPACE root.
set -euo pipefail
bazel build docs:all --experimental_remap_main_repo
for filename in bazel-bin/docs/*_gen.md; do
target_filename="$(echo $filename | sed -En "s/bazel-bin\/(.*)_gen.md/\1/p").md"
cp $filename $target_filename
done

87
docs/selects_doc.md Executable file
View File

@ -0,0 +1,87 @@
## selects.with_or
<pre>
selects.with_or(<a href="#selects.with_or-input_dict">input_dict</a>, <a href="#selects.with_or-no_match_error">no_match_error</a>)
</pre>
Drop-in replacement for `select()` that supports ORed keys.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="selects.with_or-input_dict">
<td><code>input_dict</code></td>
<td>
required.
<p>
The same dictionary `select()` takes, except keys may take
either the usual form `"//foo:config1"` or
`("//foo:config1", "//foo:config2", ...)` to signify
`//foo:config1` OR `//foo:config2` OR `...`.
</p>
</td>
</tr>
<tr id="selects.with_or-no_match_error">
<td><code>no_match_error</code></td>
<td>
optional. default is <code>""</code>
<p>
Optional custom error to report if no condition matches.
Example:
```build
deps = selects.with_or({
"//configs:one": [":dep1"],
("//configs:two", "//configs:three"): [":dep2or3"],
"//configs:four": [":dep4"],
"//conditions:default": [":default"]
})
```
Key labels may appear at most once anywhere in the input.
</p>
</td>
</tr>
</tbody>
</table>
## selects.with_or_dict
<pre>
selects.with_or_dict(<a href="#selects.with_or_dict-input_dict">input_dict</a>)
</pre>
Variation of `with_or` that returns the dict of the `select()`.
Unlike `select()`, the contents of the dict can be inspected by Starlark
macros.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="selects.with_or_dict-input_dict">
<td><code>input_dict</code></td>
<td>
required.
<p>
Same as `with_or`.
</p>
</td>
</tr>
</tbody>
</table>

71
docs/shell_doc.md Executable file
View File

@ -0,0 +1,71 @@
## shell.array_literal
<pre>
shell.array_literal(<a href="#shell.array_literal-iterable">iterable</a>)
</pre>
Creates a string from a sequence that can be used as a shell array.
For example, `shell.array_literal(["a", "b", "c"])` would return the string
`("a" "b" "c")`, which can be used in a shell script wherever an array
literal is needed.
Note that all elements in the array are quoted (using `shell.quote`) for
safety, even if they do not need to be.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="shell.array_literal-iterable">
<td><code>iterable</code></td>
<td>
required.
<p>
A sequence of elements. Elements that are not strings will be
converted to strings first, by calling `str()`.
</p>
</td>
</tr>
</tbody>
</table>
## shell.quote
<pre>
shell.quote(<a href="#shell.quote-s">s</a>)
</pre>
Quotes the given string for use in a shell command.
This function quotes the given string (in case it contains spaces or other
shell metacharacters.)
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="shell.quote-s">
<td><code>s</code></td>
<td>
required.
<p>
The string to quote.
</p>
</td>
</tr>
</tbody>
</table>

29
docs/structs_doc.md Executable file
View File

@ -0,0 +1,29 @@
## structs.to_dict
<pre>
structs.to_dict(<a href="#structs.to_dict-s">s</a>)
</pre>
Converts a `struct` to a `dict`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="structs.to_dict-s">
<td><code>s</code></td>
<td>
required.
<p>
A `struct`.
</p>
</td>
</tr>
</tbody>
</table>

261
docs/types_doc.md Executable file
View File

@ -0,0 +1,261 @@
## types.is_list
<pre>
types.is_list(<a href="#types.is_list-v">v</a>)
</pre>
Returns True if v is an instance of a list.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_list-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_string
<pre>
types.is_string(<a href="#types.is_string-v">v</a>)
</pre>
Returns True if v is an instance of a string.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_string-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_bool
<pre>
types.is_bool(<a href="#types.is_bool-v">v</a>)
</pre>
Returns True if v is an instance of a bool.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_bool-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_none
<pre>
types.is_none(<a href="#types.is_none-v">v</a>)
</pre>
Returns True if v has the type of None.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_none-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_int
<pre>
types.is_int(<a href="#types.is_int-v">v</a>)
</pre>
Returns True if v is an instance of a signed integer.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_int-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_tuple
<pre>
types.is_tuple(<a href="#types.is_tuple-v">v</a>)
</pre>
Returns True if v is an instance of a tuple.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_tuple-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_dict
<pre>
types.is_dict(<a href="#types.is_dict-v">v</a>)
</pre>
Returns True if v is an instance of a dict.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_dict-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_function
<pre>
types.is_function(<a href="#types.is_function-v">v</a>)
</pre>
Returns True if v is an instance of a function.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_function-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>
## types.is_depset
<pre>
types.is_depset(<a href="#types.is_depset-v">v</a>)
</pre>
Returns True if v is an instance of a `depset`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="types.is_depset-v">
<td><code>v</code></td>
<td>
required.
<p>
The value whose type should be checked.
</p>
</td>
</tr>
</tbody>
</table>

859
docs/unittest_doc.md Executable file
View File

@ -0,0 +1,859 @@
<a name="#unittest_toolchain"></a>
## unittest_toolchain
<pre>
unittest_toolchain(<a href="#unittest_toolchain-name">name</a>, <a href="#unittest_toolchain-failure_templ">failure_templ</a>, <a href="#unittest_toolchain-file_ext">file_ext</a>, <a href="#unittest_toolchain-join_on">join_on</a>, <a href="#unittest_toolchain-success_templ">success_templ</a>)
</pre>
### Attributes
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest_toolchain-name">
<td><code>name</code></td>
<td>
<a href="https://bazel.build/docs/build-ref.html#name">Name</a>; required
<p>
A unique name for this target.
</p>
</td>
</tr>
<tr id="unittest_toolchain-failure_templ">
<td><code>failure_templ</code></td>
<td>
String; required
</td>
</tr>
<tr id="unittest_toolchain-file_ext">
<td><code>file_ext</code></td>
<td>
String; required
</td>
</tr>
<tr id="unittest_toolchain-join_on">
<td><code>join_on</code></td>
<td>
String; required
</td>
</tr>
<tr id="unittest_toolchain-success_templ">
<td><code>success_templ</code></td>
<td>
String; required
</td>
</tr>
</tbody>
</table>
## analysistest.make
<pre>
analysistest.make(<a href="#analysistest.make-impl">impl</a>, <a href="#analysistest.make-expect_failure">expect_failure</a>, <a href="#analysistest.make-config_settings">config_settings</a>)
</pre>
Creates an analysis test rule from its implementation function.
An analysis test verifies the behavior of a "real" rule target by examining
and asserting on the providers given by the real target.
Each analysis test is defined in an implementation function that must then be
associated with a rule so that a target can be built. This function handles
the boilerplate to create and return a test rule and captures the
implementation function's name so that it can be printed in test feedback.
An example of an analysis test:
```
def _your_test(ctx):
env = analysistest.begin(ctx)
# Assert statements go here
return analysistest.end(env)
your_test = analysistest.make(_your_test)
```
Recall that names of test rules must end in `_test`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.make-impl">
<td><code>impl</code></td>
<td>
required.
<p>
The implementation function of the unit test.
</p>
</td>
</tr>
<tr id="analysistest.make-expect_failure">
<td><code>expect_failure</code></td>
<td>
optional. default is <code>False</code>
<p>
If true, the analysis test will expect the target_under_test
to fail. Assertions can be made on the underlying failure using asserts.expect_failure
</p>
</td>
</tr>
<tr id="analysistest.make-config_settings">
<td><code>config_settings</code></td>
<td>
optional. default is <code>{}</code>
<p>
A dictionary of configuration settings to change for the target under
test and its dependencies. This may be used to essentially change 'build flags' for
the target under test, and may thus be utilized to test multiple targets with different
flags in a single build
</p>
</td>
</tr>
</tbody>
</table>
## analysistest.begin
<pre>
analysistest.begin(<a href="#analysistest.begin-ctx">ctx</a>)
</pre>
Begins a unit test.
This should be the first function called in a unit test implementation
function. It initializes a "test environment" that is used to collect
assertion failures so that they can be reported and logged at the end of the
test.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.begin-ctx">
<td><code>ctx</code></td>
<td>
required.
<p>
The Skylark context. Pass the implementation function's `ctx` argument
in verbatim.
</p>
</td>
</tr>
</tbody>
</table>
## analysistest.end
<pre>
analysistest.end(<a href="#analysistest.end-env">env</a>)
</pre>
Ends an analysis test and logs the results.
This must be called and returned at the end of an analysis test implementation function so
that the results are reported.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.end-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `analysistest.begin`.
</p>
</td>
</tr>
</tbody>
</table>
## analysistest.fail
<pre>
analysistest.fail(<a href="#analysistest.fail-env">env</a>, <a href="#analysistest.fail-msg">msg</a>)
</pre>
Unconditionally causes the current test to fail.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.fail-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="analysistest.fail-msg">
<td><code>msg</code></td>
<td>
required.
<p>
The message to log describing the failure.
</p>
</td>
</tr>
</tbody>
</table>
## analysistest.target_actions
<pre>
analysistest.target_actions(<a href="#analysistest.target_actions-env">env</a>)
</pre>
Returns a list of actions registered by the target under test.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.target_actions-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `analysistest.begin`.
</p>
</td>
</tr>
</tbody>
</table>
## analysistest.target_under_test
<pre>
analysistest.target_under_test(<a href="#analysistest.target_under_test-env">env</a>)
</pre>
Returns the target under test.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="analysistest.target_under_test-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `analysistest.begin`.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.expect_failure
<pre>
asserts.expect_failure(<a href="#asserts.expect_failure-env">env</a>, <a href="#asserts.expect_failure-expected_failure_msg">expected_failure_msg</a>)
</pre>
Asserts that the target under test has failed with a given error message.
This requires that the analysis test is created with `analysistest.make()` and
`expect_failures = True` is specified.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.expect_failure-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `analysistest.begin`.
</p>
</td>
</tr>
<tr id="asserts.expect_failure-expected_failure_msg">
<td><code>expected_failure_msg</code></td>
<td>
optional. default is <code>""</code>
<p>
The error message to expect as a result of analysis failures.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.equals
<pre>
asserts.equals(<a href="#asserts.equals-env">env</a>, <a href="#asserts.equals-expected">expected</a>, <a href="#asserts.equals-actual">actual</a>, <a href="#asserts.equals-msg">msg</a>)
</pre>
Asserts that the given `expected` and `actual` values are equal.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.equals-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="asserts.equals-expected">
<td><code>expected</code></td>
<td>
required.
<p>
The expected value of some computation.
</p>
</td>
</tr>
<tr id="asserts.equals-actual">
<td><code>actual</code></td>
<td>
required.
<p>
The actual value returned by some computation.
</p>
</td>
</tr>
<tr id="asserts.equals-msg">
<td><code>msg</code></td>
<td>
optional. default is <code>None</code>
<p>
An optional message that will be printed that describes the failure.
If omitted, a default will be used.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.false
<pre>
asserts.false(<a href="#asserts.false-env">env</a>, <a href="#asserts.false-condition">condition</a>, <a href="#asserts.false-msg">msg</a>)
</pre>
Asserts that the given `condition` is false.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.false-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="asserts.false-condition">
<td><code>condition</code></td>
<td>
required.
<p>
A value that will be evaluated in a Boolean context.
</p>
</td>
</tr>
<tr id="asserts.false-msg">
<td><code>msg</code></td>
<td>
optional. default is <code>"Expected condition to be false, but was true."</code>
<p>
An optional message that will be printed that describes the failure.
If omitted, a default will be used.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.set_equals
<pre>
asserts.set_equals(<a href="#asserts.set_equals-env">env</a>, <a href="#asserts.set_equals-expected">expected</a>, <a href="#asserts.set_equals-actual">actual</a>, <a href="#asserts.set_equals-msg">msg</a>)
</pre>
Asserts that the given `expected` and `actual` sets are equal.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.set_equals-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="asserts.set_equals-expected">
<td><code>expected</code></td>
<td>
required.
<p>
The expected set resulting from some computation.
</p>
</td>
</tr>
<tr id="asserts.set_equals-actual">
<td><code>actual</code></td>
<td>
required.
<p>
The actual set returned by some computation.
</p>
</td>
</tr>
<tr id="asserts.set_equals-msg">
<td><code>msg</code></td>
<td>
optional. default is <code>None</code>
<p>
An optional message that will be printed that describes the failure.
If omitted, a default will be used.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.new_set_equals
<pre>
asserts.new_set_equals(<a href="#asserts.new_set_equals-env">env</a>, <a href="#asserts.new_set_equals-expected">expected</a>, <a href="#asserts.new_set_equals-actual">actual</a>, <a href="#asserts.new_set_equals-msg">msg</a>)
</pre>
Asserts that the given `expected` and `actual` sets are equal.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.new_set_equals-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="asserts.new_set_equals-expected">
<td><code>expected</code></td>
<td>
required.
<p>
The expected set resulting from some computation.
</p>
</td>
</tr>
<tr id="asserts.new_set_equals-actual">
<td><code>actual</code></td>
<td>
required.
<p>
The actual set returned by some computation.
</p>
</td>
</tr>
<tr id="asserts.new_set_equals-msg">
<td><code>msg</code></td>
<td>
optional. default is <code>None</code>
<p>
An optional message that will be printed that describes the failure.
If omitted, a default will be used.
</p>
</td>
</tr>
</tbody>
</table>
## asserts.true
<pre>
asserts.true(<a href="#asserts.true-env">env</a>, <a href="#asserts.true-condition">condition</a>, <a href="#asserts.true-msg">msg</a>)
</pre>
Asserts that the given `condition` is true.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="asserts.true-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="asserts.true-condition">
<td><code>condition</code></td>
<td>
required.
<p>
A value that will be evaluated in a Boolean context.
</p>
</td>
</tr>
<tr id="asserts.true-msg">
<td><code>msg</code></td>
<td>
optional. default is <code>"Expected condition to be true, but was false."</code>
<p>
An optional message that will be printed that describes the failure.
If omitted, a default will be used.
</p>
</td>
</tr>
</tbody>
</table>
## register_unittest_toolchains
<pre>
register_unittest_toolchains()
</pre>
Registers the toolchains for unittest users.
## unittest.make
<pre>
unittest.make(<a href="#unittest.make-impl">impl</a>, <a href="#unittest.make-attrs">attrs</a>)
</pre>
Creates a unit test rule from its implementation function.
Each unit test is defined in an implementation function that must then be
associated with a rule so that a target can be built. This function handles
the boilerplate to create and return a test rule and captures the
implementation function's name so that it can be printed in test feedback.
The optional `attrs` argument can be used to define dependencies for this
test, in order to form unit tests of rules.
An example of a unit test:
```
def _your_test(ctx):
env = unittest.begin(ctx)
# Assert statements go here
return unittest.end(env)
your_test = unittest.make(_your_test)
```
Recall that names of test rules must end in `_test`.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest.make-impl">
<td><code>impl</code></td>
<td>
required.
<p>
The implementation function of the unit test.
</p>
</td>
</tr>
<tr id="unittest.make-attrs">
<td><code>attrs</code></td>
<td>
optional. default is <code>None</code>
<p>
An optional dictionary to supplement the attrs passed to the
unit test's `rule()` constructor.
</p>
</td>
</tr>
</tbody>
</table>
## unittest.suite
<pre>
unittest.suite(<a href="#unittest.suite-name">name</a>, <a href="#unittest.suite-test_rules">test_rules</a>)
</pre>
Defines a `test_suite` target that contains multiple tests.
After defining your test rules in a `.bzl` file, you need to create targets
from those rules so that `blaze test` can execute them. Doing this manually
in a BUILD file would consist of listing each test in your `load` statement
and then creating each target one by one. To reduce duplication, we recommend
writing a macro in your `.bzl` file to instantiate all targets, and calling
that macro from your BUILD file so you only have to load one symbol.
For the case where your unit tests do not take any (non-default) attributes --
i.e., if your unit tests do not test rules -- you can use this function to
create the targets and wrap them in a single test_suite target. In your
`.bzl` file, write:
```
def your_test_suite():
unittest.suite(
"your_test_suite",
your_test,
your_other_test,
yet_another_test,
)
```
Then, in your `BUILD` file, simply load the macro and invoke it to have all
of the targets created:
```
load("//path/to/your/package:tests.bzl", "your_test_suite")
your_test_suite()
```
If you pass _N_ unit test rules to `unittest.suite`, _N_ + 1 targets will be
created: a `test_suite` target named `${name}` (where `${name}` is the name
argument passed in here) and targets named `${name}_test_${i}`, where `${i}`
is the index of the test in the `test_rules` list, which is used to uniquely
name each target.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest.suite-name">
<td><code>name</code></td>
<td>
required.
<p>
The name of the `test_suite` target, and the prefix of all the test
target names.
</p>
</td>
</tr>
<tr id="unittest.suite-test_rules">
<td><code>test_rules</code></td>
<td>
optional.
<p>
A list of test rules defines by `unittest.test`.
</p>
</td>
</tr>
</tbody>
</table>
## unittest.begin
<pre>
unittest.begin(<a href="#unittest.begin-ctx">ctx</a>)
</pre>
Begins a unit test.
This should be the first function called in a unit test implementation
function. It initializes a "test environment" that is used to collect
assertion failures so that they can be reported and logged at the end of the
test.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest.begin-ctx">
<td><code>ctx</code></td>
<td>
required.
<p>
The Skylark context. Pass the implementation function's `ctx` argument
in verbatim.
</p>
</td>
</tr>
</tbody>
</table>
## unittest.end
<pre>
unittest.end(<a href="#unittest.end-env">env</a>)
</pre>
Ends a unit test and logs the results.
This must be called and returned at the end of a unit test implementation function so
that the results are reported.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest.end-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
</tbody>
</table>
## unittest.fail
<pre>
unittest.fail(<a href="#unittest.fail-env">env</a>, <a href="#unittest.fail-msg">msg</a>)
</pre>
Unconditionally causes the current test to fail.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="unittest.fail-env">
<td><code>env</code></td>
<td>
required.
<p>
The test environment returned by `unittest.begin`.
</p>
</td>
</tr>
<tr id="unittest.fail-msg">
<td><code>msg</code></td>
<td>
required.
<p>
The message to log describing the failure.
</p>
</td>
</tr>
</tbody>
</table>

165
docs/versions_doc.md Executable file
View File

@ -0,0 +1,165 @@
## versions.get
<pre>
versions.get()
</pre>
Returns the current Bazel version
## versions.parse
<pre>
versions.parse(<a href="#versions.parse-bazel_version">bazel_version</a>)
</pre>
Parses a version string into a 3-tuple of ints
int tuples can be compared directly using binary operators (<, >).
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="versions.parse-bazel_version">
<td><code>bazel_version</code></td>
<td>
required.
<p>
the Bazel version string
</p>
</td>
</tr>
</tbody>
</table>
## versions.check
<pre>
versions.check(<a href="#versions.check-minimum_bazel_version">minimum_bazel_version</a>, <a href="#versions.check-maximum_bazel_version">maximum_bazel_version</a>, <a href="#versions.check-bazel_version">bazel_version</a>)
</pre>
Check that the version of Bazel is valid within the specified range.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="versions.check-minimum_bazel_version">
<td><code>minimum_bazel_version</code></td>
<td>
required.
<p>
minimum version of Bazel expected
</p>
</td>
</tr>
<tr id="versions.check-maximum_bazel_version">
<td><code>maximum_bazel_version</code></td>
<td>
optional. default is <code>None</code>
<p>
maximum version of Bazel expected
</p>
</td>
</tr>
<tr id="versions.check-bazel_version">
<td><code>bazel_version</code></td>
<td>
optional. default is <code>None</code>
<p>
the version of Bazel to check. Used for testing, defaults to native.bazel_version
</p>
</td>
</tr>
</tbody>
</table>
## versions.is_at_most
<pre>
versions.is_at_most(<a href="#versions.is_at_most-threshold">threshold</a>, <a href="#versions.is_at_most-version">version</a>)
</pre>
Check that a version is lower or equals to a threshold.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="versions.is_at_most-threshold">
<td><code>threshold</code></td>
<td>
required.
<p>
the maximum version string
</p>
</td>
</tr>
<tr id="versions.is_at_most-version">
<td><code>version</code></td>
<td>
required.
<p>
the version string to be compared to the threshold
</p>
</td>
</tr>
</tbody>
</table>
## versions.is_at_least
<pre>
versions.is_at_least(<a href="#versions.is_at_least-threshold">threshold</a>, <a href="#versions.is_at_least-version">version</a>)
</pre>
Check that a version is higher or equals to a threshold.
### Parameters
<table class="params-table">
<colgroup>
<col class="col-param" />
<col class="col-description" />
</colgroup>
<tbody>
<tr id="versions.is_at_least-threshold">
<td><code>threshold</code></td>
<td>
required.
<p>
the minimum version string
</p>
</td>
</tr>
<tr id="versions.is_at_least-version">
<td><code>version</code></td>
<td>
required.
<p>
the version string to be compared to the threshold
</p>
</td>
</tr>
</tbody>
</table>

View File

@ -7,6 +7,7 @@ package(default_visibility = ["//visibility:public"])
bzl_library(
name = "build_test",
srcs = ["build_test.bzl"],
deps = ["//lib:new_sets"],
)
bzl_library(

View File

@ -28,6 +28,7 @@ def build_test(name, targets, **kwargs):
Typical usage:
```
load("@bazel_skylib//rules:build_test.bzl", "build_test")
build_test(
name = "my_build_test",
@ -35,6 +36,7 @@ def build_test(name, targets, **kwargs):
"//some/package:rule",
],
)
```
Args:
name: The name of the test rule.