Skip to content

Commit 18d7dee

Browse files
committed
create rustfmt configs when compiling each rustfmt binary
Before we would allocate a new string for the rustfmt configs every time we invoked rustfmt. This was unnecessary since the configs won't change during the runtime of `check_diff`. Now we'll only create the configs for each binary once. Also, we'll only need to allocate a new string if the user passed a non-empty `--rustfmt-config` option when invoking `check_diff`.
1 parent 0a56037 commit 18d7dee

File tree

3 files changed

+77
-82
lines changed

3 files changed

+77
-82
lines changed

check_diff/src/lib.rs

Lines changed: 71 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::env;
23
use std::fmt::{Debug, Display};
34
use std::io::{self, Write};
@@ -181,19 +182,11 @@ pub struct CheckDiffRunners<F, S> {
181182
}
182183

183184
pub 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

207201
impl<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!(

check_diff/src/main.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn main() -> Result<ExitCode, Error> {
7777
args.edition,
7878
args.style_edition,
7979
args.commit_hash,
80+
args.rustfmt_config.as_deref(),
8081
);
8182

8283
let check_diff_runners = match compilation_result {
@@ -88,13 +89,11 @@ fn main() -> Result<ExitCode, Error> {
8889
};
8990

9091
let errors = Arc::new(AtomicUsize::new(0));
91-
let rustfmt_config = Arc::new(args.rustfmt_config);
9292
let check_diff_runners = Arc::new(check_diff_runners);
9393

9494
thread::scope(|s| {
9595
for url in REPOS {
9696
let errors = Arc::clone(&errors);
97-
let rustfmt_config = Arc::clone(&rustfmt_config);
9897
let check_diff_runners = Arc::clone(&check_diff_runners);
9998
s.spawn(move || {
10099
let repo_name = get_repo_name(url);
@@ -115,12 +114,7 @@ fn main() -> Result<ExitCode, Error> {
115114
return;
116115
};
117116

118-
let error_count = check_diff(
119-
rustfmt_config.as_deref(),
120-
&check_diff_runners,
121-
tmp_dir.path(),
122-
url,
123-
);
117+
let error_count = check_diff(&check_diff_runners, tmp_dir.path(), url);
124118

125119
errors.fetch_add(error_count as usize, Ordering::Relaxed);
126120
});

check_diff/tests/check_diff.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ use tempfile::Builder;
88
struct DoNothingFormatter;
99

1010
impl CodeFormatter for DoNothingFormatter {
11-
fn format_code<T: AsRef<str>>(
12-
&self,
13-
_code: &str,
14-
_config: Option<&[T]>,
15-
) -> Result<String, FormatCodeError> {
11+
fn format_code(&self, _code: &str) -> Result<String, FormatCodeError> {
1612
Ok(String::new())
1713
}
1814
}
@@ -21,11 +17,7 @@ impl CodeFormatter for DoNothingFormatter {
2117
struct AddWhiteSpaceFormatter;
2218

2319
impl CodeFormatter for AddWhiteSpaceFormatter {
24-
fn format_code<T: AsRef<str>>(
25-
&self,
26-
code: &str,
27-
_config: Option<&[T]>,
28-
) -> Result<String, FormatCodeError> {
20+
fn format_code(&self, code: &str) -> Result<String, FormatCodeError> {
2921
let result = code.to_string() + " ";
3022
Ok(result)
3123
}
@@ -80,7 +72,7 @@ fn check_diff_test_no_formatting_difference() -> Result<(), CheckDiffError> {
8072
let _tmp_file = File::create(file_path)?;
8173
let repo_url = "https://github.com/rust-lang/rustfmt.git";
8274

83-
let errors = check_diff(None::<&[&str]>, &runners, dir.path(), repo_url);
75+
let errors = check_diff(&runners, dir.path(), repo_url);
8476
assert_eq!(errors, 0);
8577
Ok(())
8678
}
@@ -93,7 +85,7 @@ fn check_diff_test_formatting_difference() -> Result<(), CheckDiffError> {
9385
let _tmp_file = File::create(file_path)?;
9486
let repo_url = "https://github.com/rust-lang/rustfmt.git";
9587

96-
let errors = check_diff(None::<&[&str]>, &runners, dir.path(), repo_url);
88+
let errors = check_diff(&runners, dir.path(), repo_url);
9789
assert_ne!(errors, 0);
9890
Ok(())
9991
}

0 commit comments

Comments
 (0)