From ff9014c7cb7565eaecd66198a5804409ef2d8811 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 16 Apr 2024 16:36:38 +0000 Subject: [PATCH] Add `cargo dev setup toolchain` --- clippy_dev/src/main.rs | 55 ++++++++++++++++------- clippy_dev/src/setup/mod.rs | 1 + clippy_dev/src/setup/toolchain.rs | 75 +++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 15 deletions(-) create mode 100644 clippy_dev/src/setup/toolchain.rs diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index 5bd9994e18d5..a9b1b79ec669 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -46,6 +46,13 @@ fn main() { } }, Some(("setup", sub_command)) => match sub_command.subcommand() { + Some(("git-hook", matches)) => { + if matches.get_flag("remove") { + setup::git_hook::remove_hook(); + } else { + setup::git_hook::install_hook(matches.get_flag("force-override")); + } + }, Some(("intellij", matches)) => { if matches.get_flag("remove") { setup::intellij::remove_rustc_src(); @@ -57,12 +64,12 @@ fn main() { ); } }, - Some(("git-hook", matches)) => { - if matches.get_flag("remove") { - setup::git_hook::remove_hook(); - } else { - setup::git_hook::install_hook(matches.get_flag("force-override")); - } + Some(("toolchain", matches)) => { + setup::toolchain::create( + matches.get_flag("force"), + matches.get_flag("release"), + &matches.get_one::("name").unwrap(), + ); }, Some(("vscode-tasks", matches)) => { if matches.get_flag("remove") { @@ -210,6 +217,19 @@ fn get_clap_config() -> ArgMatches { .about("Support for setting up your personal development environment") .arg_required_else_help(true) .subcommands([ + Command::new("git-hook") + .about("Add a pre-commit git hook that formats your code to make it look pretty") + .args([ + Arg::new("remove") + .long("remove") + .action(ArgAction::SetTrue) + .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), + Arg::new("force-override") + .long("force-override") + .short('f') + .action(ArgAction::SetTrue) + .help("Forces the override of an existing git pre-commit hook"), + ]), Command::new("intellij") .about("Alter dependencies so Intellij Rust can find rustc internals") .args([ @@ -225,18 +245,23 @@ fn get_clap_config() -> ArgMatches { .conflicts_with("remove") .required(true), ]), - Command::new("git-hook") - .about("Add a pre-commit git hook that formats your code to make it look pretty") + Command::new("toolchain") + .about("Install a rustup toolchain pointing to the local clippy build") .args([ - Arg::new("remove") - .long("remove") - .action(ArgAction::SetTrue) - .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"), - Arg::new("force-override") - .long("force-override") + Arg::new("force") + .long("force") .short('f') .action(ArgAction::SetTrue) - .help("Forces the override of an existing git pre-commit hook"), + .help("Override an existing toolchain"), + Arg::new("release") + .long("release") + .short('r') + .action(ArgAction::SetTrue) + .help("Point to --release clippy binaries"), + Arg::new("name") + .long("name") + .default_value("clippy") + .help("The name of the created toolchain"), ]), Command::new("vscode-tasks") .about("Add several tasks to vscode for formatting, validation and testing") diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index f691ae4fa45d..b0d318146391 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -1,5 +1,6 @@ pub mod git_hook; pub mod intellij; +pub mod toolchain; pub mod vscode; use std::path::Path; diff --git a/clippy_dev/src/setup/toolchain.rs b/clippy_dev/src/setup/toolchain.rs new file mode 100644 index 000000000000..ebb59f73c934 --- /dev/null +++ b/clippy_dev/src/setup/toolchain.rs @@ -0,0 +1,75 @@ +use std::env::consts::EXE_SUFFIX; +use std::env::current_dir; +use std::ffi::OsStr; +use std::fs; +use std::path::{Path, PathBuf}; +use walkdir::WalkDir; + +use super::verify_inside_clippy_dir; + +pub fn create(force: bool, release: bool, name: &str) { + if !verify_inside_clippy_dir() { + return; + } + + let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); + let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); + + let src = PathBuf::from_iter([&rustup_home, "toolchains", &toolchain]); + let dest = PathBuf::from_iter([&rustup_home, "toolchains", name]); + + if dest.exists() { + if force { + fs::remove_dir_all(&dest).unwrap(); + } else { + println!("{} already exists, pass `--force` to override it", dest.display()); + return; + } + } + + for entry in WalkDir::new(&src) { + let entry = entry.unwrap(); + let relative = entry.path().strip_prefix(&src).unwrap(); + + if relative.starts_with("bin") + && matches!( + relative.file_stem().and_then(OsStr::to_str), + Some("cargo-clippy" | "clippy-driver") + ) + { + continue; + } + + let target = dest.join(relative); + if entry.file_type().is_dir() { + fs::create_dir(&target).unwrap(); + } else { + fs::hard_link(entry.path(), target).unwrap(); + } + } + + symlink_bin("cargo-clippy", &dest, release); + symlink_bin("clippy-driver", &dest, release); + + println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes") +} + +fn symlink_bin(bin: &str, dest: &Path, release: bool) { + #[cfg(windows)] + use std::os::windows::fs::symlink_file as symlink; + + #[cfg(not(windows))] + use std::os::unix::fs::symlink; + + let profile = if release { "release" } else { "debug" }; + let file_name = format!("{bin}{EXE_SUFFIX}"); + + let mut src = current_dir().unwrap(); + src.extend(["target", profile, &file_name]); + + let mut dest = dest.to_path_buf(); + dest.extend(["bin", &file_name]); + + symlink(src, dest).unwrap(); +}