For a list of files how do I run a build script only for the files that were changed?

Viewed 303

I have a list of files and want to run some program for every file, but only if it was changed. So I put all the files in the vector and iterated, like this:

// build.rs

let files = vec![
    "fileA",
    "fileB",
];

for file in files{
    println!("cargo:rerun-if-changed={}", file);

    let output = Command::new("glslangValidator")
        .args(&["-V", file, "-o", file])
        .output()
        .expect("failed to run glslangValidator");
}

This works, but the build process runs for every file even if only one from the list was changed. Instead, I want glslangValidator to be called only for the files that were changed between builds.

1 Answers

If the command you're calling produces an output file, a common technique would be to compare the modification date of the output file against the modification date of the source file.

You would only need to call the tool when the output file is older than the source file, or if the output file does not exist.

Example:

fn is_input_file_outdated<P1, P2>(input: P1, output: P2) -> io::Result<bool>
where
    P1: AsRef<Path>,
    P2: AsRef<Path>,
{
    let out_meta = fs::metadata(output);
    if let Ok(meta) = out_meta {
        let output_mtime = meta.modified()?;

        // if input file is more recent than our output, we are outdated
        let input_meta = fs::metadata(input)?;
        let input_mtime = input_meta.modified()?;

        Ok(input_mtime > output_mtime)
    } else {
        // output file not found, we are outdated
        Ok(true)
    }
}
Related