Include git commit and worktree status in version output (#1060)

This will help in debugging issues as rustfmt gets more users.

If the working tree is clean, output looks like

    $ target/debug/rustfmt -V
    0.5.0 (9f5ed3b)

If the working tree is dirty, output looks like

    $ target/debug/rustfmt -V
    0.5.0 (9f5ed3b worktree dirty)

If git is unavailable, output looks like

    $ target/debug/rustfmt -V
    0.5.0 (git commit unavailable)

To avoid rebuilds on changing tests, the build script will only rerun if
files under src/ are changed. This means the actual git status may show
changed files and this would not show up in the version. This should not
be an issue as files not in src/ should not affect the build output.
This commit is contained in:
Kamal Marhubi 2016-06-12 10:38:03 +02:00 committed by Marcus Klaas de Vries
parent 1743f5caf6
commit 5361f61110
5 changed files with 85 additions and 5 deletions

10
Cargo.lock generated
View File

@ -17,6 +17,7 @@ dependencies = [
"term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -190,6 +191,15 @@ name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.7"

View File

@ -8,6 +8,7 @@ repository = "https://github.com/rust-lang-nursery/rustfmt"
readme = "README.md"
license = "Apache-2.0/MIT"
include = ["src/*.rs", "Cargo.toml"]
build = "build.rs"
[features]
default = ["cargo-fmt"]
@ -28,6 +29,9 @@ getopts = "0.2"
itertools = "0.4.15"
multimap = "0.3"
[build-dependencies]
walkdir = "0.1.5"
[target.'cfg(unix)'.dependencies]
libc = "0.2.11"

57
build.rs Normal file
View File

@ -0,0 +1,57 @@
extern crate walkdir;
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use walkdir::WalkDir;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("git_info.rs");
let mut f = File::create(&dest_path).unwrap();
writeln!(f,
"const COMMIT_HASH: Option<&'static str> = {:?};",
git_head_sha1())
.unwrap();
writeln!(f,
"const WORKTREE_CLEAN: Option<bool> = {:?};",
git_tree_is_clean())
.unwrap();
// cargo:rerun-if-changed requires one entry per individual file.
for entry in WalkDir::new("src") {
let entry = entry.unwrap();
println!("cargo:rerun-if-changed={}", entry.path().display());
}
}
// Returns `None` if git is not available.
fn git_head_sha1() -> Option<String> {
Command::new("git")
.arg("rev-parse")
.arg("--short")
.arg("HEAD")
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.map(|mut s| {
let len = s.trim_right().len();
s.truncate(len);
s
})
}
// Returns `None` if git is not available.
fn git_tree_is_clean() -> Option<bool> {
Command::new("git")
.arg("status")
.arg("--porcelain")
.arg("--untracked-files=no")
.output()
.ok()
.map(|o| o.stdout.is_empty())
}

View File

@ -29,6 +29,12 @@ use std::str::FromStr;
use getopts::{Matches, Options};
// Include git commit hash and worktree status; contents are like
// const COMMIT_HASH: Option<&'static str> = Some("c31a366");
// const WORKTREE_CLEAN: Option<bool> = Some(false);
// with `None` if running git failed, eg if it is not installed.
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));
type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;
@ -291,11 +297,13 @@ fn print_usage(opts: &Options, reason: &str) {
}
fn print_version() {
println!("{}.{}.{}{}",
option_env!("CARGO_PKG_VERSION_MAJOR").unwrap_or("X"),
option_env!("CARGO_PKG_VERSION_MINOR").unwrap_or("X"),
option_env!("CARGO_PKG_VERSION_PATCH").unwrap_or("X"),
option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""));
println!("{} ({}{})",
option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
COMMIT_HASH.unwrap_or("git commit unavailable"),
match WORKTREE_CLEAN {
Some(false) => " worktree dirty",
_ => "",
});
}
fn determine_operation(matches: &Matches) -> FmtResult<Operation> {

View File

@ -121,6 +121,7 @@ fn self_tests() {
.map(get_path_string);
// Hack because there's no `IntoIterator` impl for `[T; N]`.
let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
let files = files.chain(Some("build.rs".to_owned()).into_iter());
let (reports, count, fails) = check_files(files);
let mut warnings = 0;