xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/private/bootstrap_utils.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1"""Utilities directly related to bootstrapping `cargo-bazel`"""
2
3_SRCS_TEMPLATE = """\
4\"\"\"A generate file containing all source files used to produce `cargo-bazel`\"\"\"
5
6# Each source file is tracked as a target so the `cargo_bootstrap_repository`
7# rule will know to automatically rebuild if any of the sources changed.
8
9# Run 'bazel run //crate_universe/private:srcs_module.install' to regenerate.
10
11CARGO_BAZEL_SRCS = [
12    {srcs}
13]
14"""
15
16def _format_src_label(label):
17    if label.workspace_name != "":
18        fail("`srcs` must be from the rules_rust repository")
19    return "Label(\"{}\"),".format(str(label).lstrip("@"))
20
21def _srcs_module_impl(ctx):
22    srcs = [_format_src_label(src.owner) for src in ctx.files.srcs]
23    if not srcs:
24        fail("`srcs` cannot be empty")
25    output = ctx.actions.declare_file(ctx.label.name)
26
27    ctx.actions.write(
28        output = output,
29        content = _SRCS_TEMPLATE.format(
30            srcs = "\n    ".join(srcs),
31        ),
32    )
33
34    return DefaultInfo(
35        files = depset([output]),
36    )
37
38_srcs_module = rule(
39    doc = "A rule for writing a list of sources to a templated file",
40    implementation = _srcs_module_impl,
41    attrs = {
42        "srcs": attr.label(
43            doc = "A filegroup of source files",
44            allow_files = True,
45        ),
46    },
47)
48
49_INSTALLER_TEMPLATE = """\
50#!/usr/bin/env bash
51set -euo pipefail
52cp -f "{path}" "${{BUILD_WORKSPACE_DIRECTORY}}/{dest}"
53"""
54
55def _srcs_installer_impl(ctx):
56    output = ctx.actions.declare_file(ctx.label.name + ".sh")
57    target_file = ctx.file.input
58    dest = ctx.file.dest.short_path
59
60    ctx.actions.write(
61        output = output,
62        content = _INSTALLER_TEMPLATE.format(
63            path = target_file.short_path,
64            dest = dest,
65        ),
66        is_executable = True,
67    )
68
69    return DefaultInfo(
70        files = depset([output]),
71        runfiles = ctx.runfiles(files = [target_file]),
72        executable = output,
73    )
74
75_srcs_installer = rule(
76    doc = "A rule for writing a file back to the repository",
77    implementation = _srcs_installer_impl,
78    attrs = {
79        "dest": attr.label(
80            doc = "the file name to use for installation",
81            allow_single_file = True,
82            mandatory = True,
83        ),
84        "input": attr.label(
85            doc = "The file to write back to the repository",
86            allow_single_file = True,
87            mandatory = True,
88        ),
89    },
90    executable = True,
91)
92
93def srcs_module(name, dest, **kwargs):
94    """A helper rule to ensure the bootstrapping functionality of `cargo-bazel` is always up to date
95
96    Args:
97        name (str): The name of the sources module
98        dest (str): The filename the module should be written as in the current package.
99        **kwargs (dict): Additional keyword arguments
100    """
101    tags = kwargs.pop("tags", [])
102
103    _srcs_module(
104        name = name,
105        tags = tags,
106        **kwargs
107    )
108
109    _srcs_installer(
110        name = name + ".install",
111        input = name,
112        dest = dest,
113        tags = tags,
114    )
115