diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index c3707df1dfe..79383963061 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -164,10 +164,7 @@ pub fn get_version_string(is_verbose: bool) -> String { let version = cargo::version(); let mut version_string = format!("cargo {}\n", version); if is_verbose { - version_string.push_str(&format!( - "release: {}.{}.{}\n", - version.major, version.minor, version.patch - )); + version_string.push_str(&format!("release: {}\n", version.version,)); if let Some(ref cfg) = version.cfg_info { if let Some(ref ci) = cfg.commit_info { version_string.push_str(&format!("commit-hash: {}\n", ci.commit_hash)); diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 04d6d0a94e2..e4178fd1630 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -12,10 +12,10 @@ use crate::core::shell::Verbosity::Verbose; use crate::core::Shell; use anyhow::Error; use log::debug; -use std::fmt; pub use crate::util::errors::{InternalError, VerboseError}; pub use crate::util::{indented_lines, CargoResult, CliError, CliResult, Config}; +pub use crate::version::version; pub const CARGO_ENV: &str = "CARGO"; @@ -26,49 +26,7 @@ pub mod core; pub mod ops; pub mod sources; pub mod util; - -pub struct CommitInfo { - pub short_commit_hash: String, - pub commit_hash: String, - pub commit_date: String, -} - -pub struct CfgInfo { - // Information about the Git repository we may have been built from. - pub commit_info: Option, - // The release channel we were built for. - pub release_channel: String, -} - -pub struct VersionInfo { - pub major: u8, - pub minor: u8, - pub patch: u8, - pub pre_release: Option, - // Information that's only available when we were built with - // configure/make, rather than Cargo itself. - pub cfg_info: Option, -} - -impl fmt::Display for VersionInfo { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?; - if let Some(channel) = self.cfg_info.as_ref().map(|ci| &ci.release_channel) { - if channel != "stable" { - write!(f, "-{}", channel)?; - let empty = String::new(); - write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?; - } - }; - - if let Some(ref cfg) = self.cfg_info { - if let Some(ref ci) = cfg.commit_info { - write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; - } - }; - Ok(()) - } -} +mod version; pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! { debug!("exit_with_error; err={:?}", err); @@ -143,58 +101,3 @@ fn _display_error(err: &Error, shell: &mut Shell, as_err: bool) -> bool { } false } - -pub fn version() -> VersionInfo { - macro_rules! option_env_str { - ($name:expr) => { - option_env!($name).map(|s| s.to_string()) - }; - } - - // So this is pretty horrible... - // There are two versions at play here: - // - version of cargo-the-binary, which you see when you type `cargo --version` - // - version of cargo-the-library, which you download from crates.io for use - // in your packages. - // - // We want to make the `binary` version the same as the corresponding Rust/rustc release. - // At the same time, we want to keep the library version at `0.x`, because Cargo as - // a library is (and probably will always be) unstable. - // - // Historically, Cargo used the same version number for both the binary and the library. - // Specifically, rustc 1.x.z was paired with cargo 0.x+1.w. - // We continue to use this scheme for the library, but transform it to 1.x.w for the purposes - // of `cargo --version`. - let major = 1; - let minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap() - 1; - let patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); - - match option_env!("CFG_RELEASE_CHANNEL") { - // We have environment variables set up from configure/make. - Some(_) => { - let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo { - commit_hash: s.to_string(), - short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(), - commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(), - }); - VersionInfo { - major, - minor, - patch, - pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"), - cfg_info: Some(CfgInfo { - release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(), - commit_info, - }), - } - } - // We are being compiled by Cargo itself. - None => VersionInfo { - major, - minor, - patch, - pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"), - cfg_info: None, - }, - } -} diff --git a/src/cargo/version.rs b/src/cargo/version.rs new file mode 100644 index 00000000000..6dbb9d1c100 --- /dev/null +++ b/src/cargo/version.rs @@ -0,0 +1,95 @@ +//! Code for representing cargo's release version number. + +use std::fmt; + +/// Information about the git repository where cargo was built from. +pub struct CommitInfo { + pub short_commit_hash: String, + pub commit_hash: String, + pub commit_date: String, +} + +/// Information provided by the outer build system (rustbuild aka bootstrap). +pub struct CfgInfo { + /// Information about the Git repository we may have been built from. + pub commit_info: Option, + /// The release channel we were built for (stable/beta/nightly/dev). + pub release_channel: String, +} + +/// Cargo's version. +pub struct VersionInfo { + /// Cargo's version, such as "1.57.0", "1.58.0-beta.1", "1.59.0-nightly", etc. + pub version: String, + /// Information that's only available when we were built with + /// rustbuild, rather than Cargo itself. + pub cfg_info: Option, +} + +impl fmt::Display for VersionInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.version)?; + + if let Some(ref cfg) = self.cfg_info { + if let Some(ref ci) = cfg.commit_info { + write!(f, " ({} {})", ci.short_commit_hash, ci.commit_date)?; + } + }; + Ok(()) + } +} + +/// Returns information about cargo's version. +pub fn version() -> VersionInfo { + macro_rules! option_env_str { + ($name:expr) => { + option_env!($name).map(|s| s.to_string()) + }; + } + + // This is the version set in rustbuild, which we use to match rustc. + let version = option_env_str!("CFG_RELEASE").unwrap_or_else(|| { + // If cargo is not being built by rustbuild, then we just use the + // version from cargo's own `Cargo.toml`. + // + // There are two versions at play here: + // - version of cargo-the-binary, which you see when you type `cargo --version` + // - version of cargo-the-library, which you download from crates.io for use + // in your packages. + // + // The library is permanently unstable, so it always has a 0 major + // version. However, the CLI now reports a stable 1.x version + // (starting in 1.26) which stays in sync with rustc's version. + // + // Coincidentally, the minor version for cargo-the-library is always + // +1 of rustc's minor version (that is, `rustc 1.11.0` corresponds to + // `cargo `0.12.0`). The versions always get bumped in lockstep, so + // this should continue to hold. + let minor = env!("CARGO_PKG_VERSION_MINOR").parse::().unwrap() - 1; + let patch = env!("CARGO_PKG_VERSION_PATCH").parse::().unwrap(); + format!("1.{}.{}", minor, patch) + }); + + match option_env!("CFG_RELEASE_CHANNEL") { + // We have environment variables set up from configure/make. + Some(_) => { + let commit_info = option_env!("CFG_COMMIT_HASH").map(|s| CommitInfo { + commit_hash: s.to_string(), + short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(), + commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(), + }); + VersionInfo { + version, + cfg_info: Some(CfgInfo { + release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(), + commit_info, + }), + } + } + // We are being compiled by Cargo itself. + None => VersionInfo { + version, + cfg_info: None, + }, + } +}