Skip to content

Commit cb9d412

Browse files
committed
fix: handle missing RUNFILES_DIR in coverage collection
In Bazel 8+, RUNFILES_DIR may not be set during coverage post-processing. This change: - Makes RUNFILES_DIR optional, with fallback to BAZEL_COVERAGE_INTERNAL_RUNFILES_DIR - Derives the bindir from COVERAGE_DIR when runfiles is unavailable - Simplifies the test binary lookup logic
1 parent 8cc8c2f commit cb9d412

File tree

1 file changed

+59
-41
lines changed

1 file changed

+59
-41
lines changed

util/collect_coverage/collect_coverage.rs

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -46,70 +46,88 @@ fn find_metadata_file(execroot: &Path, runfiles_dir: &Path, path: &str) -> PathB
4646
runfiles_dir.join(path)
4747
}
4848

49-
fn find_test_binary(execroot: &Path, runfiles_dir: &Path) -> PathBuf {
50-
let test_binary = runfiles_dir
51-
.join(env::var("TEST_WORKSPACE").unwrap())
52-
.join(env::var("TEST_BINARY").unwrap());
53-
54-
if !test_binary.exists() {
55-
let configuration = runfiles_dir
56-
.strip_prefix(execroot)
57-
.expect("RUNFILES_DIR should be relative to ROOT")
58-
.components()
59-
.enumerate()
60-
.filter_map(|(i, part)| {
61-
// Keep only `bazel-out/<configuration>/bin`
62-
if i < 3 {
63-
Some(PathBuf::from(part.as_os_str()))
64-
} else {
65-
None
66-
}
67-
})
68-
.fold(PathBuf::new(), |mut path, part| {
69-
path.push(part);
70-
path
71-
});
49+
/// Derive the bindir (e.g., "bazel-out/k8-fastbuild/bin") from a bazel output path.
50+
/// Works with paths like "bazel-out/k8-fastbuild/testlogs/..." or runfiles paths.
51+
fn get_bindir(path: &Path, execroot: &Path) -> Option<PathBuf> {
52+
let relative = path.strip_prefix(execroot).unwrap_or(path);
53+
let components: Vec<_> = relative.components().take(2).collect();
54+
if components.len() >= 2 {
55+
let base: PathBuf = components.iter().collect();
56+
Some(base.join("bin"))
57+
} else {
58+
None
59+
}
60+
}
7261

73-
let test_binary = execroot
74-
.join(configuration)
75-
.join(env::var("TEST_BINARY").unwrap());
62+
fn find_test_binary(execroot: &Path, runfiles_dir: Option<&Path>, coverage_dir: &Path) -> PathBuf {
63+
let test_binary_env = env::var("TEST_BINARY").unwrap();
7664

77-
debug_log!(
78-
"TEST_BINARY is not found in runfiles. Falling back to: {}",
79-
test_binary.display()
80-
);
65+
// Try runfiles first if available
66+
if let Some(runfiles) = runfiles_dir {
67+
let test_binary = runfiles
68+
.join(env::var("TEST_WORKSPACE").unwrap_or_default())
69+
.join(&test_binary_env);
70+
if test_binary.exists() {
71+
return test_binary;
72+
}
73+
// Try deriving bindir from runfiles path
74+
if let Some(bindir) = get_bindir(runfiles, execroot) {
75+
let test_binary = execroot.join(bindir).join(&test_binary_env);
76+
if test_binary.exists() {
77+
return test_binary;
78+
}
79+
}
80+
}
8181

82-
test_binary
83-
} else {
84-
test_binary
82+
// Derive bindir from coverage_dir
83+
if let Some(bindir) = get_bindir(coverage_dir, execroot) {
84+
let test_binary = execroot.join(&bindir).join(&test_binary_env);
85+
debug_log!("Using test binary: {}", test_binary.display());
86+
return test_binary;
8587
}
88+
89+
execroot.join(&test_binary_env)
8690
}
8791

8892
fn main() {
8993
let coverage_dir = PathBuf::from(env::var("COVERAGE_DIR").unwrap());
9094
let execroot = PathBuf::from(env::var("ROOT").unwrap());
91-
let mut runfiles_dir = PathBuf::from(env::var("RUNFILES_DIR").unwrap());
9295

93-
if !runfiles_dir.is_absolute() {
94-
runfiles_dir = execroot.join(runfiles_dir);
95-
}
96+
// RUNFILES_DIR may not be set in newer Bazel versions during coverage post-processing.
97+
// Try BAZEL_COVERAGE_INTERNAL_RUNFILES_DIR as fallback.
98+
let runfiles_dir = env::var("RUNFILES_DIR")
99+
.ok()
100+
.filter(|s| !s.is_empty())
101+
.or_else(|| {
102+
env::var("BAZEL_COVERAGE_INTERNAL_RUNFILES_DIR")
103+
.ok()
104+
.filter(|s| !s.is_empty())
105+
})
106+
.map(|dir| {
107+
let path = PathBuf::from(dir);
108+
if path.is_absolute() {
109+
path
110+
} else {
111+
execroot.join(path)
112+
}
113+
});
96114

97115
debug_log!("ROOT: {}", execroot.display());
98-
debug_log!("RUNFILES_DIR: {}", runfiles_dir.display());
116+
debug_log!("RUNFILES_DIR: {:?}", runfiles_dir);
99117

100118
let coverage_output_file = coverage_dir.join("coverage.dat");
101119
let profdata_file = coverage_dir.join("coverage.profdata");
102120
let llvm_cov = find_metadata_file(
103121
&execroot,
104-
&runfiles_dir,
122+
runfiles_dir.as_deref().unwrap_or(&execroot),
105123
&env::var("RUST_LLVM_COV").unwrap(),
106124
);
107125
let llvm_profdata = find_metadata_file(
108126
&execroot,
109-
&runfiles_dir,
127+
runfiles_dir.as_deref().unwrap_or(&execroot),
110128
&env::var("RUST_LLVM_PROFDATA").unwrap(),
111129
);
112-
let test_binary = find_test_binary(&execroot, &runfiles_dir);
130+
let test_binary = find_test_binary(&execroot, runfiles_dir.as_deref(), &coverage_dir);
113131
let profraw_files: Vec<PathBuf> = fs::read_dir(coverage_dir)
114132
.unwrap()
115133
.flatten()

0 commit comments

Comments
 (0)