//! 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 { 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/, 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}"); } } }