I want to run a set of Bazel targets. My BUILD
file look like this
load("@rules_java//java:defs.bzl", "java_binary")
java_binary(
name = "run_me",
srcs = glob(["src1/main/java/com/example/*.java"]),
tags = ["java", "good"],
)
java_binary(
name = "me_also",
srcs = glob(["src2/main/java/com/example/*.java"]),
tags = ["java", "good"],
)
java_binary(
name = "do_not_run_me",
srcs = glob(["src3/main/java/com/example/*.java"]),
tags = ["java", "bad"],
)
I want to run all the targets tagged as "good". I'm hoping to be able to do something like
bazel query 'tags(["good"], //...)'
I don't see the ability to query for tags in the documentation. I do see attr
, so I tried
bazel query 'attr(tags, "\[good\]", //...)'
But that doesn't work. I assume because
List-type attributes (such as srcs, data, etc) are converted to strings of the form [value1, ..., valuen], starting with a [ bracket, ending with a ] bracket and using ", " (comma, space) to delimit multiple values
I am able to make it work with an exact match,
bazel query 'attr(tags, "\[good, java\]", //...)'
However, notice that
"\[java, good\]")
doesn't get any results). I'm not sure if it's alphabetizing or if it's putting them in a hash-set. But it means the ordering isn't reliable.Can I use tags for this task? Are tags really just intended for tests? (The test_suite
is the reason I thought to use tags in the first place.)
If by "run a set of Bazel targets" you mean bazel run
, you can use --build_tag_filters
for this:
https://docs.bazel.build/versions/3.2.0/command-line-reference.html#flag--build_tag_filters
Note however that bazel run
supports running only 1 executable target at a time.
If you want to run many binaries in a single call, you'll need to continue to pursue bazel query
.
The attr()
filter accepts a regular expression, so to get around the problem of tags being in arbitrary order, you can do something like:
bazel query "attr(tags, '\\bgood\\b', //...)"
(where \b
is the word boundary matcher)
If you have multiple tags, you can use intersect
:
bazel query "attr(tags, '\\bgood\\b', //...) intersect attr(tags, '\\balso-good\\b', //...)"
That will give you the list of targets to run, then you can do something like:
targets=$(bazel query "attr(tags, '\\bgood\\b', //...)")
bazel build ${targets[@]}
for target in ${targets[@]}; do
bazel run $target &
done
bazel run
will build the targets before running them, and bazel will wait on previous invocations of itself in the same workspace[1]. So to get the binaries to run in parallel (if that's something you want), the example builds all the targets before running them. (bazel won't block subsequent invocations of itself once the binary is running)
There's also another idea that seems nicer, which is to have an sh_binary
which depends on all the binaries you want to run, and the sh_binary
script simply runs them. You would then be able to do bazel run
on that single sh_binary
. The problem with that is you'd have to list each binary you want to run in the data
attribute of the sh_binary
, because it's not possible to create dependencies in a BUILD file using a query (despite there being a genquery
rule -- that just outputs the results of the query to a file).
[1] unless you have separate output bases using --output_base
for the different invocations