]> git.lizzy.rs Git - rust.git/blob - clippy_dev/src/bless.rs
Auto merge of #8250 - pr2502:fix_repeat_underflow, r=giraffate
[rust.git] / clippy_dev / src / bless.rs
1 //! `bless` updates the reference files in the repo with changed output files
2 //! from the last test run.
3
4 use std::ffi::OsStr;
5 use std::fs;
6 use std::lazy::SyncLazy;
7 use std::path::{Path, PathBuf};
8 use walkdir::WalkDir;
9
10 use crate::clippy_project_root;
11
12 #[cfg(not(windows))]
13 static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
14 #[cfg(windows)]
15 static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
16
17 static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
18     let mut path = std::env::current_exe().unwrap();
19     path.set_file_name(CARGO_CLIPPY_EXE);
20     fs::metadata(path).ok()?.modified().ok()
21 });
22
23 /// # Panics
24 ///
25 /// Panics if the path to a test file is broken
26 pub fn bless(ignore_timestamp: bool) {
27     let test_suite_dirs = [
28         clippy_project_root().join("tests").join("ui"),
29         clippy_project_root().join("tests").join("ui-internal"),
30         clippy_project_root().join("tests").join("ui-toml"),
31         clippy_project_root().join("tests").join("ui-cargo"),
32     ];
33     for test_suite_dir in &test_suite_dirs {
34         WalkDir::new(test_suite_dir)
35             .into_iter()
36             .filter_map(Result::ok)
37             .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
38             .for_each(|f| {
39                 let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
40                 for &ext in &["stdout", "stderr", "fixed"] {
41                     let test_name_ext = format!("stage-id.{}", ext);
42                     update_reference_file(
43                         f.path().with_extension(ext),
44                         test_name.with_extension(test_name_ext),
45                         ignore_timestamp,
46                     );
47                 }
48             });
49     }
50 }
51
52 fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) {
53     let test_output_path = build_dir().join(test_name);
54     let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
55
56     // If compiletest did not write any changes during the test run,
57     // we don't have to update anything
58     if !test_output_path.exists() {
59         return;
60     }
61
62     // If the test output was not updated since the last clippy build, it may be outdated
63     if !ignore_timestamp && !updated_since_clippy_build(&test_output_path).unwrap_or(true) {
64         return;
65     }
66
67     let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
68     let reference_file = fs::read(&reference_file_path).unwrap_or_default();
69
70     if test_output_file != reference_file {
71         // If a test run caused an output file to change, update the reference file
72         println!("updating {}", &relative_reference_file_path.display());
73         fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
74
75         // We need to re-read the file now because it was potentially updated from copying
76         let reference_file = fs::read(&reference_file_path).unwrap_or_default();
77
78         if reference_file.is_empty() {
79             // If we copied over an empty output file, we remove the now empty reference file
80             println!("removing {}", &relative_reference_file_path.display());
81             fs::remove_file(reference_file_path).expect("Could not remove reference file");
82         }
83     }
84 }
85
86 fn updated_since_clippy_build(path: &Path) -> Option<bool> {
87     let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
88     let modified = fs::metadata(path).ok()?.modified().ok()?;
89     Some(modified >= clippy_build_time)
90 }
91
92 fn build_dir() -> PathBuf {
93     let mut path = std::env::current_exe().unwrap();
94     path.set_file_name("test");
95     path
96 }