use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=SYNAPS_BUILD_ID");
let id = std::env::var("SYNAPS_BUILD_ID")
.ok()
.filter(|s| !s.trim().is_empty())
.or_else(repo_build_id)
.unwrap_or_default();
println!("cargo:rustc-env=SYNAPS_BUILD_ID={}", id.trim());
}
fn git(dir: &Path, args: &[&str]) -> Option<String> {
Command::new("git")
.arg("-C")
.arg(dir)
.args(args)
.output()
.ok()
.filter(|o| o.status.success())
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string())
}
fn abs_git_path(root: &Path, args: &[&str]) -> Option<PathBuf> {
let p = PathBuf::from(git(root, args)?);
Some(if p.is_absolute() { p } else { root.join(p) })
}
fn repo_build_id() -> Option<String> {
let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").ok()?); let ws_root = manifest.canonicalize().ok()?;
let toplevel = PathBuf::from(git(&ws_root, &["rev-parse", "--show-toplevel"])?)
.canonicalize()
.ok()?;
if toplevel != ws_root {
return None;
}
let git_dir = abs_git_path(&ws_root, &["rev-parse", "--git-dir"]);
let common_dir = abs_git_path(&ws_root, &["rev-parse", "--git-common-dir"]);
let head_ref = git(&ws_root, &["rev-parse", "--symbolic-full-name", "HEAD"]);
let mut watched: Vec<PathBuf> = Vec::new();
let mut has_reflog = false;
if let Some(d) = &git_dir {
watched.push(d.join("HEAD"));
let reflog = d.join("logs").join("HEAD");
has_reflog = reflog.exists();
watched.push(reflog);
}
if let (Some(g), Some(c)) = (&git_dir, &common_dir) {
if g != c {
watched.push(g.join("reftable"));
}
}
if let Some(d) = &common_dir {
watched.push(d.join("reftable"));
watched.push(d.join("packed-refs"));
if let Some(r) = head_ref.as_deref().filter(|r| r.starts_with("refs/")) {
let loose = d.join(r);
if !has_reflog && !loose.exists() {
if let Some(parent) = loose.parent() {
watched.push(parent.to_path_buf());
}
}
watched.push(loose);
}
}
for p in watched.iter().filter(|p| p.exists()) {
println!("cargo:rerun-if-changed={}", p.display());
}
let hash = git(&ws_root, &["rev-parse", "--short", "HEAD"]).filter(|s| !s.is_empty())?;
let dirty = git(&ws_root, &["--no-optional-locks", "status", "--porcelain", "--untracked-files=no"])
.is_some_and(|s| !s.is_empty());
Some(if dirty { format!("{hash}-dirty") } else { hash })
}