Merge v3-t78: the test bundle cache is keyed on its source inputs (T78)

This commit is contained in:
2026-11-08 04:16:21 +00:00
2 changed files with 82 additions and 0 deletions
+75
View File
@@ -1,5 +1,7 @@
//! Shared fixture copies and builds. A mutex protects cwd-init and the brush checkout.
use std::{
hash::{Hash, Hasher},
os::unix::{ffi::OsStrExt, fs::PermissionsExt},
path::{Path, PathBuf},
process::{Command, ExitStatus},
sync::{Mutex, OnceLock},
@@ -31,6 +33,79 @@ pub fn target_dir() -> PathBuf {
})
}
/// Fingerprint the snapshot inputs and their current working-tree contents.
pub fn bundle_key(repo: &Path) -> anyhow::Result<String> {
const INPUTS: &[&str] = &[
"host",
"vfs",
"userland",
"agents",
"skills",
"extensions",
"Cargo.toml",
"Cargo.lock",
"flake.nix",
"flake.lock",
"README.md",
"AGENTS.md",
".gitignore",
];
let tree = Command::new("git")
.current_dir(repo)
.args(["ls-tree", "HEAD", "--"])
.args(INPUTS)
.output()?;
anyhow::ensure!(
tree.status.success(),
"git ls-tree: {}",
String::from_utf8_lossy(&tree.stderr)
);
let files = Command::new("git")
.current_dir(repo)
.args([
"ls-files",
"-z",
"--cached",
"--others",
"--exclude-standard",
"--",
])
.args(INPUTS)
.output()?;
anyhow::ensure!(
files.status.success(),
"git ls-files: {}",
String::from_utf8_lossy(&files.stderr)
);
let mut hash = std::collections::hash_map::DefaultHasher::new();
tree.stdout.hash(&mut hash);
let mut names: Vec<_> = files
.stdout
.split(|byte| *byte == 0)
.filter(|name| !name.is_empty())
.collect();
names.sort_unstable();
for name in names {
name.hash(&mut hash);
let path = repo.join(std::ffi::OsStr::from_bytes(name));
match std::fs::symlink_metadata(&path) {
Ok(metadata) => {
metadata.permissions().mode().hash(&mut hash);
if metadata.file_type().is_symlink() {
std::fs::read_link(path)?.hash(&mut hash);
} else {
std::fs::read(path)?.hash(&mut hash);
}
}
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
"deleted".hash(&mut hash);
}
Err(error) => return Err(error.into()),
}
}
Ok(format!("{:016x}\n", hash.finish()))
}
pub fn cwd_init() {
static INIT: OnceLock<()> = OnceLock::new();
INIT.get_or_init(|| {
+7
View File
@@ -7,9 +7,15 @@ fn bundle() -> anyhow::Result<PathBuf> {
let repo = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..");
let bundle = crate::common::target_dir().join("bundle");
let _guard = crate::common::BUILD.lock().unwrap();
let key = crate::common::bundle_key(&repo)?;
let stamp = bundle.join(".source-key");
if !bundle.join("bin/sh.wasm").exists()
|| !bundle.join("src/sausage/agents/models.json").exists()
|| std::fs::read_to_string(&stamp).ok().as_deref() != Some(key.as_str())
{
if stamp.exists() {
std::fs::remove_file(&stamp)?;
}
assert!(
std::process::Command::new("nu")
.arg(repo.join("userland/bundle.nu"))
@@ -17,6 +23,7 @@ fn bundle() -> anyhow::Result<PathBuf> {
.status()?
.success()
);
std::fs::write(stamp, key)?;
}
Ok(bundle)
}