edc
edc

Reputation: 129

Using data dependency for bazel ctx.action.run_shell custom rule

I am looking at emit_rule example in bazel source tree:

https://github.com/bazelbuild/examples/blob/5a8696429e36090a75eb6fee4ef4e91a3413ef13/rules/shell_command/rules.bzl

I want to add a data dependency to the custom rule. My understanding of dependency attributes documentation calls for data attr label_list to be used, but it does not appear to work?

# This example copied from docs

def _emit_size_impl(ctx):
    in_file = ctx.file.file
    out_file = ctx.actions.declare_file("%s.pylint" % ctx.attr.name)
    ctx.actions.run_shell(
        inputs = [in_file],
        outputs = [out_file],
        command = "wc -c '%s' > '%s'" % (in_file.path, out_file.path),
    )   
    return [DefaultInfo(files = depset([out_file]),)]  

emit_size = rule(
    implementation = _emit_size_impl,
    attrs = { 
        "file": attr.label(mandatory = True,allow_single_file = True,),
        "data": attr.label_list(allow_files = True),
      # ^^^^^^^ Above does not appear to be sufficient to copy data dependency into sandbox 
    },
)

With this rule emit_size(name = "my_name", file = "my_file", data = ["my_data"]) I want to see my_data copied to bazel-out/ before running the command. How do I go about doing this?

Upvotes: 0

Views: 1244

Answers (1)

ahumesky
ahumesky

Reputation: 5006

The data files should be added as inputs to the actions that need those files, e.g. something like this:

def _emit_size_impl(ctx):
    in_file = ctx.file.file
    out_file = ctx.actions.declare_file("%s.pylint" % ctx.attr.name)
    ctx.actions.run_shell(
        inputs = [in_file] + ctx.files.data,
        outputs = [out_file],
        # For production rules, probably should use ctx.actions.run() and
        # ctx.actions.args():
        # https://bazel.build/rules/lib/Args
        command = "echo data is: ; %s ; wc -c '%s' > '%s'" % (
            "cat " + " ".join([d.path for d in ctx.files.data]),
            in_file.path, out_file.path),
    )   
    return [DefaultInfo(files = depset([out_file]),)]  

emit_size = rule(
    implementation = _emit_size_impl,
    attrs = { 
        "file": attr.label(mandatory = True, allow_single_file = True,),
        "data": attr.label_list(allow_files = True),
    },
)

BUILD:

load(":defs.bzl", "emit_size")

emit_size(
  name = "size",
  file = "file.txt",
  data = ["data1.txt", "data2.txt"],
)
$ bazel build size
INFO: Analyzed target //:size (4 packages loaded, 9 targets configured).
INFO: Found 1 target...
INFO: From Action size.pylint:
data is:
this is data
this is other data
Target //:size up-to-date:
  bazel-bin/size.pylint
INFO: Elapsed time: 0.323s, Critical Path: 0.02s
INFO: 2 processes: 1 internal, 1 linux-sandbox.
INFO: Build completed successfully, 2 total actions

$ cat bazel-bin/size.pylint
22 file.txt

Upvotes: 0

Related Questions