Skip to content

Added cargo dev setup vscode-tasks for simplicity #7409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clippy_dev/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) => {
Expand Down Expand Up @@ -180,13 +182,25 @@ 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 vscode tasks")
.required(false),
),
),
)
.subcommand(
SubCommand::with_name("remove")
.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`"),
Expand Down
6 changes: 6 additions & 0 deletions clippy_dev/src/setup/git_hook.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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() {
Expand Down
21 changes: 21 additions & 0 deletions clippy_dev/src/setup/mod.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
104 changes: 104 additions & 0 deletions clippy_dev/src/setup/vscode.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
57 changes: 57 additions & 0 deletions util/etc/vscode-tasks.json
Original file line number Diff line number Diff line change
@@ -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 dev 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": "<TODO>",
},
},
"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",
},
],
}