Skip to content

Commit 633a6c8

Browse files
Format only modified files
As discussed on rust-lang#105688, this makes x fmt only format modified files
1 parent a1fc711 commit 633a6c8

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

src/bootstrap/format.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,35 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
4444
}
4545
}
4646

47+
/// Finds the remote for rust-lang/rust.
48+
/// For example for these remotes it will return `upstream`.
49+
/// ```text
50+
/// origin https://github.com/Nilstrieb/rust.git (fetch)
51+
/// origin https://github.com/Nilstrieb/rust.git (push)
52+
/// upstream https://github.com/rust-lang/rust (fetch)
53+
/// upstream https://github.com/rust-lang/rust (push)
54+
/// ```
55+
fn get_rust_lang_rust_remote() -> Result<String, String> {
56+
let mut git = Command::new("git");
57+
git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
58+
59+
let output = git.output().map_err(|err| format!("{err:?}"))?;
60+
if !output.status.success() {
61+
return Err("failed to execute git config command".to_owned());
62+
}
63+
64+
let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
65+
66+
let rust_lang_remote = stdout
67+
.lines()
68+
.find(|remote| remote.contains("rust-lang"))
69+
.ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
70+
71+
let remote_name =
72+
rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
73+
Ok(remote_name.into())
74+
}
75+
4776
#[derive(serde::Deserialize)]
4877
struct RustfmtConfig {
4978
ignore: Vec<String>,
@@ -110,6 +139,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
110139
// preventing the latter from being formatted.
111140
ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
112141
}
142+
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);
157+
}
158+
}
113159
} else {
114160
println!("Not in git tree. Skipping git-aware format checks");
115161
}

0 commit comments

Comments
 (0)