metrale_bench/gate/
record_write.rs1use std::path::{Path, PathBuf};
18
19use anyhow::{Context, Result, bail};
20
21use super::gate_dir;
22use super::record::{GateRecord, read_record, record_path_for};
23use super::record_path::rerun_path;
24
25pub fn write_record(root: &Path, record: &GateRecord) -> Result<PathBuf> {
31 let path = preserving_path(&record_path_for(root, record), record)?;
32 std::fs::create_dir_all(path.parent().expect("record path has a parent")).with_context(
33 || {
34 format!(
35 "creating {}",
36 gate_dir(root, &record.benchmark_id).display()
37 )
38 },
39 )?;
40 let json = serde_json::to_string_pretty(record).context("serializing the gate record")?;
41 std::fs::write(&path, json + "\n").with_context(|| format!("writing {}", path.display()))?;
42 Ok(path)
43}
44
45fn preserving_path(canonical: &Path, record: &GateRecord) -> Result<PathBuf> {
49 if !holds_failure(canonical)? {
50 return Ok(canonical.to_path_buf());
51 }
52 let rerun = rerun_path(canonical, record.recorded_at);
53 if holds_failure(&rerun)? {
54 bail!(
55 "{} and {} both hold FAILING records for this commit; neither is overwritten. \
56 A failing record is evidence — remove one with `git rm` if it must go.",
57 canonical.display(),
58 rerun.display()
59 );
60 }
61 Ok(rerun)
62}
63
64fn holds_failure(path: &Path) -> Result<bool> {
68 if !path.exists() {
69 return Ok(false);
70 }
71 let existing = read_record(path).with_context(|| {
72 format!(
73 "{} exists but is not a readable gate record, so it is not overwritten",
74 path.display()
75 )
76 })?;
77 Ok(existing.verdict.as_deref() == Some("FAIL"))
78}
79
80#[cfg(test)]
81#[path = "record_write_tests.rs"]
82mod record_write_tests;