Skip to content

Commit 002cc06

Browse files
authored
Update crate_universe to run Buildifier on stdin (#3912)
closes #2972
1 parent fc00eac commit 002cc06

File tree

5 files changed

+97
-52
lines changed

5 files changed

+97
-52
lines changed
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
fn main() {
2-
let contents = std::fs::read_to_string("cargo/tests/cargo_build_script/run_from_exec_root/data.txt")
3-
.expect("Failed to read data file");
2+
let contents =
3+
std::fs::read_to_string("cargo/tests/cargo_build_script/run_from_exec_root/data.txt")
4+
.expect("Failed to read data file");
45
println!("cargo:rustc-env=DATA={}", contents);
56
}

crate_universe/private/vendor_utils.bzl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
44
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
55

6-
_BUILDIFIER_VERSION = "8.0.3"
6+
_BUILDIFIER_VERSION = "8.5.1"
77
_BUILDIFIER_URL_TEMPLATE = "https://github.com/bazelbuild/buildtools/releases/download/v{version}/{bin}"
88
_BUILDIFIER_INTEGRITY = {
9-
"buildifier-darwin-amd64": "sha256-t6MVLN4LOXGxEH8idK/neMXBVNzfbJxmmiMePABPBH4=",
10-
"buildifier-darwin-arm64": "sha256-Z0xmP3tc0DwAL4yoNKjBwAjMtSegoqEy0Ip6NViDsi0=",
11-
"buildifier-linux-amd64": "sha256-yWlIfBr4XnCFdsjf3Qu0aB6uWKrXnmiuSIgscIcYQbc=",
12-
"buildifier-linux-arm64": "sha256-vdm5Lixl1Gr/7srvtU5o00wnLR9KjFtUkpo+kqt4ggo=",
13-
"buildifier-windows-amd64.exe": "sha256-Y6JC9X4lPv57lXPXOcCKPQ5ijv2EAVyNrRfYe2Qp5EM=",
9+
"buildifier-darwin-amd64": "sha256-Md4Ynho/5Tqp6Mj3SgMJwyUnStGXkzk5GeHKZRY8oaQ=",
10+
"buildifier-darwin-arm64": "sha256-YoNqlmf6DbMJsNkehA8KPygTqcjqPkS5zVgYfJC8iLo=",
11+
"buildifier-linux-amd64": "sha256-iHN3/GTSOoUPTRigd7XbBbGZE/S5mycNGT88czS1qac=",
12+
"buildifier-linux-arm64": "sha256-lHv2cA1wgCayBXsJvqCau8PK/BXZ7Oo1uziFxLCczQQ=",
13+
"buildifier-windows-amd64.exe": "sha256-9Oy5xz3ivDi4RdTuJ2aPYkjEgTpmR9tLSTGnVWBS5OE=",
1414
}
1515

1616
def crates_vendor_deps():

crate_universe/src/cli/vendor.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//! The cli entrypoint for the `vendor` subcommand
22
3-
use std::collections::{BTreeSet, HashMap};
3+
use std::collections::{BTreeMap, HashMap};
44
use std::env;
55
use std::fs;
6+
use std::io::Write;
67
use std::path::{Path, PathBuf};
78
use std::process::{self, ExitStatus};
89
use std::sync::Arc;
@@ -89,19 +90,41 @@ pub struct VendorOptions {
8990
pub nonhermetic_root_bazel_workspace_dir: Utf8PathBuf,
9091
}
9192

92-
/// Run buildifier on a given file.
93-
fn buildifier_format(bin: &Path, file: &Path) -> anyhow::Result<ExitStatus> {
94-
let status = process::Command::new(bin)
93+
/// Format content via buildifier's stdin/stdout, avoiding the need to write
94+
/// the file to disk before formatting. The `path` argument is passed as
95+
/// `--path` so buildifier can infer the file type (BUILD vs .bzl).
96+
///
97+
/// See <https://github.com/bazelbuild/rules_rust/issues/2972>.
98+
fn buildifier_format(bin: &Path, content: &str, path: &Path) -> anyhow::Result<String> {
99+
let mut child = process::Command::new(bin)
95100
.args(["-lint=fix", "-mode=fix", "-warnings=all"])
96-
.arg(file)
97-
.status()
98-
.context("Failed to apply buildifier fixes")?;
99-
100-
if !status.success() {
101-
bail!(status)
101+
.arg(format!("--path={}", path.display()))
102+
.stdin(process::Stdio::piped())
103+
.stdout(process::Stdio::piped())
104+
.stderr(process::Stdio::piped())
105+
.spawn()
106+
.context("Failed to spawn buildifier")?;
107+
108+
child
109+
.stdin
110+
.take()
111+
.unwrap()
112+
.write_all(content.as_bytes())
113+
.context("Failed to write to buildifier stdin")?;
114+
115+
let output = child
116+
.wait_with_output()
117+
.context("Failed to wait for buildifier")?;
118+
119+
if !output.status.success() {
120+
bail!(
121+
"buildifier failed on {}: {}",
122+
path.display(),
123+
String::from_utf8_lossy(&output.stderr)
124+
);
102125
}
103126

104-
Ok(status)
127+
String::from_utf8(output.stdout).context("buildifier produced invalid UTF-8")
105128
}
106129

107130
/// Run `bazel mod tidy` in a workspace.
@@ -295,21 +318,25 @@ pub fn vendor(opt: VendorOptions) -> anyhow::Result<()> {
295318
// make cargo versioned crates compatible with bazel labels
296319
let normalized_outputs = normalize_cargo_file_paths(outputs, &opt.workspace_dir);
297320

298-
// buildifier files to check
299-
let file_names: BTreeSet<PathBuf> = normalized_outputs.keys().cloned().collect();
321+
// Optionally format outputs through buildifier before writing to disk.
322+
// Piping via stdin avoids a race where a freshly-written file may not yet
323+
// be visible to the buildifier subprocess.
324+
let normalized_outputs = if let Some(ref buildifier_bin) = opt.buildifier {
325+
normalized_outputs
326+
.into_iter()
327+
.map(|(path, content)| {
328+
let formatted = buildifier_format(buildifier_bin, &content, &path)
329+
.with_context(|| format!("Failed to run buildifier on {}", path.display()))?;
330+
Ok((path, formatted))
331+
})
332+
.collect::<anyhow::Result<BTreeMap<_, _>>>()?
333+
} else {
334+
normalized_outputs
335+
};
300336

301337
// Write outputs
302338
write_outputs(normalized_outputs, opt.dry_run).context("Failed writing output files")?;
303339

304-
// Optionally apply buildifier fixes
305-
if let Some(buildifier_bin) = opt.buildifier {
306-
for file in file_names {
307-
let file_path = opt.workspace_dir.join(file);
308-
buildifier_format(&buildifier_bin, &file_path)
309-
.with_context(|| format!("Failed to run buildifier on {}", file_path.display()))?;
310-
}
311-
}
312-
313340
// Optionally perform bazel mod tidy to update the MODULE.bazel file
314341
if bazel_info.release >= semver::Version::new(7, 0, 0) {
315342
let module_bazel = opt.workspace_dir.join("MODULE.bazel");

crate_universe/tools/urls_generator/src/main.rs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! A helper tool for generating urls and sha256 checksums of cargo-bazel binaries and writing them to a module.
22
33
use std::collections::BTreeMap;
4-
use std::io::{BufRead, BufReader};
4+
use std::io::{BufRead, BufReader, Write};
55
use std::path::{Path, PathBuf};
6-
use std::process::Command;
6+
use std::process::{Command, Stdio};
77
use std::{env, fs};
88

99
use clap::Parser;
@@ -151,25 +151,34 @@ fn render_module(artifacts: &[Artifact]) -> String {
151151
)
152152
}
153153

154-
fn write_module(content: &str) -> PathBuf {
155-
let dest = PathBuf::from(
156-
env::var("BUILD_WORKSPACE_DIRECTORY").expect("This binary is required to run under Bazel"),
157-
)
158-
.join(env!("MODULE_ROOT_PATH"));
154+
fn run_buildifier(buildifier_path: &Path, content: &str, path: &Path) -> String {
155+
let mut child = Command::new(buildifier_path)
156+
.args(["-lint=fix", "-mode=fix", "-warnings=all"])
157+
.arg(format!("--path={}", path.display()))
158+
.stdin(Stdio::piped())
159+
.stdout(Stdio::piped())
160+
.stderr(Stdio::piped())
161+
.spawn()
162+
.unwrap();
159163

160-
fs::write(&dest, content).unwrap();
164+
child
165+
.stdin
166+
.take()
167+
.unwrap()
168+
.write_all(content.as_bytes())
169+
.unwrap();
161170

162-
dest
163-
}
171+
let output = child.wait_with_output().unwrap();
164172

165-
fn run_buildifier(buildifier_path: &Path, module: &Path) {
166-
Command::new(buildifier_path)
167-
.arg("-lint=fix")
168-
.arg("-mode=fix")
169-
.arg("-warnings=all")
170-
.arg(module)
171-
.output()
172-
.unwrap();
173+
if !output.status.success() {
174+
panic!(
175+
"buildifier failed on {}: {}",
176+
path.display(),
177+
String::from_utf8_lossy(&output.stderr)
178+
);
179+
}
180+
181+
String::from_utf8(output.stdout).unwrap()
173182
}
174183

175184
fn main() {
@@ -179,9 +188,16 @@ fn main() {
179188

180189
let content = render_module(&artifacts);
181190

182-
let path = write_module(&content);
191+
let dest = PathBuf::from(
192+
env::var("BUILD_WORKSPACE_DIRECTORY").expect("This binary is required to run under Bazel"),
193+
)
194+
.join(env!("MODULE_ROOT_PATH"));
183195

184-
if let Some(buildifier_path) = opt.buildifier {
185-
run_buildifier(&buildifier_path, &path);
186-
}
196+
let content = if let Some(ref buildifier_path) = opt.buildifier {
197+
run_buildifier(buildifier_path, &content, &dest)
198+
} else {
199+
content
200+
};
201+
202+
fs::write(&dest, content).unwrap();
187203
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

0 commit comments

Comments
 (0)