diff --git a/crates/uv-cli/src/version.rs b/crates/uv-cli/src/version.rs index 94169873a..d3954ba13 100644 --- a/crates/uv-cli/src/version.rs +++ b/crates/uv-cli/src/version.rs @@ -17,20 +17,36 @@ pub(crate) struct CommitInfo { commits_since_last_tag: u32, } -/// uv's version. +/// Version information for uv itself (e.g., in `uv self version`). #[derive(Serialize)] -pub struct VersionInfo { - /// Name of the package (or "uv" if printing uv's own version) - pub package_name: Option, - /// version, such as "0.5.1" +pub struct SelfVersionInfo { + /// Name of the package (always "uv"). + package_name: String, + /// Version, such as "0.5.1". version: String, /// Information about the git commit we may have been built from. /// /// `None` if not built from a git repo or if retrieval failed. commit_info: Option, + /// The target triple for which uv was built (e.g., `x86_64-unknown-linux-gnu`). + target_triple: String, } -impl VersionInfo { +/// Version information for a project (`uv version`). +#[derive(Serialize)] +pub struct ProjectVersionInfo { + /// Name of the package. + pub package_name: Option, + /// Version, such as "0.5.1". + version: String, + /// Information about the git commit uv was built from. + /// + /// Always `null` for project versions, kept for backwards compatibility. + // TODO(zanieb): Remove this field in a breaking release. + commit_info: Option, +} + +impl ProjectVersionInfo { pub fn new(package_name: Option<&PackageName>, version: &Version) -> Self { Self { package_name: package_name.map(ToString::to_string), @@ -40,20 +56,35 @@ impl VersionInfo { } } -impl fmt::Display for VersionInfo { - /// Formatted version information: "[+] ( )" +impl fmt::Display for SelfVersionInfo { + /// Formatted version information: "[+] ([ ])" /// /// This is intended for consumption by `clap` to provide `uv --version`, - /// and intentionally omits the name of the package + /// and intentionally omits the name of the package. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.version)?; if let Some(ci) = &self.commit_info { - write!(f, "{ci}")?; + 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 { @@ -64,14 +95,14 @@ impl fmt::Display for CommitInfo { } } -impl From for clap::builder::Str { - fn from(val: VersionInfo) -> Self { +impl From for clap::builder::Str { + fn from(val: SelfVersionInfo) -> Self { val.to_string().into() } } /// Returns information about uv's version. -pub fn uv_self_version() -> VersionInfo { +pub fn uv_self_version() -> SelfVersionInfo { // Environment variables are only read at compile-time macro_rules! option_env_str { ($name:expr) => { @@ -93,10 +124,14 @@ pub fn uv_self_version() -> VersionInfo { .map_or(0, |value| value.parse::().unwrap_or(0)), }); - VersionInfo { - package_name: Some("uv".to_owned()), + // Set by `uv-cli/build.rs` + let target_triple = env!("RUST_HOST_TARGET").to_string(); + + SelfVersionInfo { + package_name: "uv".to_owned(), version, commit_info, + target_triple, } } @@ -104,22 +139,23 @@ pub fn uv_self_version() -> VersionInfo { mod tests { use insta::{assert_json_snapshot, assert_snapshot}; - use super::{CommitInfo, VersionInfo}; + use super::{CommitInfo, SelfVersionInfo}; #[test] fn version_formatting() { - let version = VersionInfo { - package_name: Some("uv".to_string()), + 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"); + assert_snapshot!(version, @"0.0.0 (x86_64-unknown-linux-gnu)"); } #[test] fn version_formatting_with_commit_info() { - let version = VersionInfo { - package_name: Some("uv".to_string()), + let version = SelfVersionInfo { + package_name: "uv".to_string(), version: "0.0.0".to_string(), commit_info: Some(CommitInfo { short_commit_hash: "53b0f5d92".to_string(), @@ -128,14 +164,15 @@ mod tests { 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)"); + 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 = VersionInfo { - package_name: Some("uv".to_string()), + let version = SelfVersionInfo { + package_name: "uv".to_string(), version: "0.0.0".to_string(), commit_info: Some(CommitInfo { short_commit_hash: "53b0f5d92".to_string(), @@ -144,14 +181,15 @@ mod tests { 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)"); + assert_snapshot!(version, @"0.0.0+24 (53b0f5d92 2023-10-19 x86_64-unknown-linux-gnu)"); } #[test] fn version_serializable() { - let version = VersionInfo { - package_name: Some("uv".to_string()), + let version = SelfVersionInfo { + package_name: "uv".to_string(), version: "0.0.0".to_string(), commit_info: Some(CommitInfo { short_commit_hash: "53b0f5d92".to_string(), @@ -160,6 +198,7 @@ mod tests { 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#" { @@ -171,7 +210,8 @@ mod tests { "commit_date": "2023-10-19", "last_tag": "v0.0.1", "commits_since_last_tag": 0 - } + }, + "target_triple": "x86_64-unknown-linux-gnu" } "#); } diff --git a/crates/uv/src/commands/project/version.rs b/crates/uv/src/commands/project/version.rs index 6909a1144..414da9268 100644 --- a/crates/uv/src/commands/project/version.rs +++ b/crates/uv/src/commands/project/version.rs @@ -7,7 +7,7 @@ use owo_colors::OwoColorize; use tracing::debug; use uv_cache::Cache; -use uv_cli::version::VersionInfo; +use uv_cli::version::ProjectVersionInfo; use uv_cli::{VersionBump, VersionBumpSpec, VersionFormat}; use uv_client::BaseClientBuilder; use uv_configuration::{ @@ -47,7 +47,19 @@ pub(crate) fn self_version( printer: Printer, ) -> Result { let version_info = uv_cli::version::uv_self_version(); - print_version(version_info, None, short, output_format, printer)?; + match output_format { + VersionFormat::Text => { + if short { + writeln!(printer.stdout(), "{}", version_info.cyan())?; + } else { + writeln!(printer.stdout(), "uv {}", version_info.cyan())?; + } + } + VersionFormat::Json => { + let string = serde_json::to_string_pretty(&version_info)?; + writeln!(printer.stdout(), "{string}")?; + } + } Ok(ExitStatus::Success) } @@ -349,8 +361,8 @@ pub(crate) async fn project_version( }; // Report the results - let old_version = VersionInfo::new(Some(&name), &old_version); - let new_version = new_version.map(|version| VersionInfo::new(Some(&name), &version)); + let old_version = ProjectVersionInfo::new(Some(&name), &old_version); + let new_version = new_version.map(|version| ProjectVersionInfo::new(Some(&name), &version)); print_version(old_version, new_version, short, output_format, printer)?; Ok(status) @@ -521,7 +533,7 @@ async fn print_frozen_version( }; // Finally, print! - let old_version = VersionInfo::new(Some(name), version); + let old_version = ProjectVersionInfo::new(Some(name), version); print_version(old_version, None, short, output_format, printer)?; Ok(ExitStatus::Success) @@ -708,8 +720,8 @@ async fn lock_and_sync( } fn print_version( - old_version: VersionInfo, - new_version: Option, + old_version: ProjectVersionInfo, + new_version: Option, short: bool, output_format: VersionFormat, printer: Printer, diff --git a/crates/uv/tests/it/version.rs b/crates/uv/tests/it/version.rs index c4e447108..0ba781611 100644 --- a/crates/uv/tests/it/version.rs +++ b/crates/uv/tests/it/version.rs @@ -2351,6 +2351,7 @@ fn self_version_json() -> Result<()> { r#"commits_since_last_tag": .*"#, r#"commits_since_last_tag": [COUNT]"#, ), + (r#"target_triple": ".*""#, r#"target_triple": "[TARGET]""#), ]) .collect::>(); @@ -2369,7 +2370,8 @@ fn self_version_json() -> Result<()> { "commit_date": "[DATE]", "last_tag": "[TAG]", "commits_since_last_tag": [COUNT] - } + }, + "target_triple": "[TARGET]" } ----- stderr ----- @@ -2383,7 +2385,8 @@ fn self_version_json() -> Result<()> { { "package_name": "uv", "version": "[VERSION]", - "commit_info": null + "commit_info": null, + "target_triple": "[TARGET]" } ----- stderr -----