c84fd14cac
Committing updates refs/heads/<branch>, not the HEAD file, so watching HEAD alone left the stamp one commit behind -- observed live, the banner reada84a72eimmediately after2337431was committed. build.rs now also watches the resolved branch ref. Belt and braces, since cargo still cannot see every source change: sidecar.sh compares the binary's stamped commit against the tree's real HEAD at launch and says so loudly on a mismatch. An evidence artefact that names the WRONG commit is worse than one that names none. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
79 lines
3.1 KiB
Rust
79 lines
3.1 KiB
Rust
//! Stamp build identity into the binary.
|
|
//!
|
|
//! A live FIFA trace has to be attributable to an exact binary. During the
|
|
//! mutation runs for the previous step, four sidecars were left listening —
|
|
//! two of them serving deliberately broken builds — and nothing in their output
|
|
//! said so. A later A/B against one of those would have read as a genuine
|
|
//! parity failure.
|
|
//!
|
|
//! So the host prints its commit, working-tree cleanliness and profile at
|
|
//! startup, and `dirty` is the important one: a mutation-tested build is a
|
|
//! dirty build, and now it announces itself.
|
|
|
|
use std::process::Command;
|
|
|
|
fn git(args: &[&str]) -> Option<String> {
|
|
let out = Command::new("git").args(args).output().ok()?;
|
|
if !out.status.success() {
|
|
return None;
|
|
}
|
|
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
|
}
|
|
|
|
fn main() {
|
|
let commit = git(&["rev-parse", "--short=7", "HEAD"]).unwrap_or_else(|| "unknown".into());
|
|
|
|
// Scoped to the crates this binary is actually built from.
|
|
//
|
|
// A whole-repo check reads DIRTY permanently here, because unrelated
|
|
// submodules carry pre-existing modifications. A warning that is always on
|
|
// is a warning nobody reads — which would defeat the point, since the whole
|
|
// job of this flag is to make a mutated build announce itself.
|
|
//
|
|
// Untracked files are excluded: scratch output is not a build difference,
|
|
// but an edited source file certainly is.
|
|
let dirty = match git(&[
|
|
"status",
|
|
"--porcelain",
|
|
"--untracked-files=no",
|
|
"--",
|
|
"openfut-blaze-host",
|
|
"openfut-adapter-fifa17",
|
|
"openfut-protocol-blaze",
|
|
]) {
|
|
Some(s) if !s.is_empty() => "DIRTY",
|
|
Some(_) => "clean",
|
|
None => "unknown",
|
|
};
|
|
|
|
println!("cargo:rustc-env=OPENFUT_BUILD_COMMIT={commit}");
|
|
println!("cargo:rustc-env=OPENFUT_BUILD_DIRTY={dirty}");
|
|
|
|
// Re-stamp when HEAD moves.
|
|
//
|
|
// IMPORTANT LIMITATION: this flag is best-effort and CAN BE STALE. Cargo
|
|
// will not re-run a build script because some other crate's source changed,
|
|
// so editing the adapter and rebuilding the host can leave `dirty` reading
|
|
// "clean". Verified: appending a line to the adapter and rebuilding did not
|
|
// flip it.
|
|
//
|
|
// So the compiled-in value is useful for naming the commit, and is NOT the
|
|
// safeguard. `sidecar.sh` re-checks the working tree at launch and
|
|
// `check-live-parity.sh` refuses to produce evidence from a dirty tree —
|
|
// those run at the right moment and cannot go stale.
|
|
for p in ["../.git/HEAD", "../.git/index"] {
|
|
if std::path::Path::new(p).exists() {
|
|
println!("cargo:rerun-if-changed={p}");
|
|
}
|
|
}
|
|
// Committing updates refs/heads/<branch>, NOT the HEAD file, so watching
|
|
// HEAD alone leaves the stamp one commit behind. Observed: the banner read
|
|
// a84a72e immediately after committing 2337431.
|
|
if let Some(rf) = git(&["symbolic-ref", "-q", "HEAD"]) {
|
|
let path = format!("../.git/{rf}");
|
|
if std::path::Path::new(&path).exists() {
|
|
println!("cargo:rerun-if-changed={path}");
|
|
}
|
|
}
|
|
}
|