cargo-bazel 0.18.0

A collection of tools which use Cargo to generate build targets for Bazel
Documentation
"""Utilities directly related to bootstrapping `cargo-bazel`"""

_SRCS_TEMPLATE = """\
\"\"\"A generate file containing all source files used to produce `cargo-bazel`\"\"\"

# Each source file is tracked as a target so the `cargo_bootstrap_repository`
# rule will know to automatically rebuild if any of the sources changed.

# Run 'bazel run //crate_universe/private:srcs_module.install' to regenerate.

CARGO_BAZEL_SRCS = [
    {srcs}
]
"""

def _format_src_label(label):
    if label.workspace_name != "":
        fail("`srcs` must be from the rules_rust repository")
    return "Label(\"{}\"),".format(str(label).lstrip("@"))

def _srcs_module_impl(ctx):
    srcs = [_format_src_label(src.owner) for src in sorted(ctx.files.srcs)]
    if not srcs:
        fail("`srcs` cannot be empty")
    output = ctx.actions.declare_file(ctx.label.name)

    ctx.actions.write(
        output = output,
        content = _SRCS_TEMPLATE.format(
            srcs = "\n    ".join(srcs),
        ),
    )

    return DefaultInfo(
        files = depset([output]),
    )

_srcs_module = rule(
    doc = "A rule for writing a list of sources to a templated file",
    implementation = _srcs_module_impl,
    attrs = {
        "srcs": attr.label(
            doc = "A filegroup of source files",
            allow_files = True,
        ),
    },
)

_INSTALLER_TEMPLATE = """\
#!/usr/bin/env bash
set -euo pipefail
cp -f "{path}" "${{BUILD_WORKSPACE_DIRECTORY}}/{dest}"
"""

def _srcs_installer_impl(ctx):
    output = ctx.actions.declare_file(ctx.label.name + ".sh")
    target_file = ctx.file.input
    dest = ctx.file.dest.short_path

    ctx.actions.write(
        output = output,
        content = _INSTALLER_TEMPLATE.format(
            path = target_file.short_path,
            dest = dest,
        ),
        is_executable = True,
    )

    return DefaultInfo(
        files = depset([output]),
        runfiles = ctx.runfiles(files = [target_file]),
        executable = output,
    )

_srcs_installer = rule(
    doc = "A rule for writing a file back to the repository",
    implementation = _srcs_installer_impl,
    attrs = {
        "dest": attr.label(
            doc = "the file name to use for installation",
            allow_single_file = True,
            mandatory = True,
        ),
        "input": attr.label(
            doc = "The file to write back to the repository",
            allow_single_file = True,
            mandatory = True,
        ),
    },
    executable = True,
)

def srcs_module(name, dest, **kwargs):
    """A helper rule to ensure the bootstrapping functionality of `cargo-bazel` is always up to date

    Args:
        name (str): The name of the sources module
        dest (str): The filename the module should be written as in the current package.
        **kwargs (dict): Additional keyword arguments
    """
    tags = kwargs.pop("tags", [])

    _srcs_module(
        name = name,
        tags = tags,
        **kwargs
    )

    _srcs_installer(
        name = name + ".install",
        input = name,
        dest = dest,
        tags = tags,
    )