use std::process::Command;
fn main() {
let rev = git_rev().unwrap_or_else(|| "unknown".to_string());
let dirty = git_dirty();
let crates_rev = git_crates_rev().unwrap_or_else(|| "unknown".to_string());
println!("cargo:rustc-env=FNO_AGENTS_GIT_REV={rev}");
println!("cargo:rustc-env=FNO_AGENTS_GIT_DIRTY={}", u8::from(dirty));
println!("cargo:rustc-env=FNO_AGENTS_CRATES_REV={crates_rev}");
println!("cargo:rerun-if-changed=build.rs");
if let Some(gitdir) = run("git", &["rev-parse", "--absolute-git-dir"]) {
let gitdir = gitdir.trim();
println!("cargo:rerun-if-changed={gitdir}/HEAD");
if let Ok(head) = std::fs::read_to_string(format!("{gitdir}/HEAD")) {
if let Some(reference) = head.strip_prefix("ref: ") {
println!("cargo:rerun-if-changed={gitdir}/{}", reference.trim());
}
}
}
}
fn git_rev() -> Option<String> {
let out = run("git", &["rev-parse", "HEAD"])?;
let rev = out.trim().to_string();
if rev.is_empty() {
None
} else {
Some(rev)
}
}
fn git_dirty() -> bool {
let Some(top) = run("git", &["rev-parse", "--show-toplevel"]) else {
return false;
};
match run(
"git",
&["-C", top.trim(), "status", "--porcelain", "--", "crates/"],
) {
Some(s) => !s.trim().is_empty(),
None => false,
}
}
fn git_crates_rev() -> Option<String> {
let top = run("git", &["rev-parse", "--show-toplevel"])?;
let top = top.trim();
let out = run(
"git",
&["-C", top, "log", "-1", "--format=%H", "--", "crates/"],
)?;
let rev = out.trim().to_string();
if rev.is_empty() {
None
} else {
Some(rev)
}
}
fn run(cmd: &str, args: &[&str]) -> Option<String> {
let output = Command::new(cmd).args(args).output().ok()?;
if !output.status.success() {
return None;
}
String::from_utf8(output.stdout).ok()
}