zc2 0.0.29

P2P compute broker with credit-based billing, WAL, and broker mesh support
//! Stamps `zc --version` with the commit and time it was built from.
//!
//! This used to be the `built` crate with its `git2` feature, which compiled
//! libgit2 from C twice (once for this script, once as a normal dependency):
//! ~57 s of CPU per cold build, on the critical path to zc itself. The git CLI
//! is enough for a short hash and a dirty flag.
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

fn git(args: &[&str]) -> Option<String> {
    let out = Command::new("git").args(args).output().ok()?;
    if !out.status.success() {
        return None;
    }
    let s = String::from_utf8(out.stdout).ok()?.trim().to_string();
    (!s.is_empty()).then_some(s)
}

/// Rerun when `path` changes. A path that doesn't exist makes cargo rerun this
/// script, and so recompile zc, on every build: that is what the old
/// `.git/HEAD` did in a worktree, where `.git` is a file.
fn watch(path: &Path) {
    if path.exists() {
        println!("cargo:rerun-if-changed={}", path.display());
    }
}

fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");

    if let Some(git_dir) = git(&["rev-parse", "--git-dir"]).map(PathBuf::from) {
        let common = git(&["rev-parse", "--git-common-dir"])
            .map(PathBuf::from)
            .unwrap_or_else(|| git_dir.clone());
        // HEAD moves on checkout, the branch's own ref on commit. Not all of
        // refs/: a fetch, or a commit in a sibling worktree, would rebuild zc.
        watch(&git_dir.join("HEAD"));
        if let Some(branch) = git(&["symbolic-ref", "-q", "HEAD"]) {
            let loose = common.join(branch);
            match loose.parent() {
                // A packed ref has no loose file until the next commit writes one.
                Some(dir) if !loose.exists() => watch(dir),
                _ => watch(&loose),
            }
            watch(&common.join("packed-refs"));
        }
        if let Some(hash) = git(&["rev-parse", "--short", "HEAD"]) {
            let dirty = git(&["status", "--porcelain", "--untracked-files=no"]).is_some();
            println!("cargo:rustc-env=ZC_GIT_HASH={hash}");
            println!("cargo:rustc-env=ZC_GIT_DIRTY={}", u8::from(dirty));
        }
    }

    let epoch = std::env::var("SOURCE_DATE_EPOCH")
        .ok()
        .and_then(|s| s.parse::<u64>().ok())
        .unwrap_or_else(|| {
            SystemTime::now()
                .duration_since(UNIX_EPOCH)
                .map_or(0, |d| d.as_secs())
        });
    println!("cargo:rustc-env=ZC_BUILD_EPOCH={epoch}");
}