feat: add command attribute to run_binary
diff --git a/docs/run_binary.md b/docs/run_binary.md index d50db14..2beceef 100644 --- a/docs/run_binary.md +++ b/docs/run_binary.md
@@ -10,7 +10,7 @@ ## run_binary <pre> -run_binary(<a href="#run_binary-name">name</a>, <a href="#run_binary-tool">tool</a>, <a href="#run_binary-srcs">srcs</a>, <a href="#run_binary-args">args</a>, <a href="#run_binary-env">env</a>, <a href="#run_binary-outs">outs</a>, <a href="#run_binary-out_dirs">out_dirs</a>, <a href="#run_binary-mnemonic">mnemonic</a>, <a href="#run_binary-progress_message">progress_message</a>, +run_binary(<a href="#run_binary-name">name</a>, <a href="#run_binary-tool">tool</a>, <a href="#run_binary-command">command</a>, <a href="#run_binary-srcs">srcs</a>, <a href="#run_binary-args">args</a>, <a href="#run_binary-env">env</a>, <a href="#run_binary-outs">outs</a>, <a href="#run_binary-out_dirs">out_dirs</a>, <a href="#run_binary-mnemonic">mnemonic</a>, <a href="#run_binary-progress_message">progress_message</a>, <a href="#run_binary-execution_requirements">execution_requirements</a>, <a href="#run_binary-stamp">stamp</a>, <a href="#run_binary-output_dir">output_dir</a>, <a href="#run_binary-kwargs">kwargs</a>) </pre> @@ -25,7 +25,8 @@ | Name | Description | Default Value | | :------------- | :------------- | :------------- | | <a id="run_binary-name"></a>name | The target name | none | -| <a id="run_binary-tool"></a>tool | The tool to run in the action.<br><br>Must be the label of a *_binary rule of a rule that generates an executable file, or of a file that can be executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary with executable permission on Linux). This label is available for <code>$(location)</code> expansion in <code>args</code> and <code>env</code>. | none | +| <a id="run_binary-tool"></a>tool | The tool to run in the action.<br><br>Must be the label of a *_binary rule of a rule that generates an executable file, or of a file that can be executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary with executable permission on Linux). This label is available for <code>$(location)</code> expansion in <code>args</code> and <code>env</code>.<br><br>Only one of <code>command</code> or <code>tool</code> may be specified. | <code>None</code> | +| <a id="run_binary-command"></a>command | The command to run in the action.<br><br>Only one of <code>command</code> or <code>tool</code> may be specified. | <code>None</code> | | <a id="run_binary-srcs"></a>srcs | Additional inputs of the action.<br><br>These labels are available for <code>$(location)</code> expansion in <code>args</code> and <code>env</code>. | <code>[]</code> | | <a id="run_binary-args"></a>args | Command line arguments of the binary.<br><br>Subject to <code>$(location)</code> and makevar expansions. | <code>[]</code> | | <a id="run_binary-env"></a>env | Environment variables of the action.<br><br>Subject to <code>$(location)</code> and makevar expansions. | <code>{}</code> |
diff --git a/lib/private/run_binary.bzl b/lib/private/run_binary.bzl index d7fe14d..c0f4abc 100644 --- a/lib/private/run_binary.bzl +++ b/lib/private/run_binary.bzl
@@ -20,8 +20,11 @@ load("//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp") def _run_binary_impl(ctx): - tool_as_list = [ctx.attr.tool] - tool_inputs, tool_input_mfs = ctx.resolve_tools(tools = tool_as_list) + if not ctx.attr.tool and not ctx.attr.command: + fail("Either tool or command must be specified") + if ctx.attr.tool and ctx.attr.command: + fail("Only one of tool or command may be specified") + args = ctx.actions.args() outputs = [] @@ -35,19 +38,19 @@ fail("output directory {} is nested within output directory {}; outputs cannot be nested within each other!".format(out_dir.path, output.path)) outputs.append(out_dir) if len(outputs) < 1: - fail("""\ + msg = """\ ERROR: target {target} is not configured to produce any outputs. Bazel only executes actions when their outputs are required, so it's never correct to create an action with no outputs. Possible fixes: - Predict what outputs are created, and list them in the outs and out_dirs attributes. -- If {rule_kind} is a binary, and you meant to run it for its side-effects, - then call it directly with `bazel run` and don't wrap it in a run_binary rule. -""".format( - target = str(ctx.label), - rule_kind = str(ctx.attr.tool.label), - )) +""".format(target = str(ctx.label)) + if ctx.attr.tool: + msg += """- If {rule_kind} is a binary, and you meant to run it for its side-effects, +then call it directly with `bazel run` and don't wrap it in a run_binary rule. +""".format(rule_kind = str(ctx.attr.tool.label)) + fail(msg) # `expand_locations(...).split(" ")` is a work-around https://github.com/bazelbuild/bazel/issues/10309 # _expand_locations returns an array of args to support $(execpaths) expansions. @@ -67,19 +70,34 @@ else: inputs = ctx.files.srcs - ctx.actions.run( - outputs = outputs, - inputs = inputs, - tools = tool_inputs, - executable = ctx.executable.tool, - arguments = [args], - mnemonic = ctx.attr.mnemonic if ctx.attr.mnemonic else None, - progress_message = ctx.attr.progress_message if ctx.attr.progress_message else None, - execution_requirements = ctx.attr.execution_requirements if ctx.attr.execution_requirements else None, - use_default_shell_env = False, - env = dicts.add(ctx.configuration.default_shell_env, envs), - input_manifests = tool_input_mfs, - ) + if ctx.attr.tool: + tool_inputs, tool_input_mfs = ctx.resolve_tools(tools = [ctx.attr.tool]) + ctx.actions.run( + outputs = outputs, + inputs = inputs, + tools = tool_inputs, + executable = ctx.executable.tool, + arguments = [args], + mnemonic = ctx.attr.mnemonic if ctx.attr.mnemonic else None, + progress_message = ctx.attr.progress_message if ctx.attr.progress_message else None, + execution_requirements = ctx.attr.execution_requirements if ctx.attr.execution_requirements else None, + use_default_shell_env = False, + env = dicts.add(ctx.configuration.default_shell_env, envs), + input_manifests = tool_input_mfs, + ) + else: + ctx.actions.run_shell( + outputs = outputs, + inputs = inputs, + command = ctx.attr.command, + arguments = [args], + mnemonic = ctx.attr.mnemonic if ctx.attr.mnemonic else None, + progress_message = ctx.attr.progress_message if ctx.attr.progress_message else None, + execution_requirements = ctx.attr.execution_requirements if ctx.attr.execution_requirements else None, + use_default_shell_env = False, + env = dicts.add(ctx.configuration.default_shell_env, envs), + ) + return DefaultInfo( files = depset(outputs), runfiles = ctx.runfiles(files = outputs), @@ -91,9 +109,9 @@ "tool": attr.label( executable = True, allow_files = True, - mandatory = True, cfg = "exec", ), + "command": attr.string(), "env": attr.string_dict(), "srcs": attr.label_list( allow_files = True, @@ -109,7 +127,8 @@ def run_binary( name, - tool, + tool = None, + command = None, srcs = [], args = [], env = {}, @@ -135,6 +154,13 @@ a file that can be executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary with executable permission on Linux). This label is available for `$(location)` expansion in `args` and `env`. + + Only one of `command` or `tool` may be specified. + + command: The command to run in the action. + + Only one of `command` or `tool` may be specified. + srcs: Additional inputs of the action. These labels are available for `$(location)` expansion in `args` and `env`. @@ -213,6 +239,7 @@ _run_binary( name = name, tool = tool, + command = command, srcs = srcs, args = args, env = env,