use std::process::Command;
mod build_ref;
fn main() {
let describe = Command::new("git")
.args([
"-c", "safe.directory=*",
"-c", "filter.lfs.required=false",
"-c", "filter.lfs.process=",
"-c", "filter.lfs.clean=",
"-c", "filter.lfs.smudge=",
"-c", "core.checkStat=minimal",
"describe",
"--tags",
"--always",
"--dirty=-modified",
"--abbrev=7",
])
.output();
let describe_failure = match &describe {
Ok(o) if o.status.success() => None,
Ok(o) => Some(format!(
"git describe exited {}: {}",
o.status,
String::from_utf8_lossy(&o.stderr).lines().next().unwrap_or("").trim()
)),
Err(e) => Some(format!("git could not be run: {e}")),
};
let describe = describe
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned())
.filter(|s| !s.is_empty());
let from_env = build_ref::env_refs();
match build_ref::choose(&from_env, describe.as_deref()) {
Some(r) => println!("cargo:rustc-env=GUNNAR_BUILD_REF={r}"),
None => {
println!("cargo:rustc-env=GUNNAR_BUILD_REF=unknown");
println!(
"cargo:warning=GUNNAR_BUILD_REF=unknown — the banner will carry no build reference and GATE-IDENTITY will refuse the install ({})",
describe_failure.as_deref().unwrap_or("git describe printed nothing")
);
}
}
println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");
println!("cargo:rustc-env=GUNNAR_BUILD_DATE={}", source_date());
for what in ["HEAD", "refs"] {
let path = Command::new("git")
.args(["-c", "safe.directory=*", "rev-parse", "--git-path", what])
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned())
.filter(|s| !s.is_empty());
if let Some(path) = path {
if std::path::Path::new(&path).exists() {
println!("cargo:rerun-if-changed={path}");
}
}
}
}
fn source_date() -> String {
if let Ok(raw) = std::env::var("SOURCE_DATE_EPOCH") {
if let Ok(secs) = raw.trim().parse::<i64>() {
return iso8601_utc(secs);
}
}
let head_epoch = Command::new("git")
.args(["-c", "safe.directory=*", "log", "-1", "--format=%ct"])
.output()
.ok()
.filter(|o| o.status.success())
.and_then(|o| {
String::from_utf8_lossy(&o.stdout)
.trim()
.parse::<i64>()
.ok()
});
match head_epoch {
Some(secs) => iso8601_utc(secs),
None => "unknown".to_owned(),
}
}
fn iso8601_utc(secs: i64) -> String {
let days = secs.div_euclid(86_400);
let rem = secs.rem_euclid(86_400);
let (hh, mm, ss) = (rem / 3600, (rem % 3600) / 60, rem % 60);
let z = days + 719_468;
let era = z.div_euclid(146_097);
let doe = z.rem_euclid(146_097); let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365; let y = yoe + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = doy - (153 * mp + 2) / 5 + 1; let m = if mp < 10 { mp + 3 } else { mp - 9 }; let y = if m <= 2 { y + 1 } else { y };
format!("{y:04}-{m:02}-{d:02}T{hh:02}:{mm:02}:{ss:02}Z")
}