use std::path::Path;
use std::process::Command;
include!("src/version_describe.rs");
fn main() {
let pkg = std::env::var("CARGO_PKG_VERSION").unwrap_or_default();
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or_default();
let version = match git_state(&manifest_dir, &pkg) {
Some(state) =>
describe_version(&pkg, state.exact_tag, Some(&state.short_hash), state.dirty),
None if is_packaged_release(&manifest_dir) => pkg,
None => format!("{pkg}+src"),
};
println!("cargo:rustc-env=RAG_RAT_VERSION={version}");
force_rerun();
}
fn is_packaged_release(manifest_dir: &str) -> bool {
Path::new(manifest_dir).join(".cargo_vcs_info.json").exists()
}
struct GitState {
exact_tag: bool,
short_hash: String,
dirty: bool,
}
fn git_state(dir: &str, pkg: &str) -> Option<GitState> {
let toplevel = git_output(dir, &["rev-parse", "--show-toplevel"])?;
if !Path::new(toplevel.trim()).join("rag-rat.toml").exists() {
return None;
}
let short_hash = git_output(dir, &["rev-parse", "--short=12", "HEAD"])?.trim().to_string();
if short_hash.is_empty() {
return None;
}
let exact_tag = git_describes_exact_tag(dir)
|| ci_release_tag(
std::env::var("GITHUB_REF_TYPE").ok().as_deref(),
std::env::var("GITHUB_REF_NAME").ok().as_deref(),
pkg,
);
let dirty = git_output(dir, &["status", "--porcelain", "--untracked-files=no"])
.is_some_and(|out| !out.trim().is_empty());
Some(GitState { exact_tag, short_hash, dirty })
}
fn git_describes_exact_tag(dir: &str) -> bool {
Command::new("git")
.current_dir(dir)
.args(["describe", "--tags", "--match", "v*", "--exact-match", "HEAD"])
.output()
.map(|out| out.status.success())
.unwrap_or(false)
}
fn git_output(dir: &str, args: &[&str]) -> Option<String> {
let out = Command::new("git").current_dir(dir).args(args).output().ok()?;
out.status.success().then(|| String::from_utf8_lossy(&out.stdout).into_owned())
}
fn force_rerun() {
println!("cargo:rerun-if-changed=RAG_RAT_ALWAYS_RESTAMP");
}