summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_dev/src/bless.rs
blob: f5c51b9474fcd878cf631441cc03a194d239301b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.

use crate::cargo_clippy_path;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use walkdir::{DirEntry, WalkDir};

static CLIPPY_BUILD_TIME: LazyLock<Option<std::time::SystemTime>> =
    LazyLock::new(|| cargo_clippy_path().metadata().ok()?.modified().ok());

/// # Panics
///
/// Panics if the path to a test file is broken
pub fn bless(ignore_timestamp: bool) {
    let extensions = ["stdout", "stderr", "fixed"].map(OsStr::new);

    WalkDir::new(build_dir())
        .into_iter()
        .map(Result::unwrap)
        .filter(|entry| entry.path().extension().map_or(false, |ext| extensions.contains(&ext)))
        .for_each(|entry| update_reference_file(&entry, ignore_timestamp));
}

fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
    let test_output_path = test_output_entry.path();

    let reference_file_name = test_output_entry.file_name().to_str().unwrap().replace(".stage-id", "");
    let reference_file_path = Path::new("tests")
        .join(test_output_path.strip_prefix(build_dir()).unwrap())
        .with_file_name(reference_file_name);

    // 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_entry).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();

    if test_output_file != reference_file {
        // If a test run caused an output file to change, update the reference file
        println!("updating {}", reference_file_path.display());
        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
    }
}

fn updated_since_clippy_build(entry: &DirEntry) -> Option<bool> {
    let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
    let modified = entry.metadata().ok()?.modified().ok()?;
    Some(modified >= clippy_build_time)
}

fn build_dir() -> PathBuf {
    let mut path = std::env::current_exe().unwrap();
    path.set_file_name("test");
    path
}