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