From 2098b27a200152f949bf08946c639d632146fb9b Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sun, 27 Jun 2021 16:59:17 +0200 Subject: [PATCH] Added `cargo dev setup vscode-tasks` for simplicity --- clippy_dev/src/main.rs | 14 +++++ clippy_dev/src/setup/git_hook.rs | 6 ++ clippy_dev/src/setup/mod.rs | 21 +++++++ clippy_dev/src/setup/vscode.rs | 104 +++++++++++++++++++++++++++++++ util/etc/vscode-tasks.json | 57 +++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 clippy_dev/src/setup/vscode.rs create mode 100644 util/etc/vscode-tasks.json diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index f5bd08657..17c321d6c 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -43,11 +43,13 @@ fn main() { .expect("this field is mandatory and therefore always valid"), ), ("git-hook", Some(matches)) => setup::git_hook::install_hook(matches.is_present("force-override")), + ("vscode-tasks", Some(matches)) => setup::vscode::install_tasks(matches.is_present("force-override")), _ => {}, }, ("remove", Some(sub_command)) => match sub_command.subcommand() { ("git-hook", Some(_)) => setup::git_hook::remove_hook(), ("intellij", Some(_)) => setup::intellij::remove_rustc_src(), + ("vscode-tasks", Some(_)) => setup::vscode::remove_tasks(), _ => {}, }, ("serve", Some(matches)) => { @@ -180,6 +182,17 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .help("Forces the override of an existing git pre-commit hook") .required(false), ), + ) + .subcommand( + SubCommand::with_name("vscode-tasks") + .about("Add several tasks to vscode for formatting, validation and testing") + .arg( + Arg::with_name("force-override") + .long("force-override") + .short("f") + .help("Forces the override of existing vs code tasks") + .required(false), + ), ), ) .subcommand( @@ -187,6 +200,7 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .about("Support for undoing changes done by the setup command") .setting(AppSettings::ArgRequiredElseHelp) .subcommand(SubCommand::with_name("git-hook").about("Remove any existing pre-commit git hook")) + .subcommand(SubCommand::with_name("vscode-tasks").about("Remove any existing vscode tasks")) .subcommand( SubCommand::with_name("intellij") .about("Removes rustc source paths added via `cargo dev setup intellij`"), diff --git a/clippy_dev/src/setup/git_hook.rs b/clippy_dev/src/setup/git_hook.rs index f27b69a19..3fbb77d59 100644 --- a/clippy_dev/src/setup/git_hook.rs +++ b/clippy_dev/src/setup/git_hook.rs @@ -1,6 +1,8 @@ use std::fs; use std::path::Path; +use super::verify_inside_clippy_dir; + /// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo. /// I've decided against this for the sake of simplicity and to make sure that it doesn't install /// the hook if `clippy_dev` would be used in the rust tree. The hook also references this tool @@ -36,6 +38,10 @@ pub fn install_hook(force_override: bool) { } fn check_precondition(force_override: bool) -> bool { + if !verify_inside_clippy_dir() { + return false; + } + // Make sure that we can find the git repository let git_path = Path::new(REPO_GIT_DIR); if !git_path.exists() || !git_path.is_dir() { diff --git a/clippy_dev/src/setup/mod.rs b/clippy_dev/src/setup/mod.rs index 3834f5a18..a1e4dd103 100644 --- a/clippy_dev/src/setup/mod.rs +++ b/clippy_dev/src/setup/mod.rs @@ -1,2 +1,23 @@ pub mod git_hook; pub mod intellij; +pub mod vscode; + +use std::path::Path; + +const CLIPPY_DEV_DIR: &str = "clippy_dev"; + +/// This function verifies that the tool is being executed in the clippy directory. +/// This is useful to ensure that setups only modify Clippys resources. The verification +/// is done by checking that `clippy_dev` is a sub directory of the current directory. +/// +/// It will print an error message and return `false` if the directory could not be +/// verified. +fn verify_inside_clippy_dir() -> bool { + let path = Path::new(CLIPPY_DEV_DIR); + if path.exists() && path.is_dir() { + true + } else { + eprintln!("error: unable to verify that the working directory is clippys directory"); + false + } +} diff --git a/clippy_dev/src/setup/vscode.rs b/clippy_dev/src/setup/vscode.rs new file mode 100644 index 000000000..d59001b2c --- /dev/null +++ b/clippy_dev/src/setup/vscode.rs @@ -0,0 +1,104 @@ +use std::fs; +use std::path::Path; + +use super::verify_inside_clippy_dir; + +const VSCODE_DIR: &str = ".vscode"; +const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json"; +const TASK_TARGET_FILE: &str = ".vscode/tasks.json"; + +pub fn install_tasks(force_override: bool) { + if !check_install_precondition(force_override) { + return; + } + + match fs::copy(TASK_SOURCE_FILE, TASK_TARGET_FILE) { + Ok(_) => { + println!("info: the task file can be removed with `cargo dev remove vscode-tasks`"); + println!("vscode tasks successfully installed"); + }, + Err(err) => eprintln!( + "error: unable to copy `{}` to `{}` ({})", + TASK_SOURCE_FILE, TASK_TARGET_FILE, err + ), + } +} + +fn check_install_precondition(force_override: bool) -> bool { + if !verify_inside_clippy_dir() { + return false; + } + + let vs_dir_path = Path::new(VSCODE_DIR); + if vs_dir_path.exists() { + // verify the target will be valid + if !vs_dir_path.is_dir() { + eprintln!("error: the `.vscode` path exists but seems to be a file"); + return false; + } + + // make sure that we don't override any existing tasks by accident + let path = Path::new(TASK_TARGET_FILE); + if path.exists() { + if force_override { + return delete_vs_task_file(path); + } + + eprintln!( + "error: there is already a `task.json` file inside the `{}` directory", + VSCODE_DIR + ); + println!("info: use the `--force-override` flag to override the existing `task.json` file"); + return false; + } + } else { + match fs::create_dir(vs_dir_path) { + Ok(_) => { + println!("info: created `{}` directory for clippy", VSCODE_DIR); + }, + Err(err) => { + eprintln!( + "error: the task target directory `{}` could not be created ({})", + VSCODE_DIR, err + ); + }, + } + } + + true +} + +pub fn remove_tasks() { + let path = Path::new(TASK_TARGET_FILE); + if path.exists() { + if delete_vs_task_file(path) { + try_delete_vs_directory_if_empty(); + println!("vscode tasks successfully removed"); + } + } else { + println!("no vscode tasks were found"); + } +} + +fn delete_vs_task_file(path: &Path) -> bool { + if let Err(err) = fs::remove_file(path) { + eprintln!("error: unable to delete the existing `tasks.json` file ({})", err); + return false; + } + + true +} + +/// This function will try to delete the `.vscode` directory if it's empty. +/// It may fail silently. +fn try_delete_vs_directory_if_empty() { + let path = Path::new(VSCODE_DIR); + if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) { + // The directory is empty. We just try to delete it but allow a silence + // fail as an empty `.vscode` directory is still valid + let _silence_result = fs::remove_dir(path); + } else { + // The directory is not empty or could not be read. Either way don't take + // any further actions + } +} diff --git a/util/etc/vscode-tasks.json b/util/etc/vscode-tasks.json new file mode 100644 index 000000000..aee31b5aa --- /dev/null +++ b/util/etc/vscode-tasks.json @@ -0,0 +1,57 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "cargo check", + "type": "shell", + "command": "cargo check", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true, + }, + }, + { + "label": "cargo fmt", + "type": "shell", + "command": "cargo dev fmt", + "problemMatcher": [], + "group": "none", + }, + { + "label": "cargo uitest", + "type": "shell", + "command": "cargo uitest", + "options": { + "env": { + "RUST_BACKTRACE": "1", + // This task will usually execute all UI tests inside `tests/ui` you can + // optionally uncomment the line below and only run a specific test. + // + // See: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md#testing + // + // "TESTNAME": "", + }, + }, + "problemMatcher": [], + "group": { + "kind": "test", + "isDefault": true, + } + }, + { + "label": "cargo test", + "type": "shell", + "command": "cargo test", + "problemMatcher": [], + "group": "test", + }, + { + "label": "cargo dev bless", + "type": "shell", + "command": "cargo dev bless", + "problemMatcher": [], + "group": "none", + }, + ], +}