use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src");
println!("cargo:rerun-if-changed=Cargo.toml");
for p in git_watch_paths() {
println!("cargo:rerun-if-changed={}", p.display());
}
println!("cargo:rerun-if-env-changed=KOTH_BUILD_GIT_SHA");
let sha = std::env::var("KOTH_BUILD_GIT_SHA")
.ok()
.filter(|s| !s.is_empty())
.or_else(git_describe)
.unwrap_or_else(|| "unknown".to_string());
println!("cargo:rustc-env=KOTH_GIT_SHA={sha}");
}
fn git_describe() -> Option<String> {
let sha = run(&["rev-parse", "--short=12", "HEAD"])?;
let clean = Command::new("git")
.args(["diff", "--quiet", "HEAD"])
.status()
.map(|s| s.success())
.unwrap_or(true);
Some(if clean { sha } else { format!("{sha}-dirty") })
}
fn run(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)
}
fn git_watch_paths() -> Vec<PathBuf> {
let Some(git_dir) = find_git_dir() else {
return Vec::new();
};
let common_dir = std::fs::read_to_string(git_dir.join("commondir"))
.ok()
.map(|c| git_dir.join(c.trim()))
.unwrap_or_else(|| git_dir.clone());
let mut paths = vec![git_dir.join("HEAD"), git_dir.join("index")];
if let Ok(head) = std::fs::read_to_string(git_dir.join("HEAD")) {
if let Some(r) = head.trim().strip_prefix("ref:") {
let r = r.trim();
let local = git_dir.join(r);
paths.push(if local.exists() {
local
} else {
common_dir.join(r)
});
}
}
paths.push(common_dir.join("packed-refs"));
paths
.into_iter()
.map(|p| p.canonicalize().unwrap_or(p))
.collect()
}
fn find_git_dir() -> Option<PathBuf> {
let start = PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR")?);
let mut dir: Option<&Path> = Some(&start);
while let Some(d) = dir {
let dot_git = d.join(".git");
if dot_git.is_dir() {
return Some(dot_git);
}
if dot_git.is_file() {
let text = std::fs::read_to_string(&dot_git).ok()?;
let target = text.lines().find_map(|l| l.strip_prefix("gitdir:"))?.trim();
return Some(d.join(target));
}
dir = d.parent();
}
None
}