From 96628cde659455e95581983e5029f5a95f3c78d8 Mon Sep 17 00:00:00 2001 From: UebelAndre Date: Wed, 19 Nov 2025 18:15:14 -0800 Subject: [PATCH 1/3] Update crate_universe to now render subpackages instead of a single package --- crate_universe/private/crates_vendor.bzl | 35 +- .../private/crates_vendor_repository.bzl | 78 ++ crate_universe/private/generate_utils.bzl | 11 +- crate_universe/src/cli/generate.rs | 5 +- crate_universe/src/cli/vendor.rs | 3 +- crate_universe/src/config.rs | 15 +- crate_universe/src/lockfile.rs | 8 +- crate_universe/src/rendering.rs | 664 ++++++++++++------ .../src/rendering/templates/module_bzl.j2 | 106 ++- .../src/rendering/templates/vendor_module.j2 | 13 +- crate_universe/src/utils.rs | 21 +- 11 files changed, 685 insertions(+), 274 deletions(-) create mode 100644 crate_universe/private/crates_vendor_repository.bzl diff --git a/crate_universe/private/crates_vendor.bzl b/crate_universe/private/crates_vendor.bzl index ca18c11cd6..cc6566a4a8 100644 --- a/crate_universe/private/crates_vendor.bzl +++ b/crate_universe/private/crates_vendor.bzl @@ -4,6 +4,9 @@ load("//crate_universe/private:generate_utils.bzl", "compile_config", generate_r load("//crate_universe/private:splicing_utils.bzl", "kebab_case_keys", generate_splicing_config = "splicing_config") load("//crate_universe/private:urls.bzl", "CARGO_BAZEL_LABEL") load("//rust/platform:triple_mappings.bzl", "SUPPORTED_PLATFORM_TRIPLES") +load(":crates_vendor_repository.bzl", _crates_vendor_remote_repository = "crates_vendor_remote_repository") + +crates_vendor_remote_repository = _crates_vendor_remote_repository _UNIX_WRAPPER = """\ #!/usr/bin/env bash @@ -337,16 +340,16 @@ def generate_config_file( if workspace_name != "": build_file_base_template = "@{}//{}:BUILD.{{name}}-{{version}}.bazel".format(workspace_name, output_pkg) crate_label_template = render_config["crate_label_template"] - crate_alias_template = "@{{repository}}//:{{name}}-{{version}}".format( + crate_alias_template = "@{{repository}}//{{name}}-{{version}}".format( output_pkg, ) # If `workspace_name` is blank (such as when using modules), the `@{}//{}:{{file}}` template would generate # a reference like `Label(@//)`. This causes issues if the module doing the `crates_vendor`ing is not the root module. # See: https://github.com/bazelbuild/rules_rust/issues/2661 - crates_module_template_value = "//{}:{{file}}".format(output_pkg) + crates_module_template_value = "//{}{{subpackage}}:{{file}}".format(output_pkg) if workspace_name != "": - crates_module_template_value = "@{}//{}:{{file}}".format( + crates_module_template_value = "@{}//{}{{subpackage}}:{{file}}".format( workspace_name, output_pkg, ) @@ -680,29 +683,3 @@ call against the generated workspace. The following table describes how to contr executable = True, toolchains = ["@rules_rust//rust:toolchain_type"], ) - -def _crates_vendor_remote_repository_impl(repository_ctx): - build_file = repository_ctx.path(repository_ctx.attr.build_file) - defs_module = repository_ctx.path(repository_ctx.attr.defs_module) - - repository_ctx.file("BUILD.bazel", repository_ctx.read(build_file)) - repository_ctx.file("defs.bzl", repository_ctx.read(defs_module)) - repository_ctx.file("crates.bzl", "") - repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format( - repository_ctx.name, - )) - -crates_vendor_remote_repository = repository_rule( - doc = "Creates a repository paired with `crates_vendor` targets using the `remote` vendor mode.", - implementation = _crates_vendor_remote_repository_impl, - attrs = { - "build_file": attr.label( - doc = "The BUILD file to use for the root package", - mandatory = True, - ), - "defs_module": attr.label( - doc = "The `defs.bzl` file to use in the repository", - mandatory = True, - ), - }, -) diff --git a/crate_universe/private/crates_vendor_repository.bzl b/crate_universe/private/crates_vendor_repository.bzl new file mode 100644 index 0000000000..fd667a44f1 --- /dev/null +++ b/crate_universe/private/crates_vendor_repository.bzl @@ -0,0 +1,78 @@ +"""crates_vendor repository rules""" + +_ALIAS_TEMPLATE = """\ +alias( + name = "{alias_name}", + actual = "{actual_label}", + tags = ["manual"], + visibility = ["//visibility:public"], +) +""" + +def _crates_vendor_remote_repository_impl(repository_ctx): + # If aliases is provided, build_file must not be provided + if repository_ctx.attr.aliases and repository_ctx.attr.build_file: + fail("Cannot provide both 'aliases' and 'build_file' attributes. Use 'aliases' for subpackage aliases or 'build_file' for root package BUILD file.") + + defs_module = repository_ctx.path(repository_ctx.attr.defs_module) + repository_ctx.file("defs.bzl", repository_ctx.read(defs_module)) + repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format( + repository_ctx.name, + )) + + if repository_ctx.attr.aliases: + # Render multiple BUILD files for aliases in subpackages + # Each alias gets its own BUILD file in a subpackage named after the alias name + # aliases maps String (actual label) -> String (alias name) + root_aliases = [] + for alias_name, actual_label_str in repository_ctx.attr.aliases.items(): + # Create the subpackage directory and BUILD file + # The alias_name is the subpackage name (e.g., "my_crate-0.1.0" -> "my_crate-0.1.0/BUILD.bazel") + alias_build_content = _ALIAS_TEMPLATE.format( + alias_name = alias_name, + actual_label = actual_label_str, + ) + repository_ctx.file("{}/BUILD.bazel".format(alias_name), alias_build_content) + + # If legacy_root_pkg_aliases is True, also create aliases in the root BUILD file + if repository_ctx.attr.legacy_root_pkg_aliases: + root_aliases.append(_ALIAS_TEMPLATE.format( + alias_name = alias_name, + actual_label = "//{}".format(alias_name), + )) + + # Render root BUILD file with aliases if legacy mode is enabled + if repository_ctx.attr.legacy_root_pkg_aliases: + root_build_content = "\n".join(root_aliases) + "\n" + repository_ctx.file("BUILD.bazel", root_build_content) + elif repository_ctx.attr.build_file: + # Render the root BUILD file + build_file = repository_ctx.path(repository_ctx.attr.build_file) + repository_ctx.file("BUILD.bazel", repository_ctx.read(build_file)) + else: + fail("Must provide either 'aliases' or 'build_file' attribute. Please update {}".format( + repository_ctx.name, + )) + +crates_vendor_remote_repository = repository_rule( + doc = "Creates a repository paired with `crates_vendor` targets using the `remote` vendor mode.", + implementation = _crates_vendor_remote_repository_impl, + attrs = { + "aliases": attr.string_dict( + 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.", + default = {}, + ), + "build_file": attr.label( + doc = "The BUILD file to use for the root package. Cannot be provided if 'aliases' is set.", + mandatory = False, + ), + "defs_module": attr.label( + doc = "The `defs.bzl` file to use in the repository", + mandatory = True, + ), + "legacy_root_pkg_aliases": attr.bool( + 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.", + default = True, + ), + }, +) diff --git a/crate_universe/private/generate_utils.bzl b/crate_universe/private/generate_utils.bzl index 0f104b0d5c..b38a437f3d 100644 --- a/crate_universe/private/generate_utils.bzl +++ b/crate_universe/private/generate_utils.bzl @@ -92,7 +92,7 @@ def get_generator(repository_ctx, host_triple): def render_config( build_file_template = "//:BUILD.{name}-{version}.bazel", crate_label_template = "@{repository}__{name}-{version}//:{target}", - crate_alias_template = "//:{name}-{version}", + crate_alias_template = "//{name}-{version}", crate_repository_template = "{repository}__{name}-{version}", crates_module_template = "//:{file}", default_alias_rule = "alias", @@ -102,7 +102,8 @@ def render_config( platforms_template = "@rules_rust//rust/platform:{triple}", regen_command = None, vendor_mode = None, - generate_rules_license_metadata = False): + generate_rules_license_metadata = False, + legacy_root_pkg_aliases = True): """Various settings used to configure rendered outputs The template parameters each support a select number of format keys. A description of each key @@ -127,7 +128,7 @@ def render_config( crate_alias_template (str, optional): The template to use when referring to generated aliases within the external repository. The available format keys are [`{repository}`, `{name}`, `{version}`]. crates_module_template (str, optional): The pattern to use for the `defs.bzl` and `BUILD.bazel` - file names used for the crates module. The available format keys are [`{file}`]. + file names used for the crates module. The available format keys are [`{file}`, `{subpackage}`]. default_alias_rule (str, option): Alias rule to use when generating aliases for all crates. Acceptable values are 'alias', 'dbg'/'fastbuild'/'opt' (transitions each crate's `compilation_mode`) or a string representing a rule in the form '