//! Capture the git HEAD sha at compile time and expose it as `AURA_COMMIT`, so
//! the binary's RunManifest is self-identifying (C8/C18 audit trail: this run =
//! this commit). When there is no git (e.g. a packaged source tree), `AURA_COMMIT`
//! is left unset and `main.rs`'s `option_env!(...).unwrap_or("unknown")` holds.
//!
//! Zero runtime/build dependency by commitment (C14/C18): we shell out to the
//! `git` already in PATH rather than pulling in a libgit crate.

use std::path::Path;
use std::process::Command;

fn main() {
    // build.rs runs with CWD = the crate dir (crates/aura-cli); the repo root,
    // which owns `.git`, is two levels up.
    let repo_root = Path::new("../..");
    let git_dir = repo_root.join(".git");

    if !git_dir.exists() {
        // No git: emit nothing; the `"unknown"` fallback in main.rs holds.
        return;
    }

    // Re-run when HEAD moves or its working tree changes so AURA_COMMIT never
    // goes stale across commits. `.git/logs/HEAD` grows on every HEAD move
    // (commit, checkout, reset), covering branch switches without resolving the
    // current branch's ref file by hand.
    println!("cargo:rerun-if-changed=../../.git/HEAD");
    println!("cargo:rerun-if-changed=../../.git/logs/HEAD");

    let head = run_git(repo_root, &["rev-parse", "HEAD"]);
    let Some(head) = head else { return };

    // Append `-dirty` when the working tree has uncommitted changes, so a run
    // built off an unclean tree is not silently attributed to the clean HEAD.
    let dirty = run_git(repo_root, &["status", "--porcelain"])
        .map(|s| !s.is_empty())
        .unwrap_or(false);

    let commit = if dirty { format!("{head}-dirty") } else { head };
    println!("cargo:rustc-env=AURA_COMMIT={commit}");
}

/// Run `git <args>` in `dir`, returning trimmed stdout on success, `None` on any
/// failure (git missing, non-zero exit, non-utf8). Never panics: a build must
/// not fail because git is unavailable.
fn run_git(dir: &Path, args: &[&str]) -> Option<String> {
    let out = Command::new("git").current_dir(dir).args(args).output().ok()?;
    if !out.status.success() {
        return None;
    }
    let s = String::from_utf8(out.stdout).ok()?;
    Some(s.trim().to_string())
}
