+fn get_rustfmt_version(build: &Builder<'_>) -> Option<(String, PathBuf)> {
+ let stamp_file = build.out.join("rustfmt.stamp");
+
+ let mut cmd = Command::new(match build.initial_rustfmt() {
+ Some(p) => p,
+ None => return None,
+ });
+ cmd.arg("--version");
+ let output = match cmd.output() {
+ Ok(status) => status,
+ Err(_) => return None,
+ };
+ if !output.status.success() {
+ return None;
+ }
+ Some((String::from_utf8(output.stdout).unwrap(), stamp_file))
+}
+
+/// Return whether the format cache can be reused.
+fn verify_rustfmt_version(build: &Builder<'_>) -> bool {
+ let Some((version, stamp_file)) = get_rustfmt_version(build) else {return false;};
+ !program_out_of_date(&stamp_file, &version)
+}
+
+/// Updates the last rustfmt version used
+fn update_rustfmt_version(build: &Builder<'_>) {
+ let Some((version, stamp_file)) = get_rustfmt_version(build) else {return;};
+ t!(std::fs::write(stamp_file, version))
+}
+
+/// Returns the Rust files modified between the `merge-base` of HEAD and
+/// rust-lang/master and what is now on the disk.
+///
+/// Returns `None` if all files should be formatted.
+fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
+ let Ok(updated_master) = updated_master_branch(Some(&build.config.src)) else { return Ok(None); };
+
+ if !verify_rustfmt_version(build) {
+ return Ok(None);
+ }
+
+ let merge_base =
+ output_result(build.config.git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
+ Ok(Some(
+ output_result(
+ build.config.git().arg("diff-index").arg("--name-only").arg(merge_base.trim()),
+ )?
+ .lines()
+ .map(|s| s.trim().to_owned())
+ .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs"))
+ .collect(),
+ ))
+}
+