Skip to content

Commit 775c900

Browse files
committed
export rich version information from cargo::version
To support `cargo --version --verbose`, ala rustc, we need more information to be injected into cargo when it's built from the Makefile, and a more explicit data structure to be returned from cargo::version. We implement fmt::Display for our newly-created structure so clients don't have to bother with the details of interpreting the structure if all they want is a string.
1 parent 84ef722 commit 775c900

File tree

3 files changed

+121
-16
lines changed

3 files changed

+121
-16
lines changed

Makefile.in

+22-6
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@ endif
2525
# allow build systems to use a constant date instead of the current one
2626
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)
2727

28-
ifeq ($(wildcard $(CFG_SRC_DIR)/.git),)
29-
CFG_VERSION = $(CFG_RELEASE) (built $(CFG_BUILD_DATE))
30-
else
31-
CFG_VER_DATE = $(shell git --git-dir='$(CFG_SRC_DIR).git' log -1 --date=short --pretty=format:'%cd')
32-
CFG_VER_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse --short HEAD)
33-
CFG_VERSION = $(CFG_RELEASE) ($(CFG_VER_HASH) $(CFG_VER_DATE))
28+
ifneq ($(wildcard $(CFG_SRC_DIR)/.git),)
29+
CFG_COMMIT_DATE = $(shell git --git-dir='$(CFG_SRC_DIR).git' log -1 --date=short --pretty=format:'%cd')
30+
CFG_SHORT_COMMIT_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse --short HEAD)
31+
CFG_COMMIT_HASH = $(shell git --git-dir='$(CFG_SRC_DIR).git' rev-parse HEAD)
3432
endif
3533
PKG_NAME = cargo-$(CFG_PACKAGE_VERS)
3634

@@ -58,7 +56,25 @@ endif
5856

5957
S := $(CFG_SRC_DIR)/
6058

59+
CFG_RELEASE_PARTS := $(subst ., ,$(CFG_RELEASE_NUM))
60+
CFG_VERSION_MAJOR := $(word 1,$(CFG_RELEASE_PARTS))
61+
CFG_VERSION_MINOR := $(word 2,$(CFG_RELEASE_PARTS))
62+
CFG_VERSION_PATCH := $(word 3,$(CFG_RELEASE_PARTS))
63+
6164
export CFG_VERSION
65+
export CFG_VERSION_MAJOR
66+
export CFG_VERSION_MINOR
67+
export CFG_VERSION_PATCH
68+
ifneq ($(CFG_PRERELEASE_VERSION),)
69+
export CFG_PRERELEASE_VERSION
70+
endif
71+
ifneq ($(CFG_COMMIT_HASH),)
72+
export CFG_COMMIT_HASH
73+
export CFG_COMMIT_DATE
74+
export CFG_SHORT_COMMIT_HASH
75+
endif
76+
export CFG_BUILD_DATE
77+
export CFG_RELEASE_CHANNEL
6278
export CFG_DISABLE_CROSS_TESTS
6379

6480
ifeq ($(OS),Windows_NT)

src/cargo/lib.rs

100644100755
+98-9
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern crate toml;
2626
extern crate url;
2727

2828
use std::env;
29+
use std::fmt;
2930
use std::io;
3031
use rustc_serialize::{Decodable, Encodable};
3132
use rustc_serialize::json;
@@ -49,6 +50,62 @@ pub mod ops;
4950
pub mod sources;
5051
pub mod util;
5152

