use std::{io, process::Command};
fn main() {
define_version_with_git();
}
fn define_version_with_git() {
let cargo_version = env!("CARGO_PKG_VERSION");
let version = version_with_git(cargo_version)
.unwrap_or_else(|_| String::from(cargo_version));
println!("cargo:rustc-env=VERSION_WITH_GIT={version}");
}
fn version_with_git(cargo_version: &str) -> io::Result<String> {
if git_describe()? == format!("v{cargo_version}")
|| is_cargo_checkout()? && !is_dev_version(cargo_version)
{
Ok(String::from(cargo_version))
} else {
let revision = git_revision_and_state()?;
Ok(format!("{cargo_version}+{revision}"))
}
}
fn git_describe() -> io::Result<String> {
let output = Command::new("git")
.args(["describe", "--always", "--dirty=-modified"])
.output()?;
Ok(String::from_utf8(output.stdout).unwrap().trim().to_owned())
}
fn git_revision_and_state() -> io::Result<String> {
let revision = git_revision()?;
if git_is_dirty()? && !is_cargo_checkout()? {
Ok(format!("{revision}-modified"))
} else {
Ok(revision)
}
}
fn git_revision() -> io::Result<String> {
let output = Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.output()?;
Ok(String::from_utf8(output.stdout).unwrap().trim().to_owned())
}
fn git_is_dirty() -> io::Result<bool> {
let output = Command::new("git")
.args(["status", "--porcelain"])
.output()?;
Ok(!output.stdout.is_empty())
}
fn is_cargo_checkout() -> io::Result<bool> {
let output = Command::new("git")
.args(["status", "--porcelain"])
.output()?;
Ok(output.stdout == b"?? .cargo-ok\n")
}
fn is_dev_version(cargo_version: &str) -> bool {
cargo_version.contains("-dev")
}