diff --git a/check_diff/src/lib.rs b/check_diff/src/lib.rs index 239cab77984..4b975fa1d59 100644 --- a/check_diff/src/lib.rs +++ b/check_diff/src/lib.rs @@ -1,21 +1,125 @@ -use diffy; use std::env; use std::fmt::{Debug, Display}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use std::str::Utf8Error; -use tracing::info; +use std::str::FromStr; +use tracing::{debug, error, info, trace}; use walkdir::WalkDir; +#[derive(Debug, Clone, Copy)] +pub enum Edition { + /// rust edition 2015 + Edition2015, + /// rust edition 2018 + Edition2018, + /// rust edition 2021 + Edition2021, + /// rust edition 2024 + Edition2024, +} + +impl Edition { + fn as_str(&self) -> &str { + match self { + Edition::Edition2015 => "2015", + Edition::Edition2018 => "2018", + Edition::Edition2021 => "2021", + Edition::Edition2024 => "2024", + } + } +} + +impl FromStr for Edition { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(Edition::Edition2015), + "2018" => Ok(Edition::Edition2018), + "2021" => Ok(Edition::Edition2021), + "2024" => Ok(Edition::Edition2024), + _ => Err(format!("Invalid rust language edition {s}")), + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum StyleEdition { + // rustfmt style_edition 2021. Also equivaluent to 2015 and 2018. + Edition2021, + // rustfmt style_edition 2024 + Edition2024, +} + +impl StyleEdition { + fn as_str(&self) -> &str { + match self { + StyleEdition::Edition2021 => "2021", + StyleEdition::Edition2024 => "2024", + } + } +} + +impl FromStr for StyleEdition { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(StyleEdition::Edition2021), + "2018" => Ok(StyleEdition::Edition2021), + "2021" => Ok(StyleEdition::Edition2021), + "2024" => Ok(StyleEdition::Edition2024), + _ => Err(format!("Invalid rustfmt style edition {s}")), + } + } +} + +pub enum FormatCodeError { + // IO Error when running code formatter + Io(std::io::Error), + /// An error occured that prevents code formatting. For example, a parse error. + CodeNotFormatted(Vec), +} + +impl From for FormatCodeError { + fn from(error: std::io::Error) -> Self { + Self::Io(error) + } +} + +impl std::fmt::Debug for FormatCodeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Io(e) => std::fmt::Debug::fmt(e, f), + Self::CodeNotFormatted(e) => { + let data = String::from_utf8_lossy(e); + f.write_str(&data) + } + } + } +} + +pub enum CreateDiffError { + /// Couldn't create a diff because the rustfmt binary compiled from the `main` branch + /// failed to format the input. + MainRustfmtFailed(FormatCodeError), + /// Couldn't create a diff because the rustfmt binary compiled from the `feature` branch + /// failed to format the input. + FeatureRustfmtFailed(FormatCodeError), + /// Couldn't create a diff because both rustfmt binaries failed to format the input + BothRustfmtFailed { + src: FormatCodeError, + feature: FormatCodeError, + }, +} + #[derive(Debug)] pub enum CheckDiffError { /// Git related errors FailedGit(GitError), /// Error for generic commands FailedCommand(&'static str), - /// UTF8 related errors - FailedUtf8(Utf8Error), /// Error for building rustfmt from source FailedSourceBuild(&'static str), /// Error when obtaining binary version @@ -37,12 +141,6 @@ impl From for CheckDiffError { } } -impl From for CheckDiffError { - fn from(error: Utf8Error) -> Self { - CheckDiffError::FailedUtf8(error) - } -} - #[derive(Debug)] pub enum GitError { FailedClone { stdout: Vec, stderr: Vec }, @@ -83,16 +181,27 @@ pub struct CheckDiffRunners { } pub trait CodeFormatter { - fn format_code<'a>( + fn format_code>( + &self, + code: &str, + config: Option<&[T]>, + ) -> Result; + + fn format_code_from_path, P: AsRef>( &self, - code: &'a str, - config: &Option>, - ) -> Result; + path: P, + config: Option<&[T]>, + ) -> Result { + let code = std::fs::read_to_string(path)?; + self.format_code(&code, config) + } } pub struct RustfmtRunner { - ld_library_path: String, + dynamic_library_path: String, binary_path: PathBuf, + edition: Edition, + style_edition: StyleEdition, } impl CheckDiffRunners { @@ -110,25 +219,49 @@ where S: CodeFormatter, { /// Creates a diff generated by running the source and feature binaries on the same file path - pub fn create_diff( + pub fn create_diff, P: AsRef>( &self, - path: &Path, - additional_configs: &Option>, - ) -> Result { - let code = std::fs::read_to_string(path)?; - let src_format = self.src_runner.format_code(&code, additional_configs)?; - let feature_format = self.feature_runner.format_code(&code, additional_configs)?; - Ok(Diff { - src_format, - feature_format, - }) + path: P, + additional_configs: Option<&[T]>, + ) -> Result { + let src_format = self + .src_runner + .format_code_from_path(&path, additional_configs); + let feature_format = self + .feature_runner + .format_code_from_path(&path, additional_configs); + + match (src_format, feature_format) { + (Ok(s), Ok(f)) => Ok(Diff { + src_format: s, + feature_format: f, + }), + (Err(error), Ok(_)) => { + // main formatting failed. + Err(CreateDiffError::MainRustfmtFailed(error)) + } + (Ok(_), Err(error)) => { + // feature formatting failed + Err(CreateDiffError::FeatureRustfmtFailed(error)) + } + (Err(src_error), Err(feature_error)) => { + // Both main formatting and feature formatting failed + Err(CreateDiffError::BothRustfmtFailed { + src: src_error, + feature: feature_error, + }) + } + } } } impl RustfmtRunner { fn get_binary_version(&self) -> Result { let Ok(command) = Command::new(&self.binary_path) - .env("LD_LIBRARY_PATH", &self.ld_library_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) .args(["--version"]) .output() else { @@ -137,27 +270,103 @@ impl RustfmtRunner { )); }; - let binary_version = std::str::from_utf8(&command.stdout)?.trim(); - return Ok(binary_version.to_string()); + Ok(buffer_into_utf8_lossy(command.stdout)) + } +} + +/// Convert a buffer of u8 into a String. +fn buffer_into_utf8_lossy(buffer: Vec) -> String { + let mut s = match String::from_utf8(buffer) { + Ok(s) => s, + Err(e) => String::from_utf8_lossy(e.as_bytes()).to_string(), + }; + s.truncate(s.trim_end().len()); + s +} + +/// Returns the name of the environment variable used to search for dynamic libraries. +/// This is the same logic that cargo uses when setting these environment variables +fn dynamic_library_path_env_var_name() -> &'static str { + if cfg!(windows) { + "PATH" + } else if cfg!(target_os = "macos") { + "DYLD_FALLBACK_LIBRARY_PATH" + } else if cfg!(target_os = "aix") { + "LIBPATH" + } else { + "LD_LIBRARY_PATH" } } impl CodeFormatter for RustfmtRunner { + // When rustfmt knows the file path it's able to skip formatting for files listed in the repo's + // rustfmt.toml `ignore` list. For example, this helps us skip files in r-l/rust that have + // been explicitly skipped because trying to format them causes rustfmt to hang or rustfmt. + // doesn't do a good job at formatting those files. + fn format_code_from_path, P: AsRef>( + &self, + path: P, + config: Option<&[T]>, + ) -> Result { + let config = create_config_arg(config); + let command = Command::new(&self.binary_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) + .args([ + "--edition", + self.edition.as_str(), + "--style-edition", + self.style_edition.as_str(), + "--unstable-features", + "--skip-children", + "--emit=stdout", + config.as_str(), + ]) + .arg(path.as_ref()) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + let output = command.wait_with_output()?; + let formatted_code = buffer_into_utf8_lossy(output.stdout); + + match output.status.code() { + Some(0) => Ok(formatted_code), + Some(_) | None => { + if !formatted_code.is_empty() { + Ok(formatted_code) + } else { + Err(FormatCodeError::CodeNotFormatted(output.stderr)) + } + } + } + } + // Run rusfmt to see if a diff is produced. Runs on the code specified // // Parameters: // code: Code to run the binary on // config: Any additional configuration options to pass to rustfmt // - fn format_code<'a>( + fn format_code>( &self, - code: &'a str, - config: &Option>, - ) -> Result { + code: &str, + config: Option<&[T]>, + ) -> Result { let config = create_config_arg(config); let mut command = Command::new(&self.binary_path) - .env("LD_LIBRARY_PATH", &self.ld_library_path) + .env( + dynamic_library_path_env_var_name(), + &self.dynamic_library_path, + ) .args([ + "--edition", + self.edition.as_str(), + "--style-edition", + self.style_edition.as_str(), "--unstable-features", "--skip-children", "--emit=stdout", @@ -170,19 +379,30 @@ impl CodeFormatter for RustfmtRunner { command.stdin.as_mut().unwrap().write_all(code.as_bytes())?; let output = command.wait_with_output()?; - Ok(std::str::from_utf8(&output.stdout)?.to_string()) + let formatted_code = buffer_into_utf8_lossy(output.stdout); + + match output.status.code() { + Some(0) => Ok(formatted_code), + Some(_) | None => { + if !formatted_code.is_empty() { + Ok(formatted_code) + } else { + Err(FormatCodeError::CodeNotFormatted(output.stderr)) + } + } + } } } /// Creates a configuration in the following form: /// =, =, ... -fn create_config_arg(config: &Option>) -> String { +fn create_config_arg>(config: Option<&[T]>) -> String { let config_arg: String = match config { Some(configs) => { let mut result = String::new(); for arg in configs.iter() { result.push(','); - result.push_str(arg.as_str()); + result.push_str(arg.as_ref()); } result } @@ -222,8 +442,8 @@ pub fn clone_git_repo(url: &str, dest: &Path) -> Result<(), GitError> { return Err(error); } - info!("Successfully clone repository."); - return Ok(()); + info!("Successfully cloned repository {url} to {}", dest.display()); + Ok(()) } pub fn git_remote_add(url: &str) -> Result<(), GitError> { @@ -242,7 +462,7 @@ pub fn git_remote_add(url: &str) -> Result<(), GitError> { } info!("Successfully added remote: {url}"); - return Ok(()); + Ok(()) } pub fn git_fetch(branch_name: &str) -> Result<(), GitError> { @@ -261,7 +481,7 @@ pub fn git_fetch(branch_name: &str) -> Result<(), GitError> { } info!("Successfully fetched: {branch_name}"); - return Ok(()); + Ok(()) } pub fn git_switch(git_ref: &str, should_detach: bool) -> Result<(), GitError> { @@ -279,20 +499,20 @@ pub fn git_switch(git_ref: &str, should_detach: bool) -> Result<(), GitError> { return Err(error); } info!("Successfully switched to {git_ref}"); - return Ok(()); + Ok(()) } pub fn change_directory_to_path(dest: &Path) -> io::Result<()> { let dest_path = Path::new(&dest); - env::set_current_dir(&dest_path)?; + env::set_current_dir(dest_path)?; info!( - "Current directory: {}", + "Setting current directory to: {}", env::current_dir().unwrap().display() ); - return Ok(()); + Ok(()) } -pub fn get_ld_library_path(dir: &Path) -> Result { +pub fn get_dynamic_library_path(dir: &Path) -> Result { let Ok(command) = Command::new("rustc") .current_dir(dir) .args(["--print", "sysroot"]) @@ -300,9 +520,9 @@ pub fn get_ld_library_path(dir: &Path) -> Result { else { return Err(CheckDiffError::FailedCommand("Error getting sysroot")); }; - let sysroot = std::str::from_utf8(&command.stdout)?.trim_end(); - let ld_lib_path = format!("{}/lib", sysroot); - return Ok(ld_lib_path); + let mut sysroot = buffer_into_utf8_lossy(command.stdout); + sysroot.push_str("/lib"); + Ok(sysroot) } pub fn get_cargo_version() -> Result { @@ -312,8 +532,7 @@ pub fn get_cargo_version() -> Result { )); }; - let cargo_version = std::str::from_utf8(&command.stdout)?.trim_end(); - return Ok(cargo_version.to_string()); + Ok(buffer_into_utf8_lossy(command.stdout)) } /// Obtains the ld_lib path and then builds rustfmt from source @@ -321,12 +540,12 @@ pub fn get_cargo_version() -> Result { pub fn build_rustfmt_from_src( binary_path: PathBuf, dir: &Path, + edition: Edition, + style_edition: StyleEdition, ) -> Result { - //Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each - // binary can find it's runtime dependencies. - // See https://github.com/rust-lang/rustfmt/issues/5675 - // This will prepend the `LD_LIBRARY_PATH` for the main rustfmt binary - let ld_lib_path = get_ld_library_path(&dir)?; + // Because we're building standalone binaries we need to set the dynamic library path + // so each rustfmt binary can find it's runtime dependencies. + let dynamic_library_path = get_dynamic_library_path(dir)?; info!("Building rustfmt from source"); let Ok(_) = Command::new("cargo") @@ -341,10 +560,12 @@ pub fn build_rustfmt_from_src( std::fs::copy(dir.join("target/release/rustfmt"), &binary_path)?; - return Ok(RustfmtRunner { - ld_library_path: ld_lib_path, + Ok(RustfmtRunner { + dynamic_library_path, binary_path, - }); + edition, + style_edition, + }) } // Compiles and produces two rustfmt binaries. @@ -355,6 +576,8 @@ pub fn compile_rustfmt( dest: &Path, remote_repo_url: String, feature_branch: String, + edition: Edition, + style_edition: StyleEdition, commit_hash: Option, ) -> Result, CheckDiffError> { const RUSTFMT_REPO: &str = "https://github.com/rust-lang/rustfmt.git"; @@ -366,72 +589,126 @@ pub fn compile_rustfmt( let cargo_version = get_cargo_version()?; info!("Compiling with {}", cargo_version); - let src_runner = build_rustfmt_from_src(dest.join("src_rustfmt"), dest)?; + let src_runner = + build_rustfmt_from_src(dest.join("src_rustfmt"), dest, edition, style_edition)?; let should_detach = commit_hash.is_some(); git_switch( - commit_hash.unwrap_or(feature_branch).as_str(), + commit_hash.as_ref().unwrap_or(&feature_branch), should_detach, )?; - let feature_runner = build_rustfmt_from_src(dest.join("feature_rustfmt"), dest)?; + let feature_runner = + build_rustfmt_from_src(dest.join("feature_rustfmt"), dest, edition, style_edition)?; info!("RUSFMT_BIN {}", src_runner.get_binary_version()?); + let dynamic_library_path_env_var = dynamic_library_path_env_var_name(); info!( - "Runtime dependencies for (src) rustfmt -- LD_LIBRARY_PATH: {}", - src_runner.ld_library_path + "Runtime dependencies for (main) rustfmt -- {}: {}", + dynamic_library_path_env_var, src_runner.dynamic_library_path ); info!("FEATURE_BIN {}", feature_runner.get_binary_version()?); info!( - "Runtime dependencies for (feature) rustfmt -- LD_LIBRARY_PATH: {}", - feature_runner.ld_library_path + "Runtime dependencies for ({}) rustfmt -- {}: {}", + feature_branch, dynamic_library_path_env_var, feature_runner.dynamic_library_path ); - return Ok(CheckDiffRunners { + Ok(CheckDiffRunners { src_runner, feature_runner, - }); + }) } /// Searches for rust files in the particular path and returns an iterator to them. pub fn search_for_rs_files(repo: &Path) -> impl Iterator { - return WalkDir::new(repo).into_iter().filter_map(|e| match e.ok() { + WalkDir::new(repo).into_iter().filter_map(|e| match e.ok() { Some(entry) => { let path = entry.path(); - if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") { + if path.is_file() && path.extension().is_some_and(|ext| ext == "rs") { return Some(entry.into_path()); } - return None; + None } None => None, - }); + }) } /// Calculates the number of errors when running the compiled binary and the feature binary on the /// repo specified with the specific configs. -pub fn check_diff( - config: Option>, - runners: CheckDiffRunners, - repo: &Path, -) -> i32 { - let mut errors = 0; +pub fn check_diff, P: AsRef>( + config: Option<&[T]>, + runners: &CheckDiffRunners, + repo: P, + repo_url: &str, +) -> u8 { + let mut errors: u8 = 0; + let repo = repo.as_ref(); let iter = search_for_rs_files(repo); for file in iter { - match runners.create_diff(file.as_path(), &config) { + let relative_path = file.strip_prefix(repo).unwrap_or(&file); + let repo_name = get_repo_name(repo_url); + + trace!( + "Formatting '{0}' file {0}/{1}", + repo_name, + relative_path.display() + ); + + match runners.create_diff(file.as_path(), config) { Ok(diff) => { if !diff.is_empty() { - eprint!("{diff}"); - errors += 1; + error!( + "Diff found in '{0}' when formatting {0}/{1}\n{2}", + repo_name, + relative_path.display(), + diff, + ); + errors = errors.saturating_add(1); + } else { + trace!( + "No diff found in '{0}' when formatting {0}/{1}", + repo_name, + relative_path.display(), + ) } } - Err(e) => { - eprintln!( - "Error creating diff for {:?}: {:?}", - file.as_path().display(), - e + Err(CreateDiffError::MainRustfmtFailed(e)) => { + debug!( + "`main` rustfmt failed to format {}/{}\n{:?}", + repo_name, + relative_path.display(), + e, + ); + continue; + } + Err(CreateDiffError::FeatureRustfmtFailed(e)) => { + debug!( + "`feature` rustfmt failed to format {}/{}\n{:?}", + repo_name, + relative_path.display(), + e, + ); + continue; + } + Err(CreateDiffError::BothRustfmtFailed { src, feature }) => { + debug!( + "Both rustfmt binaries failed to format {}/{}\n{:?}\n{:?}", + repo_name, + relative_path.display(), + src, + feature, ); - errors += 1; + continue; } } } - return errors; + errors +} + +/// parse out the repository name from a GitHub Repository name. +pub fn get_repo_name(git_url: &str) -> &str { + let strip_git_prefix = git_url.strip_suffix(".git").unwrap_or(git_url); + let (_, repo_name) = strip_git_prefix + .rsplit_once('/') + .unwrap_or(("", strip_git_prefix)); + repo_name } diff --git a/check_diff/src/main.rs b/check_diff/src/main.rs index 9c14c5f08cd..50bda185398 100644 --- a/check_diff/src/main.rs +++ b/check_diff/src/main.rs @@ -1,7 +1,44 @@ -use check_diff::{CheckDiffError, check_diff, compile_rustfmt}; +use std::io::Error; +use std::process::ExitCode; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread; + +use check_diff::{ + Edition, StyleEdition, check_diff, clone_git_repo, compile_rustfmt, get_repo_name, +}; use clap::Parser; -use tempfile::Builder; -use tracing::info; +use tempfile::tempdir; +use tracing::{error, info, warn}; + +/// A curated set of `rust-lang/*` and popular ecosystem repositories to compare `rustfmt`s against. +const REPOS: &[&str] = &[ + // `rust-lang/*` repositories. + "https://github.com/rust-lang/cargo.git", + "https://github.com/rust-lang/futures-rs.git", + "https://github.com/rust-lang/log.git", + "https://github.com/rust-lang/mdBook.git", + "https://github.com/rust-lang/miri.git", + "https://github.com/rust-lang/packed_simd.git", + "https://github.com/rust-lang/rust-analyzer.git", + "https://github.com/rust-lang/rust-bindgen.git", + "https://github.com/rust-lang/rust-semverver.git", + "https://github.com/rust-lang/rust.git", + "https://github.com/rust-lang/rustlings.git", + "https://github.com/rust-lang/rustup.git", + // Ecosystem repositories + "https://github.com/actix/actix.git", + "https://github.com/bitflags/bitflags.git", + "https://github.com/denoland/deno.git", + "https://github.com/dtolnay/anyhow.git", + "https://github.com/dtolnay/syn.git", + "https://github.com/dtolnay/thiserror.git", + "https://github.com/hyperium/hyper.git", + "https://github.com/rustls/rustls.git", + "https://github.com/serde-rs/serde.git", + "https://github.com/SergioBenitez/Rocket.git", + "https://github.com/Stebalien/tempfile.git", +]; /// Inputs for the check_diff script #[derive(Parser)] @@ -10,6 +47,12 @@ struct CliInputs { remote_repo_url: String, /// Name of the feature branch on the forked repo feature_branch: String, + /// Rust language `edition` used to parse code. Possible values {2015, 2018, 2021, 2024} + #[arg(short, long, default_value = "2015")] + edition: Edition, + /// rustfmt `style_edition` used when formatting code. Possible vales {2015, 2018, 2021, 2024}. + #[arg(short, long, default_value = "2021")] + style_edition: StyleEdition, /// Optional commit hash from the feature branch #[arg(short, long)] commit_hash: Option, @@ -19,22 +62,79 @@ struct CliInputs { rustfmt_config: Option>, } -fn main() -> Result<(), CheckDiffError> { +fn main() -> Result { tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_env("CHECK_DIFF_LOG")) .init(); let args = CliInputs::parse(); - let tmp_dir = Builder::new().tempdir_in("").unwrap(); + let tmp_dir = tempdir()?; info!("Created tmp_dir {:?}", tmp_dir); - let check_diff_runners = compile_rustfmt( + + let compilation_result = compile_rustfmt( tmp_dir.path(), args.remote_repo_url, args.feature_branch, + args.edition, + args.style_edition, args.commit_hash, - )?; + ); + + let check_diff_runners = match compilation_result { + Ok(runner) => runner, + Err(e) => { + error!("Failed to compile rustfmt:\n{e:?}"); + return Ok(ExitCode::FAILURE); + } + }; + + let errors = Arc::new(AtomicUsize::new(0)); + let rustfmt_config = Arc::new(args.rustfmt_config); + let check_diff_runners = Arc::new(check_diff_runners); + + thread::scope(|s| { + for url in REPOS { + let errors = Arc::clone(&errors); + let rustfmt_config = Arc::clone(&rustfmt_config); + let check_diff_runners = Arc::clone(&check_diff_runners); + s.spawn(move || { + let repo_name = get_repo_name(url); + info!("Processing repo: {repo_name}"); + let Ok(tmp_dir) = tempdir() else { + warn!( + "Failed to create a tempdir for {}. Can't check formatting diff for {}", + &url, repo_name + ); + return; + }; + + let Ok(_) = clone_git_repo(url, tmp_dir.path()) else { + warn!( + "Failed to clone repo {}. Can't check formatting diff for {}", + &url, repo_name + ); + return; + }; + + let error_count = check_diff( + rustfmt_config.as_deref(), + &check_diff_runners, + tmp_dir.path(), + url, + ); - // TODO: currently using same tmp dir path for sake of compilation - let _ = check_diff(args.rustfmt_config, check_diff_runners, tmp_dir.path()); + errors.fetch_add(error_count as usize, Ordering::Relaxed); + }); + } + }); - Ok(()) + let error_count = Arc::into_inner(errors) + .expect("All other threads are done") + .load(Ordering::Relaxed); + if error_count > 0 { + error!("{error_count} formatting diffs found 💔"); + Ok(ExitCode::FAILURE) + } else { + info!("No diff found 😊"); + Ok(ExitCode::SUCCESS) + } } diff --git a/check_diff/tests/check_diff.rs b/check_diff/tests/check_diff.rs index 17297c13043..ddd39c0dfc8 100644 --- a/check_diff/tests/check_diff.rs +++ b/check_diff/tests/check_diff.rs @@ -1,5 +1,6 @@ use check_diff::{ - CheckDiffError, CheckDiffRunners, CodeFormatter, check_diff, search_for_rs_files, + CheckDiffError, CheckDiffRunners, CodeFormatter, FormatCodeError, check_diff, + search_for_rs_files, }; use std::fs::File; use tempfile::Builder; @@ -7,11 +8,11 @@ use tempfile::Builder; struct DoNothingFormatter; impl CodeFormatter for DoNothingFormatter { - fn format_code<'a>( + fn format_code>( &self, - _code: &'a str, - _config: &Option>, - ) -> Result { + _code: &str, + _config: Option<&[T]>, + ) -> Result { Ok(String::new()) } } @@ -20,11 +21,11 @@ impl CodeFormatter for DoNothingFormatter { struct AddWhiteSpaceFormatter; impl CodeFormatter for AddWhiteSpaceFormatter { - fn format_code<'a>( + fn format_code>( &self, - code: &'a str, - _config: &Option>, - ) -> Result { + code: &str, + _config: Option<&[T]>, + ) -> Result { let result = code.to_string() + " "; Ok(result) } @@ -77,8 +78,9 @@ fn check_diff_test_no_formatting_difference() -> Result<(), CheckDiffError> { let dir = Builder::new().tempdir_in("").unwrap(); let file_path = dir.path().join("test.rs"); let _tmp_file = File::create(file_path)?; + let repo_url = "https://github.com/rust-lang/rustfmt.git"; - let errors = check_diff(None, runners, dir.path()); + let errors = check_diff(None::<&[&str]>, &runners, dir.path(), repo_url); assert_eq!(errors, 0); Ok(()) } @@ -89,8 +91,9 @@ fn check_diff_test_formatting_difference() -> Result<(), CheckDiffError> { let dir = Builder::new().tempdir_in("").unwrap(); let file_path = dir.path().join("test.rs"); let _tmp_file = File::create(file_path)?; + let repo_url = "https://github.com/rust-lang/rustfmt.git"; - let errors = check_diff(None, runners, dir.path()); + let errors = check_diff(None::<&[&str]>, &runners, dir.path(), repo_url); assert_ne!(errors, 0); Ok(()) }