diff --git a/Makefile.in b/Makefile.in index f4862903678..4a410d6d4a3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,12 +25,10 @@ endif # allow build systems to use a constant date instead of the current one CFG_BUILD_DATE = $(shell SOURCE_DATE_EPOCH="$${SOURCE_DATE_EPOCH:-$$(date +%s)}" ; date -u -d "@$$SOURCE_DATE_EPOCH" +%F 2>/dev/null || date -u -r "$$SOURCE_DATE_EPOCH" +%F 2>/dev/null || date -u +%F) -ifeq ($(wildcard $(CFG_SRC_DIR)/.git),) -CFG_VERSION = $(CFG_RELEASE) (built $(CFG_BUILD_DATE)) -else -CFG_VER_DATE = $(shell git --git-dir='$(CFG_SRC_DIR).git' log -1 --date=short --pretty=format:'%cd') -CFG_VER_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse --short HEAD) -CFG_VERSION = $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE)) +ifneq ($(wildcard $(CFG_SRC_DIR)/.git),) +CFG_COMMIT_DATE = $(shell git --git-dir='$(CFG_SRC_DIR).git' log -1 --date=short --pretty=format:'%cd') +CFG_SHORT_COMMIT_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse --short HEAD) +CFG_COMMIT_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse HEAD) endif PKG_NAME = cargo-$(CFG_PACKAGE_VERS) @@ -58,7 +56,25 @@ endif S := $(CFG_SRC_DIR)/ +CFG_RELEASE_PARTS := $(subst ., ,$(CFG_RELEASE_NUM)) +CFG_VERSION_MAJOR := $(word 1,$(CFG_RELEASE_PARTS)) +CFG_VERSION_MINOR := $(word 2,$(CFG_RELEASE_PARTS)) +CFG_VERSION_PATCH := $(word 3,$(CFG_RELEASE_PARTS)) + export CFG_VERSION +export CFG_VERSION_MAJOR +export CFG_VERSION_MINOR +export CFG_VERSION_PATCH +ifneq ($(CFG_PRERELEASE_VERSION),) +export CFG_PRERELEASE_VERSION +endif +ifneq ($(CFG_COMMIT_HASH),) +export CFG_COMMIT_HASH +export CFG_COMMIT_DATE +export CFG_SHORT_COMMIT_HASH +endif +export CFG_BUILD_DATE +export CFG_RELEASE_CHANNEL export CFG_DISABLE_CROSS_TESTS ifeq ($(OS),Windows_NT) diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs old mode 100644 new mode 100755 index 46daa9441e7..b1e4198f829 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -26,6 +26,7 @@ extern crate toml; extern crate url; use std::env; +use std::fmt; use std::io; use rustc_serialize::{Decodable, Encodable}; use rustc_serialize::json; @@ -49,6 +50,62 @@ 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 date that the build was performed. + pub build_date: String, + // The release channel we were built for. + pub release_channel: String, +} + +pub struct VersionInfo { + pub major: String, + pub minor: String, + pub patch: String, + 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, "cargo-{}.{}.{}", + self.major, self.minor, self.patch)?; + match self.cfg_info.as_ref().map(|ci| &ci.release_channel) { + Some(channel) => { + if channel != "stable" { + write!(f, "-{}", channel)?; + let empty = String::from(""); + write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?; + } + }, + None => (), + }; + + if let Some(ref cfg) = self.cfg_info { + match cfg.commit_info { + Some(ref ci) => { + write!(f, " ({} {})", + ci.short_commit_hash, ci.commit_date)?; + }, + None => { + write!(f, " (built {})", + cfg.build_date)?; + } + } + }; + Ok(()) + } +} + pub fn execute_main_without_stdin( exec: fn(T, &Config) -> CliResult>, options_first: bool, @@ -201,15 +258,47 @@ fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool { } } -pub fn version() -> String { - format!("cargo {}", match option_env!("CFG_VERSION") { - Some(s) => s.to_string(), - None => format!("{}.{}.{}{}", - env!("CARGO_PKG_VERSION_MAJOR"), - env!("CARGO_PKG_VERSION_MINOR"), - env!("CARGO_PKG_VERSION_PATCH"), - option_env!("CARGO_PKG_VERSION_PRE").unwrap_or("")) - }) +pub fn version() -> VersionInfo { + macro_rules! env_str { + ($name:expr) => { env!($name).to_string() } + } + macro_rules! option_env_str { + ($name:expr) => { option_env!($name).map(|s| s.to_string()) } + } + 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: option_env_str!("CFG_VERSION_MAJOR").unwrap(), + minor: option_env_str!("CFG_VERSION_MINOR").unwrap(), + patch: option_env_str!("CFG_VERSION_PATCH").unwrap(), + pre_release: option_env_str!("CFG_PRERELEASE_VERSION"), + cfg_info: Some(CfgInfo { + build_date: option_env_str!("CFG_BUILD_DATE").unwrap(), + release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(), + commit_info: commit_info, + }), + } + }, + // We are being compiled by Cargo itself. + None => { + VersionInfo { + major: env_str!("CARGO_PKG_VERSION_MAJOR"), + minor: env_str!("CARGO_PKG_VERSION_MINOR"), + patch: env_str!("CARGO_PKG_VERSION_PATCH"), + pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"), + cfg_info: None, + } + } + } } fn flags_from_args(usage: &str, args: &[String], options_first: bool) -> CliResult diff --git a/src/cargo/ops/registry.rs b/src/cargo/ops/registry.rs index f3c8de93415..f8ca6dbc403 100644 --- a/src/cargo/ops/registry.rs +++ b/src/cargo/ops/registry.rs @@ -225,7 +225,7 @@ pub fn http_handle(config: &Config) -> CargoResult { handle.connect_timeout(Duration::new(30, 0))?; handle.low_speed_limit(10 /* bytes per second */)?; handle.low_speed_time(Duration::new(30, 0))?; - handle.useragent(&version())?; + handle.useragent(&version().to_string())?; if let Some(proxy) = http_proxy(config)? { handle.proxy(&proxy)?; }