|
| 1 | +"""crates_vendor repository rules""" |
| 2 | + |
| 3 | +_ALIAS_TEMPLATE = """\ |
| 4 | +alias( |
| 5 | + name = "{alias_name}", |
| 6 | + actual = "{actual_label}", |
| 7 | + tags = ["manual"], |
| 8 | + visibility = ["//visibility:public"], |
| 9 | +) |
| 10 | +""" |
| 11 | + |
| 12 | +def _crates_vendor_remote_repository_impl(repository_ctx): |
| 13 | + # If aliases is provided, build_file must not be provided |
| 14 | + if repository_ctx.attr.aliases and repository_ctx.attr.build_file: |
| 15 | + fail("Cannot provide both 'aliases' and 'build_file' attributes. Use 'aliases' for subpackage aliases or 'build_file' for root package BUILD file.") |
| 16 | + |
| 17 | + defs_module = repository_ctx.path(repository_ctx.attr.defs_module) |
| 18 | + repository_ctx.file("defs.bzl", repository_ctx.read(defs_module)) |
| 19 | + repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format( |
| 20 | + repository_ctx.name, |
| 21 | + )) |
| 22 | + |
| 23 | + if repository_ctx.attr.aliases: |
| 24 | + # Render multiple BUILD files for aliases in subpackages |
| 25 | + # Each alias gets its own BUILD file in a subpackage named after the alias name |
| 26 | + # aliases maps String (actual label) -> String (alias name) |
| 27 | + root_aliases = [] |
| 28 | + for alias_name, actual_label_str in repository_ctx.attr.aliases.items(): |
| 29 | + # Create the subpackage directory and BUILD file |
| 30 | + # The alias_name is the subpackage name (e.g., "my_crate-0.1.0" -> "my_crate-0.1.0/BUILD.bazel") |
| 31 | + alias_build_content = _ALIAS_TEMPLATE.format( |
| 32 | + alias_name = alias_name, |
| 33 | + actual_label = actual_label_str, |
| 34 | + ) |
| 35 | + repository_ctx.file("{}/BUILD.bazel".format(alias_name), alias_build_content) |
| 36 | + |
| 37 | + # If legacy_root_pkg_aliases is True, also create aliases in the root BUILD file |
| 38 | + if repository_ctx.attr.legacy_root_pkg_aliases: |
| 39 | + root_aliases.append(_ALIAS_TEMPLATE.format( |
| 40 | + alias_name = alias_name, |
| 41 | + actual_label = "//{}".format(alias_name), |
| 42 | + )) |
| 43 | + |
| 44 | + # Render root BUILD file with aliases if legacy mode is enabled |
| 45 | + if repository_ctx.attr.legacy_root_pkg_aliases: |
| 46 | + root_build_content = "\n".join(root_aliases) + "\n" |
| 47 | + repository_ctx.file("BUILD.bazel", root_build_content) |
| 48 | + elif repository_ctx.attr.build_file: |
| 49 | + # Render the root BUILD file |
| 50 | + build_file = repository_ctx.path(repository_ctx.attr.build_file) |
| 51 | + repository_ctx.file("BUILD.bazel", repository_ctx.read(build_file)) |
| 52 | + else: |
| 53 | + fail("Must provide either 'aliases' or 'build_file' attribute. Please update {}".format( |
| 54 | + repository_ctx.name, |
| 55 | + )) |
| 56 | + |
| 57 | +crates_vendor_remote_repository = repository_rule( |
| 58 | + doc = "Creates a repository paired with `crates_vendor` targets using the `remote` vendor mode.", |
| 59 | + implementation = _crates_vendor_remote_repository_impl, |
| 60 | + attrs = { |
| 61 | + "aliases": attr.string_dict( |
| 62 | + doc = "A dictionary mapping alias actual values (label strings) to alias names. Each alias gets its own BUILD file in a subpackage named after the alias name. Cannot be provided if 'build_file' is set.", |
| 63 | + default = {}, |
| 64 | + ), |
| 65 | + "build_file": attr.label( |
| 66 | + doc = "The BUILD file to use for the root package. Cannot be provided if 'aliases' is set.", |
| 67 | + mandatory = False, |
| 68 | + ), |
| 69 | + "defs_module": attr.label( |
| 70 | + doc = "The `defs.bzl` file to use in the repository", |
| 71 | + mandatory = True, |
| 72 | + ), |
| 73 | + "legacy_root_pkg_aliases": attr.bool( |
| 74 | + doc = "If True and `aliases` is provided, also creates aliases in the root BUILD file with `name=\"{alias_name}\"` and `actual=\"//{alias_name}\"`. This provides backward compatibility for accessing aliases from the root package.", |
| 75 | + default = True, |
| 76 | + ), |
| 77 | + }, |
| 78 | +) |
0 commit comments