cydonian
cydonian

Reputation: 1816

Bazel: map set(files) -> set(targets)

According to https://docs.bazel.build/versions/master/query-how-to.html#What_build_rule_contains_file_ja,

fullname=$(bazel query path/to/file/bar.java)
bazel query "attr('srcs', $fullname, ${fullname//:*/}:*)"

will tell me which target bar.java belongs to.

How can I get the set of targets that multiple files belong to? I.e. map set(files) -> set(targets). I could do this in serial, but each bazel call is fairly expensive and slow---I want to get it done in one call.

Context: I'd like to do this (build targets pertaining to a few files):

git diff HEAD~ | xargs bazel query "get targets for set(files)" | xargs bazel build

I feel like this capability must already exist, but I haven't been able to find it.

Upvotes: 1

Views: 617

Answers (1)

ahumesky
ahumesky

Reputation: 5006

Using query will work, but you can also use aquery for a more direct approach. https://docs.bazel.build/versions/master/aquery.html

BUILD:

genrule(
  name = "gen1",
  srcs = ["a"],
  outs = ["gen1.out"],
  cmd = "echo foo > $@",
)

pkg/BUILD:

genrule(
  name = "gen2",
  srcs = ["b"],
  outs = ["gen2.out"],
  cmd = "echo foo > $@",
)
$ bazel aquery "inputs('a|pkg/b', ...)" --include_artifacts=false --include_commandline=false
INFO: Analyzed 2 targets (6 packages loaded, 10 targets configured).
INFO: Found 2 targets...
action 'Executing genrule //pkg:gen2'
  Mnemonic: Genrule
  Target: //pkg:gen2
  Configuration: k8-fastbuild
  ActionKey: 8d7d05620bfd8303aa66488e0cd6586d8e978197126cdb41c5fc8c49c81988ef

action 'Executing genrule //:gen1'
  Mnemonic: Genrule
  Target: //:gen1
  Configuration: k8-fastbuild
  ActionKey: d4c76a6b6913ce5d887829dbc00d101c1cf5b0ff5240ed13ea328c26e4b41960

INFO: Elapsed time: 0.198s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions

inputs (like attr) accepts a regular expression, so you can "or" the files together with |. Then just filter for Target:, or use one of the other outputs (--output=(proto|textproto|jsonproto))

This has the advantages that:

  1. you don't need to figure out the labels of the files first (since attr in query operates on labels).
  2. aquery queries after the analysis phase, so your results are more accurate because it accounts for configuration (flags, etc).
  3. this will work for any attribute, since it's querying the inputs of all actions, which is at a lower level than rules

On the other hand, since aquery runs loading + analysis, it might take longer than query, since query just runs the loading phase.

Upvotes: 2

Related Questions