@@ -44,6 +44,35 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
44
44
}
45
45
}
46
46
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
+
47
76
#[ derive( serde:: Deserialize ) ]
48
77
struct RustfmtConfig {
49
78
ignore : Vec < String > ,
@@ -110,6 +139,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
110
139
// preventing the latter from being formatted.
111
140
ignore_fmt. add ( & format ! ( "!/{}" , untracked_path) ) . expect ( & untracked_path) ;
112
141
}
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
+ }
113
159
} else {
114
160
println ! ( "Not in git tree. Skipping git-aware format checks" ) ;
115
161
}
0 commit comments