blob: 60aee6ee2cb2a5b6bfa781a9a9a2b6f109e45a4b [file] [log] [blame]
use std::io::Error;
use std::process::ExitCode;
use check_diff::{
Edition, StyleEdition, check_diff, clone_repositories_for_diff_check, compile_rustfmt,
};
use clap::Parser;
use tempfile::tempdir;
use tracing::{error, info};
/// 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-clippy.git",
"https://github.com/rust-lang/rust-semverver.git",
"https://github.com/rust-lang/rustfmt.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)]
struct CliInputs {
/// Git url of a rustfmt fork to compare against the latest main rustfmt
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<String>,
/// Optional comma separated list of rustfmt config options to
/// pass when running the feature branch
#[arg(value_delimiter = ',', short, long, num_args = 1..)]
rustfmt_config: Option<Vec<String>>,
/// How many threads should check for formatting diffs.
// Choosing 16 as the default since that's a common multiple of available CPU cores.
#[arg(short, long, default_value_t = std::num::NonZeroU8::new(16).unwrap())]
worker_threads: std::num::NonZeroU8,
}
fn main() -> Result<ExitCode, Error> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_env("CHECK_DIFF_LOG"))
.init();
let args = CliInputs::parse();
let tmp_dir = tempdir()?;
info!("Created tmp_dir {:?}", tmp_dir);
let compilation_result = compile_rustfmt(
tmp_dir.path(),
args.remote_repo_url,
args.feature_branch,
args.edition,
args.style_edition,
args.commit_hash,
args.rustfmt_config.as_deref(),
);
let check_diff_runners = match compilation_result {
Ok(runner) => runner,
Err(e) => {
error!("Failed to compile rustfmt:\n{e:?}");
return Ok(ExitCode::FAILURE);
}
};
// Clone all repositories we plan to check
let repositories = clone_repositories_for_diff_check(REPOS);
info!("Starting the Diff Check");
let errors = check_diff(&check_diff_runners, &repositories, args.worker_threads);
if errors.is_empty() {
info!("No diff found 😊");
return Ok(ExitCode::SUCCESS);
}
for (diff, file, repo) in errors.iter() {
let repo_name = repo.name();
let relative_path = repo.relative_path(&file);
error!(
"Diff found in '{0}' when formatting {0}/{1}\n{2}",
repo_name,
relative_path.display(),
diff,
);
}
error!("{} formatting diffs found 💔", errors.len());
Ok(ExitCode::FAILURE)
}