Skip to content

Commit d7c7117

Browse files
authored
Add build_script_env_files crate annotation (bazelbuild#4166)
## Summary Add `build_script_env_files` support to `crate.annotation`, allowing environment files to be passed to generated `cargo_build_script` targets. The change: - Exposes `build_script_env_files` through bzlmod and legacy crate annotations. - Propagates the annotation through crate-universe configuration and build-script context. - Renders the attribute on generated `cargo_build_script` rules. - Supports unconditional and platform-selected values. - Updates the configuration digest. - Adds tests for annotation propagation and BUILD-file rendering. ## Testing - `bazel test //crate_universe:unit_test`
1 parent ea0592c commit d7c7117

20 files changed

Lines changed: 147 additions & 32 deletions

cargo/private/cargo_build_script_runner/bin.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,44 @@ use std::process::Command;
2424
use cargo_build_script_runner::cargo_manifest_dir::{remove_symlink, symlink, RunfilesMaker};
2525
use cargo_build_script_runner::{BuildScriptOutput, CompileAndLinkFlags, SUPPRESS_WARNINGS_ENV};
2626

27+
fn parse_env_file(contents: &str) -> Result<Vec<(String, String)>, String> {
28+
fn push_variable(
29+
variables: &mut Vec<(String, String)>,
30+
variable: &mut String,
31+
) -> Result<(), String> {
32+
let (key, value) = variable
33+
.split_once('=')
34+
.ok_or_else(|| "error: Wrong environment file format, should not happen".to_owned())?;
35+
variables.push((key.to_owned(), value.to_owned()));
36+
variable.clear();
37+
Ok(())
38+
}
39+
40+
let mut variables = Vec::new();
41+
let mut variable = String::new();
42+
43+
for line in contents.lines() {
44+
if let Some(value) = line.strip_suffix('\\') {
45+
variable.push_str(value);
46+
variable.push('\n');
47+
continue;
48+
}
49+
50+
variable.push_str(line);
51+
if !variable.is_empty() {
52+
push_variable(&mut variables, &mut variable)?;
53+
}
54+
}
55+
56+
// `str::lines` does not yield a final empty line, so finalize a value
57+
// whose last line ended in a continuation as well.
58+
if !variable.is_empty() {
59+
push_variable(&mut variables, &mut variable)?;
60+
}
61+
62+
Ok(variables)
63+
}
64+
2765
fn run_buildrs() -> Result<(), String> {
2866
// We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
2967
// some execution strategies and remote execution environments may use symlinks in ways which
@@ -107,25 +145,10 @@ fn run_buildrs() -> Result<(), String> {
107145
set_script_runfiles_env(&script_path, &mut command);
108146

109147
for dep_env_path in input_dep_env_paths.iter() {
110-
if let Ok(contents) = read_to_string(dep_env_path) {
111-
for line in contents.split('\n') {
112-
// split on empty contents will still produce a single empty string in iterable.
113-
if line.is_empty() {
114-
continue;
115-
}
116-
match line.split_once('=') {
117-
Some((key, value)) => {
118-
command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
119-
}
120-
_ => {
121-
return Err(
122-
"error: Wrong environment file format, should not happen".to_owned()
123-
)
124-
}
125-
}
126-
}
127-
} else {
128-
return Err("error: Dependency environment file unreadable".to_owned());
148+
let contents = read_to_string(dep_env_path)
149+
.map_err(|_| "error: Dependency environment file unreadable".to_owned())?;
150+
for (key, value) in parse_env_file(&contents)? {
151+
command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
129152
}
130153
}
131154

crate_universe/extensions.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,9 @@ _ANNOTATION_SELECT_ATTRS = {
14181418
"build_script_env": attr.string_dict(
14191419
doc = "Additional environment variables to set on a crate's `cargo_build_script::env` attribute.",
14201420
),
1421+
"build_script_env_files": _relative_label_list(
1422+
doc = "A list of labels to set on a crate's `cargo_build_script::build_script_env_files` attribute.",
1423+
),
14211424
"build_script_exec_properties": attr.string_dict(
14221425
doc = "Execution properties to set on a crate's `cargo_build_script::exec_properties` attribute.",
14231426
),

crate_universe/private/crate.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def _annotation(
9696
build_script_data_glob = None,
9797
build_script_deps = None,
9898
build_script_env = None,
99+
build_script_env_files = None,
99100
build_script_exec_properties = None,
100101
build_script_link_deps = None,
101102
build_script_proc_macro_deps = None,
@@ -143,6 +144,8 @@ def _annotation(
143144
attribute.
144145
build_script_deps (list, optional): A list of labels to add to a crate's `cargo_build_script::deps` attribute.
145146
build_script_env (dict, optional): Additional environment variables to set when running the crate's `cargo_build_script` - sets that target's `build_script_env` attribute.
147+
build_script_env_files (list, optional): A list of labels to set on a crate's
148+
`cargo_build_script::build_script_env_files` attribute.
146149
build_script_exec_properties (dict, optional): Execution properties to set on a crate's `cargo_build_script::exec_properties` attribute.
147150
build_script_link_deps: A list of labels to add to a crate's `cargo_build_script::link_deps` attribute.
148151
build_script_proc_macro_deps (list, optional): A list of labels to add to a crate's
@@ -214,6 +217,7 @@ def _annotation(
214217
build_script_data_glob = build_script_data_glob,
215218
build_script_deps = _stringify_list(build_script_deps),
216219
build_script_env = build_script_env,
220+
build_script_env_files = _stringify_list(build_script_env_files),
217221
build_script_exec_properties = build_script_exec_properties,
218222
build_script_link_deps = build_script_link_deps,
219223
build_script_proc_macro_deps = _stringify_list(build_script_proc_macro_deps),

crate_universe/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ pub(crate) struct CrateAnnotations {
357357
/// [build_script_env](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-rustc_env) attribute.
358358
pub(crate) build_script_env: Option<Select<BTreeMap<String, String>>>,
359359

360+
/// Additional environment variable files to pass to a build script's
361+
/// [build_script_env_files](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-build_script_env_files) attribute.
362+
pub(crate) build_script_env_files: Option<Select<BTreeSet<String>>>,
363+
360364
/// Additional rustc_env flags to pass to a build script's
361365
/// [rustc_env](https://bazelbuild.github.io/rules_rust/cargo.html#cargo_build_script-rustc_env) attribute.
362366
pub(crate) build_script_rustc_env: Option<Select<BTreeMap<String, String>>>,
@@ -473,6 +477,7 @@ impl Add for CrateAnnotations {
473477
build_script_tools: select_merge(self.build_script_tools, rhs.build_script_tools),
474478
build_script_data_glob: joined_extra_member!(self.build_script_data_glob, rhs.build_script_data_glob, BTreeSet::new, BTreeSet::extend),
475479
build_script_env: select_merge(self.build_script_env, rhs.build_script_env),
480+
build_script_env_files: select_merge(self.build_script_env_files, rhs.build_script_env_files),
476481
build_script_rustc_env: select_merge(self.build_script_rustc_env, rhs.build_script_rustc_env),
477482
build_script_exec_properties: select_merge(self.build_script_exec_properties, rhs.build_script_exec_properties),
478483
build_script_toolchains: joined_extra_member!(self.build_script_toolchains, rhs.build_script_toolchains, BTreeSet::new, BTreeSet::extend),

crate_universe/src/context/crate_context.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,12 @@ impl CrateContext {
710710
Select::merge(attrs.build_script_env.clone(), extra.clone());
711711
}
712712

713+
// Build script env files
714+
if let Some(extra) = &crate_extra.build_script_env_files {
715+
attrs.build_script_env_files =
716+
Select::merge(attrs.build_script_env_files.clone(), extra.clone());
717+
}
718+
713719
// Exec properties
714720
if let Some(extra) = &crate_extra.build_script_exec_properties {
715721
attrs.exec_properties =
@@ -1101,6 +1107,59 @@ mod test {
11011107
assert!(context.build_script_attrs.unwrap().data_glob.contains("**"));
11021108
}
11031109

1110+
#[test]
1111+
fn context_with_build_script_env_files_annotation() {
1112+
let mut build_script_env_files =
1113+
Select::from_value(BTreeSet::from(["@//:build-script.env".to_owned()]));
1114+
build_script_env_files.insert(
1115+
"@//:linux-build-script.env".to_owned(),
1116+
Some("x86_64-unknown-linux-gnu".to_owned()),
1117+
);
1118+
1119+
let mut config = crate::config::Config::default();
1120+
config.annotations.insert(
1121+
crate::config::CrateNameAndVersionReq::new(
1122+
"openssl-sys".to_owned(),
1123+
"0.9.87".parse().unwrap(),
1124+
),
1125+
CrateAnnotations {
1126+
build_script_env_files: Some(build_script_env_files.clone()),
1127+
..CrateAnnotations::default()
1128+
},
1129+
);
1130+
1131+
let annotations = Annotations::new(
1132+
crate::test::metadata::build_scripts(),
1133+
&None,
1134+
crate::test::lockfile::build_scripts(),
1135+
config,
1136+
Utf8Path::new("/tmp/bazelworkspace"),
1137+
)
1138+
.unwrap();
1139+
let package_id = PackageId {
1140+
repr: "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.87"
1141+
.to_owned(),
1142+
};
1143+
let crate_annotation = &annotations.metadata.crates[&package_id];
1144+
1145+
let context = CrateContext::new(
1146+
crate_annotation,
1147+
&annotations.metadata.packages,
1148+
&annotations.lockfile.crates,
1149+
&annotations.pairred_extras,
1150+
&annotations.metadata.workspace_metadata.tree_metadata,
1151+
false,
1152+
true,
1153+
false,
1154+
)
1155+
.unwrap();
1156+
1157+
assert_eq!(
1158+
context.build_script_attrs.unwrap().build_script_env_files,
1159+
build_script_env_files
1160+
);
1161+
}
1162+
11041163
#[test]
11051164
fn context_disabled_build_script() {
11061165
let annotations = build_script_annotations();

crate_universe/src/lockfile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ mod test {
305305
);
306306

307307
assert_eq!(
308-
Digest("c92abd7d08fb65f955500488beb775486f537d4ec30a5a2f1ea6dbeead3eace0".to_owned()),
308+
Digest("4e15466c65fbe0069462f551062a2e71fcc1b7a2f614c5df14eed322aa6f90a4".to_owned()),
309309
digest,
310310
);
311311
}

crate_universe/src/rendering.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,12 @@ impl Renderer {
691691
.unwrap_or_default(),
692692
platforms,
693693
),
694+
build_script_env_files: SelectSet::new(
695+
attrs
696+
.map(|attrs| attrs.build_script_env_files.clone())
697+
.unwrap_or_default(),
698+
platforms,
699+
),
694700
use_default_shell_env: attrs.and_then(|a| a.use_default_shell_env),
695701
use_cc_toolchain: attrs.and_then(|a| a.use_cc_toolchain),
696702
compile_data: make_data_with_exclude(
@@ -1387,6 +1393,9 @@ mod test {
13871393
let attrs = BuildScriptAttributes {
13881394
use_default_shell_env: Some(1),
13891395
use_cc_toolchain: Some(0),
1396+
build_script_env_files: Select::from_value(BTreeSet::from([
1397+
"//:build_script.env".to_owned()
1398+
])),
13901399
exec_properties: Select::from_value(BTreeMap::from([
13911400
("OSFamily".to_owned(), "Linux".to_owned()),
13921401
("container-image".to_owned(), "docker://my-image".to_owned()),
@@ -1473,6 +1482,16 @@ mod test {
14731482
"```\n{}```\n",
14741483
build_file_content
14751484
);
1485+
assert!(
1486+
build_file_content.contains("build_script_env_files = ["),
1487+
"```\n{}```\n",
1488+
build_file_content
1489+
);
1490+
assert!(
1491+
build_file_content.contains("\"//:build_script.env\""),
1492+
"```\n{}```\n",
1493+
build_file_content
1494+
);
14761495

14771496
// Ensure `cargo_build_script` requirements are met
14781497
assert!(build_file_content.contains("name = \"_bs\""));

crate_universe/src/utils/starlark.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ pub(crate) struct CargoBuildScript {
9898
pub(crate) aliases: SelectDict<Label, String>,
9999
#[serde(skip_serializing_if = "SelectDict::is_empty")]
100100
pub(crate) build_script_env: SelectDict<String, String>,
101+
#[serde(skip_serializing_if = "SelectSet::is_empty")]
102+
pub(crate) build_script_env_files: SelectSet<String>,
101103
#[serde(skip_serializing_if = "Data::is_empty")]
102104
pub(crate) compile_data: Data,
103105
#[serde(skip_serializing_if = "SelectDict::is_empty")]

crate_universe/tests/integration/alias_rule/cargo-bazel-lock_global_alias_annotation_none.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"checksum": "7fdbd86a97bee065cf950f2f32e3ef7b4be29aa190dbef98fdfeb5ea7248463a",
2+
"checksum": "fb5ba9be8b4537eaec17b6d71cf44b7307203b2d5712bbd663bef22df1945e20",
33
"crates": {
44
"direct-cargo-bazel-deps 0.0.1": {
55
"name": "direct-cargo-bazel-deps",

crate_universe/tests/integration/alias_rule/cargo-bazel-lock_global_alias_annotation_opt.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"checksum": "c54d4f51cc5814b68c9f857661b5026e76faadc13031a15813001c1355f33740",
2+
"checksum": "f78faae1578a3a1abf5c2a279bb1f19acde30a74ce0b3dd66b7e4aa51e0f19c2",
33
"crates": {
44
"direct-cargo-bazel-deps 0.0.1": {
55
"name": "direct-cargo-bazel-deps",

0 commit comments

Comments
 (0)