use std::fmt;
use serde::Serialize;
use uv_normalize::PackageName;
use uv_pep508::uv_pep440::Version;
#[derive(Serialize)]
pub(crate) struct CommitInfo {
short_commit_hash: String,
commit_hash: String,
commit_date: String,
last_tag: Option<String>,
commits_since_last_tag: u32,
}
#[derive(Serialize)]
pub struct SelfVersionInfo {
package_name: String,
version: String,
commit_info: Option<CommitInfo>,
target_triple: String,
}
#[derive(Serialize)]
pub struct ProjectVersionInfo {
pub package_name: Option<String>,
version: String,
commit_info: Option<CommitInfo>,
}
impl ProjectVersionInfo {
pub fn new(package_name: Option<&PackageName>, version: &Version) -> Self {
Self {
package_name: package_name.map(ToString::to_string),
version: version.to_string(),
commit_info: None,
}
}
}
impl fmt::Display for SelfVersionInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.version)?;
if let Some(ci) = &self.commit_info {
if ci.commits_since_last_tag > 0 {
write!(f, "+{}", ci.commits_since_last_tag)?;
}
write!(
f,
" ({} {} {})",
ci.short_commit_hash, ci.commit_date, self.target_triple
)?;
} else {
write!(f, " ({})", self.target_triple)?;
}
Ok(())
}
}
impl fmt::Display for ProjectVersionInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.version)
}
}
impl fmt::Display for CommitInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.commits_since_last_tag > 0 {
write!(f, "+{}", self.commits_since_last_tag)?;
}
write!(f, " ({} {})", self.short_commit_hash, self.commit_date)?;
Ok(())
}
}
impl From<SelfVersionInfo> for clap::builder::Str {
fn from(val: SelfVersionInfo) -> Self {
val.to_string().into()
}
}
pub fn uv_self_version() -> SelfVersionInfo {
macro_rules! option_env_str {
($name:expr) => {
option_env!($name).map(|s| s.to_string())
};
}
let version = uv_version::version().to_string();
let commit_info = option_env_str!("UV_COMMIT_HASH").map(|commit_hash| CommitInfo {
short_commit_hash: option_env_str!("UV_COMMIT_SHORT_HASH").unwrap(),
commit_hash,
commit_date: option_env_str!("UV_COMMIT_DATE").unwrap(),
last_tag: option_env_str!("UV_LAST_TAG"),
commits_since_last_tag: option_env_str!("UV_LAST_TAG_DISTANCE")
.as_deref()
.map_or(0, |value| value.parse::<u32>().unwrap_or(0)),
});
let target_triple = env!("RUST_HOST_TARGET").to_string();
SelfVersionInfo {
package_name: "uv".to_owned(),
version,
commit_info,
target_triple,
}
}
#[cfg(test)]
mod tests {
use insta::{assert_json_snapshot, assert_snapshot};
use super::{CommitInfo, SelfVersionInfo};
#[test]
fn version_formatting() {
let version = SelfVersionInfo {
package_name: "uv".to_string(),
version: "0.0.0".to_string(),
commit_info: None,
target_triple: "x86_64-unknown-linux-gnu".to_string(),
};
assert_snapshot!(version, @"0.0.0 (x86_64-unknown-linux-gnu)");
}
#[test]
fn version_formatting_with_commit_info() {
let version = SelfVersionInfo {
package_name: "uv".to_string(),
version: "0.0.0".to_string(),
commit_info: Some(CommitInfo {
short_commit_hash: "53b0f5d92".to_string(),
commit_hash: "53b0f5d924110e5b26fbf09f6fd3a03d67b475b7".to_string(),
last_tag: Some("v0.0.1".to_string()),
commit_date: "2023-10-19".to_string(),
commits_since_last_tag: 0,
}),
target_triple: "x86_64-unknown-linux-gnu".to_string(),
};
assert_snapshot!(version, @"0.0.0 (53b0f5d92 2023-10-19 x86_64-unknown-linux-gnu)");
}
#[test]
fn version_formatting_with_commits_since_last_tag() {
let version = SelfVersionInfo {
package_name: "uv".to_string(),
version: "0.0.0".to_string(),
commit_info: Some(CommitInfo {
short_commit_hash: "53b0f5d92".to_string(),
commit_hash: "53b0f5d924110e5b26fbf09f6fd3a03d67b475b7".to_string(),
last_tag: Some("v0.0.1".to_string()),
commit_date: "2023-10-19".to_string(),
commits_since_last_tag: 24,
}),
target_triple: "x86_64-unknown-linux-gnu".to_string(),
};
assert_snapshot!(version, @"0.0.0+24 (53b0f5d92 2023-10-19 x86_64-unknown-linux-gnu)");
}
#[test]
fn version_serializable() {
let version = SelfVersionInfo {
package_name: "uv".to_string(),
version: "0.0.0".to_string(),
commit_info: Some(CommitInfo {
short_commit_hash: "53b0f5d92".to_string(),
commit_hash: "53b0f5d924110e5b26fbf09f6fd3a03d67b475b7".to_string(),
last_tag: Some("v0.0.1".to_string()),
commit_date: "2023-10-19".to_string(),
commits_since_last_tag: 0,
}),
target_triple: "x86_64-unknown-linux-gnu".to_string(),
};
assert_json_snapshot!(version, @r#"
{
"package_name": "uv",
"version": "0.0.0",
"commit_info": {
"short_commit_hash": "53b0f5d92",
"commit_hash": "53b0f5d924110e5b26fbf09f6fd3a03d67b475b7",
"commit_date": "2023-10-19",
"last_tag": "v0.0.1",
"commits_since_last_tag": 0
},
"target_triple": "x86_64-unknown-linux-gnu"
}
"#);
}
}