53+
pub struct CommitInfo {
54+
pub short_commit_hash: String,
55+
pub commit_hash: String,
56+
pub commit_date: String,
57+
}
58+
59+
pub struct CfgInfo {
60+
// Information about the git repository we may have been built from.
61+
pub commit_info: Option<CommitInfo>,
62+
// The date that the build was performed.
63+
pub build_date: String,
64+
// The release channel we were built for.
65+
pub release_channel: String,
66+
}
67+
68+
pub struct VersionInfo {
69+
pub major: String,
70+
pub minor: String,
71+
pub patch: String,
72+
pub pre_release: Option<String>,
73+
// Information that's only available when we were built with
74+
// configure/make, rather than cargo itself.
75+
pub cfg_info: Option<CfgInfo>,
76+
}
77+
78+
impl fmt::Display for VersionInfo {
79+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80+
write!(f, "cargo-{}.{}.{}",
81+
self.major, self.minor, self.patch)?;
82+
match self.cfg_info.as_ref().map(|ci| &ci.release_channel) {
83+
Some(channel) => {
84+
if channel != "stable" {
85+
write!(f, "-{}", channel)?;
86+
let empty = String::from("");
87+
write!(f, "{}", self.pre_release.as_ref().unwrap_or(&empty))?;
88+
}
89+
},
90+
None => (),
91+
};
92+
93+
if let Some(ref cfg) = self.cfg_info {
94+
match cfg.commit_info {
95+
Some(ref ci) => {
96+
write!(f, " ({} {})",
97+
ci.short_commit_hash, ci.commit_date)?;
98+
},
99+
None => {
100+
write!(f, " (built {})",
101+
cfg.build_date)?;
102+
}
103+
}
104+
};
105+
Ok(())
106+
}
107+
}
108+
52109
pub fn execute_main_without_stdin<T, V>(
53110
exec: fn(T, &Config) -> CliResult<Option<V>>,
54111
options_first: bool,
@@ -201,15 +258,47 @@ fn handle_cause(mut cargo_err: &CargoError, shell: &mut MultiShell) -> bool {
201258
}
202259
}
203260

204-
pub fn version() -> String {
205-
format!("cargo {}", match option_env!("CFG_VERSION") {
206-
Some(s) => s.to_string(),
207-
None => format!("{}.{}.{}{}",
208-
env!("CARGO_PKG_VERSION_MAJOR"),
209-
env!("CARGO_PKG_VERSION_MINOR"),
210-
env!("CARGO_PKG_VERSION_PATCH"),
211-
option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
212-
})
261+
pub fn version() -> VersionInfo {
262+
macro_rules! env_str {
263+
($name:expr) => { env!($name).to_string() }
264+
}
265+
macro_rules! option_env_str {
266+
($name:expr) => { option_env!($name).map(|s| s.to_string()) }
267+
}
268+
match option_env!("CFG_RELEASE_CHANNEL") {
269+
// We have environment variables set up from configure/make.
270+
Some(_) => {
271+
let commit_info =
272+
option_env!("CFG_COMMIT_HASH").map(|s| {
273+
CommitInfo {
274+
commit_hash: s.to_string(),
275+
short_commit_hash: option_env_str!("CFG_SHORT_COMMIT_HASH").unwrap(),
276+
commit_date: option_env_str!("CFG_COMMIT_DATE").unwrap(),
277+
}
278+
});
279+
VersionInfo {
280+
major: option_env_str!("CFG_VERSION_MAJOR").unwrap(),
281+
minor: option_env_str!("CFG_VERSION_MINOR").unwrap(),
282+
patch: option_env_str!("CFG_VERSION_PATCH").unwrap(),
283+
pre_release: option_env_str!("CFG_PRERELEASE_VERSION"),
284+
cfg_info: Some(CfgInfo {
285+
build_date: option_env_str!("CFG_BUILD_DATE").unwrap(),
286+
release_channel: option_env_str!("CFG_RELEASE_CHANNEL").unwrap(),
287+
commit_info: commit_info,
288+
}),
289+
}
290+
},
291+
// We are being compiled by Cargo itself.
292+
None => {
293+
VersionInfo {
294+
major: env_str!("CARGO_PKG_VERSION_MAJOR"),
295+
minor: env_str!("CARGO_PKG_VERSION_MINOR"),
296+
patch: env_str!("CARGO_PKG_VERSION_PATCH"),
297+
pre_release: option_env_str!("CARGO_PKG_VERSION_PRE"),
298+
cfg_info: None,
299+
}
300+
}
301+
}
213302
}
214303

215304
fn flags_from_args<T>(usage: &str, args: &[String], options_first: bool) -> CliResult<T>

src/cargo/ops/registry.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ pub fn http_handle(config: &Config) -> CargoResult<Easy> {
225225
handle.connect_timeout(Duration::new(30, 0))?;
226226
handle.low_speed_limit(10 /* bytes per second */)?;
227227
handle.low_speed_time(Duration::new(30, 0))?;
228-
handle.useragent(&version())?;
228+
handle.useragent(&version().to_string())?;
229229
if let Some(proxy) = http_proxy(config)? {
230230
handle.proxy(&proxy)?;
231231
}

0 commit comments

Comments
 (0)