use std::{env, fs, path::PathBuf, process::Command};
fn main() {
let sha = from_env_var()
.or_else(from_cargo_vcs_info)
.or_else(from_git_rev_parse)
.unwrap_or_else(|| "unknown".to_owned());
let fragment = format!(r#""{sha}""#);
let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is always set"));
fs::write(out_dir.join("version_fragment.rs"), fragment)
.expect("writing version_fragment.rs to OUT_DIR");
println!("cargo::rerun-if-changed=build.rs");
println!("cargo::rerun-if-changed=.cargo_vcs_info.json");
println!("cargo::rerun-if-env-changed=GIT_HASH");
}
fn from_env_var() -> Option<String> {
let s = env::var("GIT_HASH").ok()?;
if is_valid_sha(&s) { Some(s) } else { None }
}
fn from_cargo_vcs_info() -> Option<String> {
let dir = env::var_os("CARGO_MANIFEST_DIR")?;
let path = PathBuf::from(&dir).join(".cargo_vcs_info.json");
let content = fs::read_to_string(path).ok()?;
let v: serde_json::Value = serde_json::from_str(&content).ok()?;
let s = v.get("git")?.get("sha1")?.as_str()?;
if is_valid_sha(s) {
Some(s.to_owned())
} else {
None
}
}
fn from_git_rev_parse() -> Option<String> {
let output = Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let s = String::from_utf8(output.stdout).ok()?.trim().to_owned();
if is_valid_sha(&s) { Some(s) } else { None }
}
fn is_valid_sha(s: &str) -> bool {
s.len() == 40
&& s.bytes()
.all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
}