@@ -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 ) ]
4877struct 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