]> git.lizzy.rs Git - rust.git/blob - clippy_dev/src/bless.rs
48a2458594c724f006785008a48fe2bdebd9f7da
[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::env;
5 use std::ffi::OsStr;
6 use std::fs;
7 use std::lazy::SyncLazy;
8 use std::path::PathBuf;
9 use walkdir::WalkDir;
10
11 use crate::clippy_project_root;
12
13 // NOTE: this is duplicated with tests/cargo/mod.rs What to do?
14 pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
15     Some(v) => v.into(),
16     None => env::current_dir().unwrap().join("target"),
17 });
18
19 pub fn bless() {
20     let test_dirs = [
21         clippy_project_root().join("tests").join("ui"),
22         clippy_project_root().join("tests").join("ui-toml"),
23         clippy_project_root().join("tests").join("ui-cargo"),
24     ];
25     for test_dir in &test_dirs {
26         WalkDir::new(test_dir)
27             .into_iter()
28             .filter_map(Result::ok)
29             .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
30             .for_each(|f| {
31                 let test_name = f.path().strip_prefix(test_dir).unwrap();
32
33                 update_reference_file(f.path().with_extension("stdout"), test_name.with_extension("stdout"));
34                 update_reference_file(f.path().with_extension("stderr"), test_name.with_extension("stderr"));
35                 update_reference_file(f.path().with_extension("fixed"), test_name.with_extension("fixed"));
36             });
37     }
38 }
39
40 fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) {
41     let test_output_path = build_dir().join(test_name);
42     let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
43
44     // If compiletest did not write any changes during the test run,
45     // we don't have to update anything
46     if !test_output_path.exists() {
47         return;
48     }
49
50     let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
51     let reference_file = fs::read(&reference_file_path).unwrap_or_default();
52
53     if test_output_file != reference_file {
54         // If a test run caused an output file to change, update the reference file
55         println!("updating {}", &relative_reference_file_path.display());
56         fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
57
58         // We need to re-read the file now because it was potentially updated from copying
59         let reference_file = fs::read(&reference_file_path).unwrap_or_default();
60
61         if reference_file.is_empty() {
62             // If we copied over an empty output file, we remove the now empty reference file
63             println!("removing {}", &relative_reference_file_path.display());
64             fs::remove_file(reference_file_path).expect("Could not remove reference file");
65         }
66     }
67 }
68
69 fn build_dir() -> PathBuf {
70     let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
71     let mut path = PathBuf::new();
72     path.push(CARGO_TARGET_DIR.clone());
73     path.push(profile);
74     path.push("test_build_base");
75     path
76 }