metrale_bench/gate/
check_paths.rs1use std::path::Path;
11
12pub fn invalidating_paths(
25 root: &Path,
26 head: &str,
27 record_sha: &str,
28 gate: &super::coverage::GateCoverage,
29) -> Option<Vec<String>> {
30 invalidating_paths_with(root, head, record_sha, gate, |path| {
31 super::amnesty::excused(root, head, path)
32 })
33}
34
35fn invalidating_paths_with(
36 root: &Path,
37 head: &str,
38 record_sha: &str,
39 gate: &super::coverage::GateCoverage,
40 mut is_excused: impl FnMut(&str) -> bool,
41) -> Option<Vec<String>> {
42 if head == record_sha {
43 return Some(Vec::new());
44 }
45 let out = std::process::Command::new("git")
46 .arg("-C")
47 .arg(root)
48 .args(["diff", "--name-only", record_sha, head])
49 .stdin(std::process::Stdio::null())
50 .output()
51 .ok()?;
52 if !out.status.success() {
53 return None;
54 }
55 Some(
56 String::from_utf8_lossy(&out.stdout)
57 .lines()
58 .map(str::trim)
59 .filter(|p| !p.is_empty())
60 .filter(|p| super::coverage::invalidates(gate, p))
61 .filter(|p| {
65 if is_excused(p) {
66 tracing::warn!(
67 "amnesty: {p} would re-open {} but its content at {head} is the \
68 pinned one-time grant; excused (see gate/amnesty.rs)",
69 gate.id
70 );
71 return false;
72 }
73 true
74 })
75 .map(str::to_string)
76 .collect(),
77 )
78}
79
80#[cfg(test)]
81pub(crate) fn invalidating_paths_with_amnesty(
82 root: &Path,
83 head: &str,
84 record_sha: &str,
85 gate: &super::coverage::GateCoverage,
86 table: &[super::amnesty::AmnestyEntry],
87) -> Option<Vec<String>> {
88 invalidating_paths_with(root, head, record_sha, gate, |path| {
89 super::amnesty::excused_by(root, head, path, table)
90 })
91}