use super::types::PlannedCompilationUnit;
use crate::core::hash::Sha256;
use std::path::Path;
pub fn single_flight_key(unit: &PlannedCompilationUnit, action_key: &str) -> String {
if !super::unit_inputs::is_mutable_unit(unit) {
return action_key.to_string();
}
let pkg_dir = unit.manifest_path.parent().unwrap_or(Path::new("."));
let Some(dir) = unit
.src_path
.parent()
.filter(|d| *d != pkg_dir && d.starts_with(pkg_dir))
else {
return action_key.to_string();
};
let mut files = Vec::new();
if super::unit_inputs::scan_dir_inputs(dir, pkg_dir, &mut files).is_err() {
return action_key.to_string();
}
files.sort();
let mut payload = format!("single_flight:{action_key}\n");
for (path, digest) in files {
payload.push_str(&format!("{path}={digest}\n"));
}
Sha256::digest(payload.as_bytes())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
fn unit_in(dir: &Path) -> PlannedCompilationUnit {
fs::create_dir_all(dir.join("src")).unwrap();
fs::write(
dir.join("Cargo.toml"),
"[package]\nname = \"sf\"\nversion = \"0.1.0\"\n",
)
.unwrap();
fs::write(dir.join("src/lib.rs"), "mod m;\n").unwrap();
PlannedCompilationUnit {
package_name: "sf".into(),
target_name: "sf".into(),
kind: "lib".into(),
src_path: dir.join("src/lib.rs"),
manifest_path: dir.join("Cargo.toml"),
is_workspace: true,
..Default::default()
}
}
#[test]
fn same_coarse_key_with_different_modules_takes_different_locks() {
let a = tempfile::tempdir().unwrap();
let b = tempfile::tempdir().unwrap();
let c = tempfile::tempdir().unwrap();
let (ua, ub, uc) = (unit_in(a.path()), unit_in(b.path()), unit_in(c.path()));
fs::write(a.path().join("src/m.rs"), "pub fn v() -> u32 { 1 }\n").unwrap();
fs::write(b.path().join("src/m.rs"), "pub fn v() -> u32 { 2 }\n").unwrap();
fs::write(c.path().join("src/m.rs"), "pub fn v() -> u32 { 1 }\n").unwrap();
fs::write(c.path().join("README.md"), "other\n").unwrap();
let ka = single_flight_key(&ua, "coarse");
assert_ne!(ka, single_flight_key(&ub, "coarse"));
assert_eq!(
ka,
single_flight_key(&uc, "coarse"),
"identical crate sources in another checkout must share the lock"
);
}
}