Search code examples
bazel

How to get file object for file created in execpath in Bazel?


I have a bash script:

mkdir a_dir
echo "Hello World!" > a_dir/out1.txt
echo "Hello World!" > a_dir/out2.txt

I would like to create an action to run the script, and have the files it creates declared as outputs, and be able to pass them as inputs to other actions.

The problem is I can't figure out how to reference the files weather with ctx.actions.declare_file or some other method that I'm not aware of.

I think what I'm looking for is a method to get File objects that reference files under the execroot path.

Note: The actual binary I will be running instead of the bash script doesn't grant control over the path of its output, so declaring a file within the implementation function and passing it as a parameter to the binary is not an option.


Solution

  • After looking online and opening a thread on bazel-discuss, It seems like there isn't any way of declaring outputs outside of the output root.

    The solution I chose is creating a wrapper script which cds into the output directory, out_dir, which is evaluated as paths.join(ctx.bin_dir.path, ctx.label.package)

    The reason I chose cd rather mv or cp is discussed in the bazel-discuss thread.

    After cd into out_dir, the paths of files given to the binary as arguments are no longer valid, and can be fixed by prepending them with ..s. If the files that are to be fixed are in a depset and you require to fix the paths without converting the depset to a list, you can prepend the path-fix using the format_each parameter of args.add_all().

    This is not the most elegant solution, but as far as I know, does not compromise functionality. Here is some example code:

    # Inside implementation function:
    out_dir = paths.join(ctx.bin_dir.path, ctx.label.package)
    path_fix = "/".join(len(out_dir.split("/"))*[".."])
    args = ctx.actions.args()
    args.add_all(files_depset, format_each=path_fix+"/%s")
    ctx.actions.run_shell(..., command = "cd {out_dir}; {binary} $@".format(
        out_dir = out_dir,
        binary = your_binary
    ))