Skip to content

Commit 96628cd

Browse files
committed
Update crate_universe to now render subpackages instead of a single package
1 parent e0c8ac2 commit 96628cd

File tree

11 files changed

+685
-274
lines changed

11 files changed

+685
-274
lines changed

crate_universe/private/crates_vendor.bzl

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ load("//crate_universe/private:generate_utils.bzl", "compile_config", generate_r
44
load("//crate_universe/private:splicing_utils.bzl", "kebab_case_keys", generate_splicing_config = "splicing_config")
55
load("//crate_universe/private:urls.bzl", "CARGO_BAZEL_LABEL")
66
load("//rust/platform:triple_mappings.bzl", "SUPPORTED_PLATFORM_TRIPLES")
7+
load(":crates_vendor_repository.bzl", _crates_vendor_remote_repository = "crates_vendor_remote_repository")
8+
9+
crates_vendor_remote_repository = _crates_vendor_remote_repository
710

811
_UNIX_WRAPPER = """\
912
#!/usr/bin/env bash
@@ -337,16 +340,16 @@ def generate_config_file(
337340
if workspace_name != "":
338341
build_file_base_template = "@{}//{}:BUILD.{{name}}-{{version}}.bazel".format(workspace_name, output_pkg)
339342
crate_label_template = render_config["crate_label_template"]
340-
crate_alias_template = "@{{repository}}//:{{name}}-{{version}}".format(
343+
crate_alias_template = "@{{repository}}//{{name}}-{{version}}".format(
341344
output_pkg,
342345
)
343346

344347
# If `workspace_name` is blank (such as when using modules), the `@{}//{}:{{file}}` template would generate
345348
# a reference like `Label(@//<stuff>)`. This causes issues if the module doing the `crates_vendor`ing is not the root module.
346349
# See: https://github.com/bazelbuild/rules_rust/issues/2661
347-
crates_module_template_value = "//{}:{{file}}".format(output_pkg)
350+
crates_module_template_value = "//{}{{subpackage}}:{{file}}".format(output_pkg)
348351
if workspace_name != "":
349-
crates_module_template_value = "@{}//{}:{{file}}".format(
352+
crates_module_template_value = "@{}//{}{{subpackage}}:{{file}}".format(
350353
workspace_name,
351354
output_pkg,
352355
)
@@ -680,29 +683,3 @@ call against the generated workspace. The following table describes how to contr
680683
executable = True,
681684
toolchains = ["@rules_rust//rust:toolchain_type"],
682685
)
683-
684-
def _crates_vendor_remote_repository_impl(repository_ctx):
685-
build_file = repository_ctx.path(repository_ctx.attr.build_file)
686-
defs_module = repository_ctx.path(repository_ctx.attr.defs_module)
687-
688-
repository_ctx.file("BUILD.bazel", repository_ctx.read(build_file))
689-
repository_ctx.file("defs.bzl", repository_ctx.read(defs_module))
690-
repository_ctx.file("crates.bzl", "")
691-
repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
692-
repository_ctx.name,
693-
))
694-
695-
crates_vendor_remote_repository = repository_rule(
696-
doc = "Creates a repository paired with `crates_vendor` targets using the `remote` vendor mode.",
697-
implementation = _crates_vendor_remote_repository_impl,
698-
attrs = {
699-
"build_file": attr.label(
700-
doc = "The BUILD file to use for the root package",
701-
mandatory = True,
702-
),
703-
"defs_module": attr.label(
704-
doc = "The `defs.bzl` file to use in the repository",
705-
mandatory = True,
706-
),
707-
},
708-
)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
)

crate_universe/private/generate_utils.bzl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def get_generator(repository_ctx, host_triple):
9292
def render_config(
9393
build_file_template = "//:BUILD.{name}-{version}.bazel",
9494
crate_label_template = "@{repository}__{name}-{version}//:{target}",
95-
crate_alias_template = "//:{name}-{version}",
95+
crate_alias_template = "//{name}-{version}",
9696
crate_repository_template = "{repository}__{name}-{version}",
9797
crates_module_template = "//:{file}",
9898
default_alias_rule = "alias",
@@ -102,7 +102,8 @@ def render_config(
102102
platforms_template = "@rules_rust//rust/platform:{triple}",
103103
regen_command = None,
104104
vendor_mode = None,
105-
generate_rules_license_metadata = False):
105+
generate_rules_license_metadata = False,
106+
legacy_root_pkg_aliases = True):
106107
"""Various settings used to configure rendered outputs
107108
108109
The template parameters each support a select number of format keys. A description of each key
@@ -127,7 +128,7 @@ def render_config(
127128
crate_alias_template (str, optional): The template to use when referring to generated aliases within the external
128129
repository. The available format keys are [`{repository}`, `{name}`, `{version}`].
129130
crates_module_template (str, optional): The pattern to use for the `defs.bzl` and `BUILD.bazel`
130-
file names used for the crates module. The available format keys are [`{file}`].
131+
file names used for the crates module. The available format keys are [`{file}`, `{subpackage}`].
131132
default_alias_rule (str, option): Alias rule to use when generating aliases for all crates. Acceptable values
132133
are 'alias', 'dbg'/'fastbuild'/'opt' (transitions each crate's `compilation_mode`) or a string
133134
representing a rule in the form '<label to .bzl>:<rule>' that takes a single label parameter 'actual'.
@@ -145,6 +146,9 @@ def render_config(
145146
regen_command (str, optional): An optional command to demonstrate how generated files should be regenerated.
146147
vendor_mode (str, optional): An optional configuration for rendirng content to be rendered into repositories.
147148
generate_rules_license_metadata (bool, optional): Whether to generate rules license metadata
149+
legacy_root_pkg_aliases (bool, optional): Whether to generate legacy root package aliases pointing to
150+
subpackage aliases. When aliases are rendered into subpackages, this controls whether aliases are also
151+
generated in the root package that point to the subpackage locations. Defaults to True.
148152
149153
Returns:
150154
string: A json encoded struct to match the Rust `config::RenderConfig` struct
@@ -163,6 +167,7 @@ def render_config(
163167
platforms_template = platforms_template,
164168
regen_command = regen_command,
165169
vendor_mode = vendor_mode,
170+
legacy_root_pkg_aliases = legacy_root_pkg_aliases,
166171
))
167172

168173
def _crate_id(name, version):

crate_universe/src/cli/generate.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ pub fn generate(opt: GenerateOptions) -> Result<()> {
129129
.render(&context, opt.generator)?;
130130

131131
// make file paths compatible with bazel labels
132-
let normalized_outputs = normalize_cargo_file_paths(outputs, &opt.repository_dir);
132+
let normalized_outputs =
133+
normalize_cargo_file_paths(outputs, &opt.repository_dir, &None);
133134

134135
// Write the outputs to disk
135136
write_outputs(normalized_outputs, opt.dry_run)?;
@@ -216,7 +217,7 @@ pub fn generate(opt: GenerateOptions) -> Result<()> {
216217
.render(&context, opt.generator)?;
217218

218219
// make file paths compatible with bazel labels
219-
let normalized_outputs = normalize_cargo_file_paths(outputs, &opt.repository_dir);
220+
let normalized_outputs = normalize_cargo_file_paths(outputs, &opt.repository_dir, &None);
220221

221222
// Write the outputs to disk
222223
write_outputs(normalized_outputs, opt.dry_run)?;

crate_universe/src/cli/vendor.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,8 @@ pub fn vendor(opt: VendorOptions) -> anyhow::Result<()> {
293293
}
294294

295295
// make cargo versioned crates compatible with bazel labels
296-
let normalized_outputs = normalize_cargo_file_paths(outputs, &opt.workspace_dir);
296+
let normalized_outputs =
297+
normalize_cargo_file_paths(outputs, &opt.workspace_dir, &config.rendering.vendor_mode);
297298

298299
// buildifier files to check
299300
let file_names: BTreeSet<PathBuf> = normalized_outputs.keys().cloned().collect();

crate_universe/src/config.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ pub(crate) struct RenderConfig {
107107
/// Whether to generate cargo_toml_env_vars targets.
108108
/// This is expected to always be true except for bootstrapping.
109109
pub(crate) generate_cargo_toml_env_vars: bool,
110+
111+
/// Whether to generate legacy root package aliases pointing to subpackage aliases.
112+
/// When aliases are rendered into subpackages, this controls whether aliases are also
113+
/// generated in the root package that point to the subpackage locations.
114+
#[serde(default = "default_legacy_root_pkg_aliases")]
115+
pub(crate) legacy_root_pkg_aliases: bool,
110116
}
111117

112118
// Default is manually implemented so that the default values match the default
@@ -129,6 +135,7 @@ impl Default for RenderConfig {
129135
regen_command: String::default(),
130136
vendor_mode: Option::default(),
131137
generate_rules_license_metadata: default_generate_rules_license_metadata(),
138+
legacy_root_pkg_aliases: default_legacy_root_pkg_aliases(),
132139
}
133140
}
134141
}
@@ -144,15 +151,15 @@ fn default_build_file_template() -> String {
144151
}
145152

146153
fn default_crates_module_template() -> String {
147-
"//:{file}".to_owned()
154+
"//{subpackage}:{file}".to_owned()
148155
}
149156

150157
fn default_crate_label_template() -> String {
151158
"@{repository}__{name}-{version}//:{target}".to_owned()
152159
}
153160

154161
fn default_crate_alias_template() -> String {
155-
"//:{name}-{version}".to_owned()
162+
"//{name}-{version}".to_owned()
156163
}
157164

158165
fn default_crate_repository_template() -> String {
@@ -175,6 +182,10 @@ fn default_generate_rules_license_metadata() -> bool {
175182
false
176183
}
177184

185+
fn default_legacy_root_pkg_aliases() -> bool {
186+
true
187+
}
188+
178189
/// A representation of some Git identifier used to represent the "revision" or "pin" of a checkout.
179190
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord)]
180191
pub(crate) enum Commitish {

crate_universe/src/lockfile.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ mod test {
247247
);
248248

249249
assert_eq!(
250-
Digest("edd73970897c01af3bb0e6c9d62f572203dd38a03c189dcca555d463990aa086".to_owned()),
250+
Digest("cdbb4147046e1dd00738eb0ad254b8478d578208b1bfe6e8d6a1426ea5b00012".to_owned()),
251251
digest,
252252
);
253253
}
@@ -292,7 +292,7 @@ mod test {
292292
);
293293

294294
assert_eq!(
295-
Digest("17a426b0cb5c1eff5114997a35562bc8560afd365ec80ae31b3dcc449ee1fa60".to_owned()),
295+
Digest("21565b1e240cbc9bad180519849b5e4f00e5e12bee0405882994f55bf32936a7".to_owned()),
296296
digest,
297297
);
298298
}
@@ -323,7 +323,7 @@ mod test {
323323
);
324324

325325
assert_eq!(
326-
Digest("1e01331686ba1f26f707dc098cd9d21c39d6ccd8e46be03329bb2470d3833e15".to_owned()),
326+
Digest("fcc183f52ab0f38028cf201bcb459122f6b4cd8e63b334edbcac882b9c832e76".to_owned()),
327327
digest,
328328
);
329329
}
@@ -372,7 +372,7 @@ mod test {
372372
);
373373

374374
assert_eq!(
375-
Digest("45ccf7109db2d274420fac521f4736a1fb55450ec60e6df698e1be4dc2c89fad".to_owned()),
375+
Digest("24e34c5b59fb474cc6f6979a5d137288f637f1b4114d5012ba8ee781b2aaae71".to_owned()),
376376
digest,
377377
);
378378
}

0 commit comments

Comments
 (0)