use std::path::{Path, PathBuf};
use std::process::Command;
const PATH_DEPS: [(&str, &str); 0] = [];
fn git(repo: &Path, args: &[&str]) -> Option<String> {
let out = Command::new("git")
.current_dir(repo)
.args(args)
.output()
.ok()?;
if !out.status.success() {
return None;
}
let text = String::from_utf8(out.stdout).ok()?;
let trimmed = text.trim();
if trimmed.is_empty() {
return None;
}
Some(trimmed.to_string())
}
fn commit(repo: &Path) -> Option<String> {
git(repo, &["rev-parse", "HEAD"])
}
fn dirty(repo: &Path) -> Option<bool> {
let status = git(repo, &["status", "--porcelain"]).unwrap_or_default();
git(repo, &["rev-parse", "--is-inside-work-tree"])?;
Some(status.lines().any(|line| {
let path = line.get(3..).unwrap_or("").trim();
let path = path.rsplit(" -> ").next().unwrap_or(path);
!(path.ends_with(".md") || path == ".brokkr/results.db")
}))
}
fn track(repo: &Path) {
println!("cargo:rerun-if-changed={}/src", repo.display());
println!("cargo:rerun-if-changed={}/Cargo.toml", repo.display());
let git_dir = repo.join(".git");
println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display());
if let Some(head) = git(repo, &["symbolic-ref", "-q", "HEAD"]) {
println!("cargo:rerun-if-changed={}", git_dir.join(head).display());
}
}
fn emit(name: &str, value: &str) {
println!("cargo:rustc-env=ELIVAGAR_BUILD_{name}={value}");
}
fn locked_version(lock: &str, package: &str) -> Option<String> {
let name_line = format!("name = \"{package}\"");
let mut in_target = false;
for line in lock.lines() {
let line = line.trim();
if line == "[[package]]" {
in_target = false;
} else if line == name_line {
in_target = true;
} else if in_target && let Some(rest) = line.strip_prefix("version = \"") {
return rest.strip_suffix('"').map(str::to_string);
}
}
None
}
fn main() {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.lock");
let repos = std::iter::once(("ELIVAGAR", manifest.clone())).chain(
PATH_DEPS
.iter()
.map(|(name, rel)| (*name, manifest.join(rel))),
);
for (name, repo) in repos {
track(&repo);
emit(
&format!("{name}_COMMIT"),
commit(&repo).as_deref().unwrap_or("unknown"),
);
emit(
&format!("{name}_DIRTY"),
match dirty(&repo) {
Some(true) => "true",
Some(false) => "false",
None => "unknown",
},
);
}
let lock = std::fs::read(manifest.join("Cargo.lock")).unwrap_or_default();
emit(
"CARGO_LOCK_XXH3_128",
&format!("{:032x}", xxhash_rust::xxh3::xxh3_128(&lock)),
);
let lock_text = String::from_utf8_lossy(&lock);
emit(
"PBFHOGG_VERSION",
locked_version(&lock_text, "pbfhogg")
.as_deref()
.unwrap_or("unknown"),
);
let mut features: Vec<String> = std::env::vars()
.filter_map(|(k, _)| k.strip_prefix("CARGO_FEATURE_").map(str::to_string))
.map(|f| f.to_lowercase().replace('_', "-"))
.collect();
features.sort();
emit("CARGO_FEATURES", &features.join(","));
}