Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you run the executables of other rules within a Bazel rule?

Say I have a custom rule, my_object. It looks like:

my_object(
  name = "foo",
  deps = [
    //services/image-A:push,
    //services/image-B:push,
  ]
)

Where the labels in deps are rules_docker's container_push rules.

I want to be able to bazel run //:foo and have it push the Docker images within the deps list. How do I do this?

This seems to be a specific case of just generally wanting to run the executables of other rules within the executable of a custom rule.

like image 304
thundergolfer Avatar asked Nov 08 '19 06:11

thundergolfer


People also ask

How do I run Bazel commands?

To run Bazel, go to your base workspace directory or any of its subdirectories and type bazel . % bazel help [Bazel release bazel-<version>] Usage: bazel <command> <options> ... Available commands: analyze-profile Analyzes build profile data.

What is CTX in Bazel?

A context object that is passed to the implementation function for a rule or aspect. It provides access to the information and methods needed to analyze the current target.

What is Bazel extension?

Bazel extensions are files ending in . bzl . Use a load statement to import a symbol from an extension. Before learning the more advanced concepts, first: Read about the Starlark language, used in both the BUILD and .

What is a Bazel target?

target-name is the name of the target within the package. The name of a rule is the value of the name attribute in the rule's declaration in a BUILD file; the name of a file is its pathname relative to the directory containing the BUILD file.


1 Answers

The thing to do here is to have my_object output an executable that executes the other executables.

Consider this example:

def _impl1(ctx):
  ctx.actions.write(
    output = ctx.outputs.executable,
    is_executable = True,
    content = "echo %s 123" % ctx.label.name)
  return DefaultInfo(executable = ctx.outputs.executable)


exec_rule1 = rule(
  implementation = _impl1,
  executable = True,
)


def _impl2(ctx):

  executable_paths = []
  runfiles = ctx.runfiles()
  for dep in ctx.attr.deps:
    # the "./" is needed if the executable is in the current directory
    # (i.e. in the workspace root)
    executable_paths.append("./" + dep.files_to_run.executable.short_path)
    # collect the runfiles of the other executables so their own runfiles
    # will be available when the top-level executable runs
    runfiles = runfiles.merge(dep.default_runfiles)

  ctx.actions.write(
    output = ctx.outputs.executable,
    is_executable = True,
    content = "\n".join(executable_paths))

  return DefaultInfo(
    executable = ctx.outputs.executable,
    runfiles = runfiles)


exec_rule2 = rule(
  implementation = _impl2,
  executable = True,
  attrs = {
    "deps": attr.label_list(),
  },
)

BUILD.bazel:

load(":defs.bzl", "exec_rule1", "exec_rule2")

exec_rule1(name = "foo")
exec_rule1(name = "bar")
exec_rule2(name = "baz", deps = [":foo", ":bar"])

and then running it:

$ bazel run //:baz
INFO: Analyzed target //:baz (4 packages loaded, 19 targets configured).
INFO: Found 1 target...
Target //:baz up-to-date:
  bazel-bin/baz
INFO: Elapsed time: 0.211s, Critical Path: 0.01s
INFO: 0 processes.
INFO: Build completed successfully, 6 total actions
INFO: Build completed successfully, 6 total actions
foo 123
bar 123
like image 127
ahumesky Avatar answered Nov 15 '22 08:11

ahumesky