1+ use std:: borrow:: Cow ;
12use std:: env;
23use std:: fmt:: { Debug , Display } ;
34use std:: io:: { self , Write } ;
@@ -181,19 +182,11 @@ pub struct CheckDiffRunners<F, S> {
181182}
182183
183184pub trait CodeFormatter {
184- fn format_code < T : AsRef < str > > (
185- & self ,
186- code : & str ,
187- config : Option < & [ T ] > ,
188- ) -> Result < String , FormatCodeError > ;
189-
190- fn format_code_from_path < T : AsRef < str > , P : AsRef < Path > > (
191- & self ,
192- path : P ,
193- config : Option < & [ T ] > ,
194- ) -> Result < String , FormatCodeError > {
185+ fn format_code ( & self , code : & str ) -> Result < String , FormatCodeError > ;
186+
187+ fn format_code_from_path < P : AsRef < Path > > ( & self , path : P ) -> Result < String , FormatCodeError > {
195188 let code = std:: fs:: read_to_string ( path) ?;
196- self . format_code ( & code, config )
189+ self . format_code ( & code)
197190 }
198191}
199192
@@ -202,6 +195,7 @@ pub struct RustfmtRunner {
202195 binary_path : PathBuf ,
203196 edition : Edition ,
204197 style_edition : StyleEdition ,
198+ config : Cow < ' static , str > ,
205199}
206200
207201impl < F , S > CheckDiffRunners < F , S > {
@@ -219,17 +213,9 @@ where
219213 S : CodeFormatter ,
220214{
221215 /// Creates a diff generated by running the source and feature binaries on the same file path
222- pub fn create_diff < T : AsRef < str > , P : AsRef < Path > > (
223- & self ,
224- path : P ,
225- additional_configs : Option < & [ T ] > ,
226- ) -> Result < Diff , CreateDiffError > {
227- let src_format = self
228- . src_runner
229- . format_code_from_path ( & path, additional_configs) ;
230- let feature_format = self
231- . feature_runner
232- . format_code_from_path ( & path, additional_configs) ;
216+ pub fn create_diff < P : AsRef < Path > > ( & self , path : P ) -> Result < Diff , CreateDiffError > {
217+ let src_format = self . src_runner . format_code_from_path ( & path) ;
218+ let feature_format = self . feature_runner . format_code_from_path ( & path) ;
233219
234220 match ( src_format, feature_format) {
235221 ( Ok ( s) , Ok ( f) ) => Ok ( Diff {
@@ -272,6 +258,10 @@ impl RustfmtRunner {
272258
273259 Ok ( buffer_into_utf8_lossy ( command. stdout ) )
274260 }
261+
262+ fn command_line_configs ( & self ) -> & str {
263+ & self . config
264+ }
275265}
276266
277267/// Convert a buffer of u8 into a String.
@@ -303,12 +293,7 @@ impl CodeFormatter for RustfmtRunner {
303293 // rustfmt.toml `ignore` list. For example, this helps us skip files in r-l/rust that have
304294 // been explicitly skipped because trying to format them causes rustfmt to hang or rustfmt.
305295 // doesn't do a good job at formatting those files.
306- fn format_code_from_path < T : AsRef < str > , P : AsRef < Path > > (
307- & self ,
308- path : P ,
309- config : Option < & [ T ] > ,
310- ) -> Result < String , FormatCodeError > {
311- let config = create_config_arg ( config) ;
296+ fn format_code_from_path < P : AsRef < Path > > ( & self , path : P ) -> Result < String , FormatCodeError > {
312297 let command = Command :: new ( & self . binary_path )
313298 . env (
314299 dynamic_library_path_env_var_name ( ) ,
@@ -322,7 +307,7 @@ impl CodeFormatter for RustfmtRunner {
322307 "--unstable-features" ,
323308 "--skip-children" ,
324309 "--emit=stdout" ,
325- config . as_str ( ) ,
310+ self . command_line_configs ( ) ,
326311 ] )
327312 . arg ( path. as_ref ( ) )
328313 . stdin ( Stdio :: piped ( ) )
@@ -351,12 +336,7 @@ impl CodeFormatter for RustfmtRunner {
351336 // code: Code to run the binary on
352337 // config: Any additional configuration options to pass to rustfmt
353338 //
354- fn format_code < T : AsRef < str > > (
355- & self ,
356- code : & str ,
357- config : Option < & [ T ] > ,
358- ) -> Result < String , FormatCodeError > {
359- let config = create_config_arg ( config) ;
339+ fn format_code ( & self , code : & str ) -> Result < String , FormatCodeError > {
360340 let mut command = Command :: new ( & self . binary_path )
361341 . env (
362342 dynamic_library_path_env_var_name ( ) ,
@@ -370,7 +350,7 @@ impl CodeFormatter for RustfmtRunner {
370350 "--unstable-features" ,
371351 "--skip-children" ,
372352 "--emit=stdout" ,
373- config . as_str ( ) ,
353+ self . command_line_configs ( ) ,
374354 ] )
375355 . stdin ( Stdio :: piped ( ) )
376356 . stdout ( Stdio :: piped ( ) )
@@ -394,25 +374,42 @@ impl CodeFormatter for RustfmtRunner {
394374 }
395375}
396376
377+ const DEFAULT_CONFIG : & str = "--config=error_on_line_overflow=false,error_on_unformatted=false" ;
378+
397379/// Creates a configuration in the following form:
398380/// <config_name>=<config_val>, <config_name>=<config_val>, ...
399- fn create_config_arg < T : AsRef < str > > ( config : Option < & [ T ] > ) -> String {
400- let config_arg: String = match config {
401- Some ( configs) => {
402- let mut result = String :: new ( ) ;
403- for arg in configs. iter ( ) {
404- result. push ( ',' ) ;
405- result. push_str ( arg. as_ref ( ) ) ;
406- }
407- result
408- }
409- None => String :: new ( ) ,
381+ fn create_config_arg < T : AsRef < str > > ( configs : Option < & [ T ] > ) -> Cow < ' static , str > {
382+ let Some ( configs) = configs else {
383+ return Cow :: Borrowed ( DEFAULT_CONFIG ) ;
410384 } ;
411- let config = format ! (
412- "--config=error_on_line_overflow=false,error_on_unformatted=false{}" ,
413- config_arg. as_str( )
414- ) ;
415- config
385+
386+ let mut configs_len = 0 ;
387+ let mut num_configs = 0 ;
388+
389+ // Determine how many non empty configs we've got
390+ for c in configs. iter ( ) . map ( AsRef :: as_ref) {
391+ if c. is_empty ( ) {
392+ continue ;
393+ }
394+
395+ configs_len += c. len ( ) ;
396+ num_configs += 1 ;
397+ }
398+
399+ if num_configs == 0 {
400+ // All configs were empty so return the default.
401+ return Cow :: Borrowed ( DEFAULT_CONFIG ) ;
402+ }
403+
404+ // We need capacity for the default configs len + one ',' per config + total config element len
405+ let mut result = String :: with_capacity ( DEFAULT_CONFIG . len ( ) + num_configs + configs_len) ;
406+
407+ for c in configs. iter ( ) . map ( AsRef :: as_ref) {
408+ result. push ( ',' ) ;
409+ result. push_str ( c) ;
410+ }
411+
412+ Cow :: Owned ( result)
416413}
417414/// Clone a git repository
418415///
@@ -537,11 +534,12 @@ pub fn get_cargo_version() -> Result<String, CheckDiffError> {
537534
538535/// Obtains the ld_lib path and then builds rustfmt from source
539536/// If that operation succeeds, the source is then copied to the output path specified
540- pub fn build_rustfmt_from_src (
537+ pub fn build_rustfmt_from_src < T : AsRef < str > > (
541538 binary_path : PathBuf ,
542539 dir : & Path ,
543540 edition : Edition ,
544541 style_edition : StyleEdition ,
542+ config : Option < & [ T ] > ,
545543) -> Result < RustfmtRunner , CheckDiffError > {
546544 // Because we're building standalone binaries we need to set the dynamic library path
547545 // so each rustfmt binary can find it's runtime dependencies.
@@ -565,20 +563,22 @@ pub fn build_rustfmt_from_src(
565563 binary_path,
566564 edition,
567565 style_edition,
566+ config : create_config_arg ( config) ,
568567 } )
569568}
570569
571570// Compiles and produces two rustfmt binaries.
572571// One for the current main branch, and another for the feature branch
573572// Parameters:
574573// dest: Directory where rustfmt will be cloned
575- pub fn compile_rustfmt (
574+ pub fn compile_rustfmt < T : AsRef < str > > (
576575 dest : & Path ,
577576 remote_repo_url : String ,
578577 feature_branch : String ,
579578 edition : Edition ,
580579 style_edition : StyleEdition ,
581580 commit_hash : Option < String > ,
581+ config : Option < & [ T ] > ,
582582) -> Result < CheckDiffRunners < RustfmtRunner , RustfmtRunner > , CheckDiffError > {
583583 const RUSTFMT_REPO : & str = "https://github.com/rust-lang/rustfmt.git" ;
584584
@@ -589,16 +589,26 @@ pub fn compile_rustfmt(
589589
590590 let cargo_version = get_cargo_version ( ) ?;
591591 info ! ( "Compiling with {}" , cargo_version) ;
592- let src_runner =
593- build_rustfmt_from_src ( dest. join ( "src_rustfmt" ) , dest, edition, style_edition) ?;
592+ let src_runner = build_rustfmt_from_src (
593+ dest. join ( "src_rustfmt" ) ,
594+ dest,
595+ edition,
596+ style_edition,
597+ config,
598+ ) ?;
594599 let should_detach = commit_hash. is_some ( ) ;
595600 git_switch (
596601 commit_hash. as_ref ( ) . unwrap_or ( & feature_branch) ,
597602 should_detach,
598603 ) ?;
599604
600- let feature_runner =
601- build_rustfmt_from_src ( dest. join ( "feature_rustfmt" ) , dest, edition, style_edition) ?;
605+ let feature_runner = build_rustfmt_from_src (
606+ dest. join ( "feature_rustfmt" ) ,
607+ dest,
608+ edition,
609+ style_edition,
610+ config,
611+ ) ?;
602612 info ! ( "RUSFMT_BIN {}" , src_runner. get_binary_version( ) ?) ;
603613 let dynamic_library_path_env_var = dynamic_library_path_env_var_name ( ) ;
604614 info ! (
@@ -633,8 +643,7 @@ pub fn search_for_rs_files(repo: &Path) -> impl Iterator<Item = PathBuf> {
633643
634644/// Calculates the number of errors when running the compiled binary and the feature binary on the
635645/// repo specified with the specific configs.
636- pub fn check_diff < T : AsRef < str > , P : AsRef < Path > > (
637- config : Option < & [ T ] > ,
646+ pub fn check_diff < P : AsRef < Path > > (
638647 runners : & CheckDiffRunners < impl CodeFormatter , impl CodeFormatter > ,
639648 repo : P ,
640649 repo_url : & str ,
@@ -652,7 +661,7 @@ pub fn check_diff<T: AsRef<str>, P: AsRef<Path>>(
652661 relative_path. display( )
653662 ) ;
654663
655- match runners. create_diff ( file. as_path ( ) , config ) {
664+ match runners. create_diff ( file. as_path ( ) ) {
656665 Ok ( diff) => {
657666 if !diff. is_empty ( ) {
658667 error ! (
0 commit comments