use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::ExitCode;
fn main() -> ExitCode {
let mut args = env::args().skip(1);
let Some(dir) = args.next() else {
eprintln!("usage: sign-fixtures <fixtures-dir>");
return ExitCode::from(2);
};
if args.next().is_some() {
eprintln!("usage: sign-fixtures <fixtures-dir>");
return ExitCode::from(2);
}
match run(PathBuf::from(dir)) {
Ok(count) => {
eprintln!("signed {count} fixture(s)");
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("sign-fixtures: {e}");
ExitCode::from(1)
}
}
}
fn run(dir: PathBuf) -> Result<usize, String> {
let canonical =
fs::canonicalize(&dir).map_err(|e| format!("canonicalize {}: {e}", dir.display()))?;
let mut entries: Vec<(String, String)> = Vec::new();
let read =
fs::read_dir(&canonical).map_err(|e| format!("read_dir {}: {e}", canonical.display()))?;
for dirent in read {
let dirent = dirent.map_err(|e| format!("dirent: {e}"))?;
let path = dirent.path();
if !path.is_file() {
continue;
}
let name = path
.file_name()
.and_then(|s| s.to_str())
.ok_or_else(|| format!("non-utf8 filename in {}", canonical.display()))?
.to_string();
if name == "INDEX.toml" || name == "schema.json" {
continue;
}
if !name.ends_with(".json") {
continue;
}
let bytes = fs::read(&path).map_err(|e| format!("read {}: {e}", path.display()))?;
let hex = blake3::hash(&bytes).to_hex().to_string();
entries.push((name, hex));
}
entries.sort_by(|a, b| a.0.cmp(&b.0));
let mut out = String::new();
out.push_str("# AUTO-GENERATED by scripts/sign-fixtures.sh\n");
out.push_str("# Lane 1.D / THREATS T-RM-1 — BLAKE3-only fixture index.\n");
out.push_str(
"# Edits MUST regenerate this file via the script; ReplayAdapter rejects mismatches.\n\n",
);
for (name, hex) in &entries {
out.push_str(&format!(
"[[fixture]]\npath = \"{name}\"\nblake3 = \"{hex}\"\n\n"
));
}
let index_path = canonical.join("INDEX.toml");
let mut f = fs::File::create(&index_path)
.map_err(|e| format!("create {}: {e}", index_path.display()))?;
f.write_all(out.as_bytes())
.map_err(|e| format!("write {}: {e}", index_path.display()))?;
Ok(entries.len())
}