From 5361f611107bdaed67dfeffe3e20aad082556ef7 Mon Sep 17 00:00:00 2001 From: Kamal Marhubi Date: Sun, 12 Jun 2016 10:38:03 +0200 Subject: [PATCH] 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. --- Cargo.lock | 10 ++++++++ Cargo.toml | 4 ++++ build.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++ src/bin/rustfmt.rs | 18 +++++++++++---- tests/system.rs | 1 + 5 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 build.rs diff --git a/Cargo.lock b/Cargo.lock index 1835836ba35..84293a46205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index d00f651aad1..dbf3e1edee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/build.rs b/build.rs new file mode 100644 index 00000000000..9192426f99a --- /dev/null +++ b/build.rs @@ -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 = {:?};", + 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 { + 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 { + Command::new("git") + .arg("status") + .arg("--porcelain") + .arg("--untracked-files=no") + .output() + .ok() + .map(|o| o.stdout.is_empty()) +} diff --git a/src/bin/rustfmt.rs b/src/bin/rustfmt.rs index 5aa7cc4e080..30894b9d03c 100644 --- a/src/bin/rustfmt.rs +++ b/src/bin/rustfmt.rs @@ -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 = 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; type FmtResult = std::result::Result; @@ -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 { diff --git a/tests/system.rs b/tests/system.rs index 38d1e8584a5..08ec576f221 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -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;