|
1 | 1 | //! Runs rustfmt on the repository.
|
2 | 2 |
|
3 | 3 | use crate::builder::Builder;
|
4 |
| -use crate::util::{output, t}; |
| 4 | +use crate::util::{output, program_out_of_date, t}; |
5 | 5 | use ignore::WalkBuilder;
|
6 | 6 | use std::collections::VecDeque;
|
7 | 7 | use std::path::{Path, PathBuf};
|
@@ -44,6 +44,68 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
|
44 | 44 | }
|
45 | 45 | }
|
46 | 46 |
|
| 47 | +fn verify_timestamp(build: &Builder<'_>) -> bool { |
| 48 | + let stamp_file = { |
| 49 | + let mut s = build.out.clone(); |
| 50 | + s.push("rustfmt.stamp"); |
| 51 | + s |
| 52 | + }; |
| 53 | + |
| 54 | + let mut cmd = Command::new(match build.initial_rustfmt() { |
| 55 | + Some(p) => p, |
| 56 | + None => return false, |
| 57 | + }); |
| 58 | + cmd.arg("--version"); |
| 59 | + let output = match cmd.output() { |
| 60 | + Ok(status) => status, |
| 61 | + Err(_) => return false, |
| 62 | + }; |
| 63 | + if !output.status.success() { |
| 64 | + return false; |
| 65 | + } |
| 66 | + let version = String::from_utf8(output.stdout).unwrap(); |
| 67 | + !program_out_of_date(&stamp_file, &version) |
| 68 | +} |
| 69 | + |
| 70 | +fn update_timestamp(build: &Builder<'_>) { |
| 71 | + let stamp_file = { |
| 72 | + let mut s = build.out.clone(); |
| 73 | + s.push("rustfmt.stamp"); |
| 74 | + s |
| 75 | + }; |
| 76 | + |
| 77 | + let mut cmd = Command::new(match build.initial_rustfmt() { |
| 78 | + Some(p) => p, |
| 79 | + None => return, |
| 80 | + }); |
| 81 | + cmd.arg("--version"); |
| 82 | + let output = match cmd.output() { |
| 83 | + Ok(status) => status, |
| 84 | + Err(_) => return, |
| 85 | + }; |
| 86 | + if !output.status.success() { |
| 87 | + return; |
| 88 | + } |
| 89 | + let version = String::from_utf8(output.stdout).unwrap(); |
| 90 | + |
| 91 | + t!(std::fs::write(stamp_file, version)) |
| 92 | +} |
| 93 | + |
| 94 | +fn get_modified_files(build: &Builder<'_>) -> Option<Vec<String>> { |
| 95 | + let Ok(remote) = get_rust_lang_rust_remote() else {return None;}; |
| 96 | + if !verify_timestamp(build) { |
| 97 | + return None; |
| 98 | + } |
| 99 | + let base = |
| 100 | + output(build.config.git().arg("merge-base").arg("HEAD").arg(format!("{remote}/master"))); |
| 101 | + Some( |
| 102 | + output(build.config.git().arg("diff").arg("--name-only").arg(base.trim())) |
| 103 | + .lines() |
| 104 | + .map(|s| s.trim().to_owned()) |
| 105 | + .collect(), |
| 106 | + ) |
| 107 | +} |
| 108 | + |
47 | 109 | /// Finds the remote for rust-lang/rust.
|
48 | 110 | /// For example for these remotes it will return `upstream`.
|
49 | 111 | /// ```text
|
@@ -140,20 +202,11 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
140 | 202 | ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
|
141 | 203 | }
|
142 | 204 | if !check && paths.is_empty() {
|
143 |
| - let remote = t!(get_rust_lang_rust_remote()); |
144 |
| - let base = output( |
145 |
| - build |
146 |
| - .config |
147 |
| - .git() |
148 |
| - .arg("merge-base") |
149 |
| - .arg("HEAD") |
150 |
| - .arg(format!("{remote}/master")), |
151 |
| - ); |
152 |
| - let files = |
153 |
| - output(build.config.git().arg("diff").arg("--name-only").arg(base.trim())); |
154 |
| - for file in files.lines() { |
155 |
| - println!("formatting modified file {file}"); |
156 |
| - ignore_fmt.add(&format!("/{file}")).expect(file); |
| 205 | + if let Some(files) = get_modified_files(build) { |
| 206 | + for file in files { |
| 207 | + println!("formatting modified file {file}"); |
| 208 | + ignore_fmt.add(&format!("/{file}")).expect(&file); |
| 209 | + } |
157 | 210 | }
|
158 | 211 | }
|
159 | 212 | } else {
|
@@ -233,4 +286,6 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
233 | 286 | drop(tx);
|
234 | 287 |
|
235 | 288 | thread.join().unwrap();
|
| 289 | + |
| 290 | + update_timestamp(build); |
236 | 291 | }
|
0 commit comments