| """Implementation for yq rule""" |
| |
| load("//lib:stamping.bzl", "STAMP_ATTRS", "maybe_stamp") |
| |
| _yq_attrs = dict({ |
| "srcs": attr.label_list( |
| allow_files = True, |
| mandatory = True, |
| allow_empty = True, |
| ), |
| "expression": attr.string(mandatory = False), |
| "args": attr.string_list(), |
| "outs": attr.output_list(mandatory = True), |
| "_parse_status_file_expression": attr.label( |
| allow_single_file = True, |
| default = Label("//lib/private:parse_status_file.yq"), |
| ), |
| }, **STAMP_ATTRS) |
| |
| def is_split_operation(args): |
| for arg in args: |
| if arg.startswith("-s") or arg.startswith("--split-exp"): |
| return True |
| return False |
| |
| def _escape_path(path): |
| return "/".join([".." for t in path.split("/")]) + "/" |
| |
| def _yq_impl(ctx): |
| yq_bin = ctx.toolchains["@aspect_bazel_lib//lib:yq_toolchain_type"].yqinfo.bin |
| |
| outs = ctx.outputs.outs |
| args = ctx.attr.args[:] |
| inputs = ctx.files.srcs[:] |
| |
| split_operation = is_split_operation(args) |
| |
| if "eval" in args or "eval-all" in args: |
| fail("Do not pass 'eval' or 'eval-all' into yq; this is already set based on the number of srcs") |
| if not split_operation and len(outs) > 1: |
| fail("Cannot specify multiple outputs when -s or --split-exp is not set") |
| if "-i" in args or "--inplace" in args: |
| fail("Cannot use arg -i or --inplace as it is not bazel-idiomatic to update the input file; consider using write_source_files to write back to the source tree") |
| if len(ctx.attr.srcs) == 0 and "-n" not in args and "--null-input" not in args: |
| args = args + ["--null-input"] |
| |
| stamp = maybe_stamp(ctx) |
| stamp_yaml = ctx.actions.declare_file("_%s_stamp.yaml" % ctx.label.name) |
| if stamp: |
| # create an action that gives a YAML representation of the stamp keys |
| ctx.actions.run_shell( |
| tools = [yq_bin], |
| inputs = [stamp.stable_status_file, stamp.volatile_status_file, ctx.file._parse_status_file_expression], |
| outputs = [stamp_yaml], |
| command = "{yq} --from-file {expression} {stable} {volatile} > {out}".format( |
| yq = yq_bin.path, |
| expression = ctx.file._parse_status_file_expression.path, |
| stable = stamp.stable_status_file.path, |
| volatile = stamp.volatile_status_file.path, |
| out = stamp_yaml.path, |
| ), |
| mnemonic = "ConvertStatusToYaml", |
| ) |
| else: |
| # create an empty stamp file as placeholder |
| ctx.actions.write( |
| output = stamp_yaml, |
| content = "{}", |
| ) |
| inputs.append(stamp_yaml) |
| |
| # For split operations, yq outputs files in the same directory so we |
| # must cd to the correct output dir before executing it |
| bin_dir = "/".join([ctx.bin_dir.path, ctx.label.package]) if ctx.label.package else ctx.bin_dir.path |
| escape_bin_dir = _escape_path(bin_dir) |
| cmd = "cd {bin_dir} && {yq} {args} {eval_cmd} {expression} {sources} {maybe_out}".format( |
| bin_dir = ctx.bin_dir.path + "/" + ctx.label.package, |
| yq = escape_bin_dir + yq_bin.path, |
| eval_cmd = "eval" if len(inputs) <= 1 else "eval-all", |
| args = " ".join(args), |
| expression = "'%s'" % ctx.attr.expression if ctx.attr.expression else "", |
| sources = " ".join(["'%s%s'" % (escape_bin_dir, file.path) for file in ctx.files.srcs]), |
| # In the -s/--split-exr case, the out file names are determined by the yq expression |
| maybe_out = (" > %s%s" % (escape_bin_dir, outs[0].path)) if len(outs) == 1 else "", |
| ) |
| |
| ctx.actions.run_shell( |
| tools = [yq_bin], |
| inputs = inputs, |
| outputs = outs, |
| command = cmd, |
| env = {"STAMP": escape_bin_dir + stamp_yaml.path}, |
| mnemonic = "Yq", |
| ) |
| |
| return DefaultInfo(files = depset(outs), runfiles = ctx.runfiles(outs)) |
| |
| yq_lib = struct( |
| attrs = _yq_attrs, |
| implementation = _yq_impl, |
| ) |