diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index 5f66ff4f30ea..529f1161a0f7 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -5,7 +5,7 @@ use std::env; use std::ffi::OsStr; use std::fs; use std::lazy::SyncLazy; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use walkdir::WalkDir; use crate::clippy_project_root; @@ -16,7 +16,15 @@ pub static CARGO_TARGET_DIR: SyncLazy = SyncLazy::new(|| match env::var None => env::current_dir().unwrap().join("target"), }); -pub fn bless() { +static CLIPPY_BUILD_TIME: SyncLazy> = SyncLazy::new(|| { + let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); + let mut path = PathBuf::from(&**CARGO_TARGET_DIR); + path.push(profile); + path.push("cargo-clippy"); + fs::metadata(path).ok()?.modified().ok() +}); + +pub fn bless(ignore_timestamp: bool) { let test_suite_dirs = [ clippy_project_root().join("tests").join("ui"), clippy_project_root().join("tests").join("ui-toml"), @@ -29,15 +37,18 @@ pub fn bless() { .filter(|f| f.path().extension() == Some(OsStr::new("rs"))) .for_each(|f| { let test_name = f.path().strip_prefix(test_suite_dir).unwrap(); - - update_reference_file(f.path().with_extension("stdout"), test_name.with_extension("stdout")); - update_reference_file(f.path().with_extension("stderr"), test_name.with_extension("stderr")); - update_reference_file(f.path().with_extension("fixed"), test_name.with_extension("fixed")); + for &ext in &["stdout", "stderr", "fixed"] { + update_reference_file( + f.path().with_extension(ext), + test_name.with_extension(ext), + ignore_timestamp, + ); + } }); } } -fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) { +fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) { let test_output_path = build_dir().join(test_name); let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap(); @@ -47,6 +58,11 @@ fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) { return; } + // If the test output was not updated since the last clippy build, it may be outdated + if !ignore_timestamp && !updated_since_clippy_build(&test_output_path).unwrap_or(true) { + return; + } + let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file"); let reference_file = fs::read(&reference_file_path).unwrap_or_default(); @@ -66,6 +82,12 @@ fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) { } } +fn updated_since_clippy_build(path: &Path) -> Option { + let clippy_build_time = (*CLIPPY_BUILD_TIME)?; + let modified = fs::metadata(path).ok()?.modified().ok()?; + Some(modified >= clippy_build_time) +} + fn build_dir() -> PathBuf { let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); let mut path = PathBuf::new(); diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 4fdae38e3ab7..2ea56c42fafd 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -7,8 +7,8 @@ fn main() { let matches = get_clap_config(); match matches.subcommand() { - ("bless", Some(_)) => { - bless::bless(); + ("bless", Some(matches)) => { + bless::bless(matches.is_present("ignore-timestamp")); }, ("fmt", Some(matches)) => { fmt::run(matches.is_present("check"), matches.is_present("verbose")); @@ -47,7 +47,15 @@ fn main() { fn get_clap_config<'a>() -> ArgMatches<'a> { App::new("Clippy developer tooling") - .subcommand(SubCommand::with_name("bless").about("bless the test output changes")) + .subcommand( + SubCommand::with_name("bless") + .about("bless the test output changes") + .arg( + Arg::with_name("ignore-timestamp") + .long("ignore-timestamp") + .help("Include files updated before clippy was built"), + ), + ) .subcommand( SubCommand::with_name("fmt") .about("Run rustfmt on all projects and tests")