//! Runs rustfmt on the repository.
use crate::builder::Builder;
-use crate::util::{output, program_out_of_date, t};
+use crate::util::{output, output_result, program_out_of_date, t};
+use build_helper::git::updated_master_branch;
use ignore::WalkBuilder;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
t!(std::fs::write(stamp_file, version))
}
-/// Returns the files modified between the `merge-base` of HEAD and
+/// 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_files(build: &Builder<'_>) -> Option<Vec<String>> {
- let Ok(remote) = get_rust_lang_rust_remote() else {return None;};
+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 None;
+ return Ok(None);
}
- Some(
- output(
- build
- .config
- .git()
- .arg("diff-index")
- .arg("--name-only")
- .arg("--merge-base")
- .arg(&format!("{remote}/master")),
- )
+
+ 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(),
- )
-}
-
-/// Finds the remote for rust-lang/rust.
-/// For example for these remotes it will return `upstream`.
-/// ```text
-/// origin https://github.com/Nilstrieb/rust.git (fetch)
-/// origin https://github.com/Nilstrieb/rust.git (push)
-/// upstream https://github.com/rust-lang/rust (fetch)
-/// upstream https://github.com/rust-lang/rust (push)
-/// ```
-fn get_rust_lang_rust_remote() -> Result<String, String> {
- let mut git = Command::new("git");
- git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
-
- let output = git.output().map_err(|err| format!("{err:?}"))?;
- if !output.status.success() {
- return Err("failed to execute git config command".to_owned());
- }
-
- let stdout = String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?;
-
- let rust_lang_remote = stdout
- .lines()
- .find(|remote| remote.contains("rust-lang"))
- .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
-
- let remote_name =
- rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
- Ok(remote_name.into())
+ ))
}
#[derive(serde::Deserialize)]
Ok(status) => status.success(),
Err(_) => false,
};
+
+ let mut paths = paths.to_vec();
+
if git_available {
let in_working_tree = match build
.config
ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
}
if !check && paths.is_empty() {
- if let Some(files) = get_modified_files(build) {
- for file in files {
- println!("formatting modified file {file}");
- ignore_fmt.add(&format!("/{file}")).expect(&file);
+ match get_modified_rs_files(build) {
+ Ok(Some(files)) => {
+ for file in files {
+ println!("formatting modified file {file}");
+ ignore_fmt.add(&format!("/{file}")).expect(&file);
+ }
+ }
+ Ok(None) => {}
+ Err(err) => {
+ println!(
+ "WARN: Something went wrong when running git commands:\n{err}\n\
+ Falling back to formatting all files."
+ );
+ // Something went wrong when getting the version. Just format all the files.
+ paths.push(".".into());
}
}
}
} else {
println!("Could not find usable git. Skipping git-aware format checks");
}
+
let ignore_fmt = ignore_fmt.build().unwrap();
let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {