Skip to content

Commit f4bc9cf

Browse files
committed
Auto merge of #7409 - xFrednet:5394-vs-code-tasks, r=giraffate,flip1995
Added `cargo dev setup vscode-tasks` for simplicity This PR adds a setup command to `clippy dev` that installs tasks into the Clippy vscode workspace. These might be useful as they be used via shortcuts and are accessible over the GUI. The available tasks are: * `cargo check` (standard Linux shortcut `[ctrl] + [shift] + b`) * `cargo dev fmt` * `cargo uitest` (with a comment how to add the `TESTNAME` environment value) * `cargo test` * `cargo dev bless` --- changelog: none only internal changes again. cc #5394 r? `@flip1995` This should be pretty much the same as the other `cargo dev setup` commands. Would you mind reviewing this? 🙃
2 parents e405c68 + e400191 commit f4bc9cf

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

clippy_dev/src/main.rs

+14
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ fn main() {
4343
.expect("this field is mandatory and therefore always valid"),
4444
),
4545
("git-hook", Some(matches)) => setup::git_hook::install_hook(matches.is_present("force-override")),
46+
("vscode-tasks", Some(matches)) => setup::vscode::install_tasks(matches.is_present("force-override")),
4647
_ => {},
4748
},
4849
("remove", Some(sub_command)) => match sub_command.subcommand() {
4950
("git-hook", Some(_)) => setup::git_hook::remove_hook(),
5051
("intellij", Some(_)) => setup::intellij::remove_rustc_src(),
52+
("vscode-tasks", Some(_)) => setup::vscode::remove_tasks(),
5153
_ => {},
5254
},
5355
("serve", Some(matches)) => {
@@ -181,13 +183,25 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
181183
.help("Forces the override of an existing git pre-commit hook")
182184
.required(false),
183185
),
186+
)
187+
.subcommand(
188+
SubCommand::with_name("vscode-tasks")
189+
.about("Add several tasks to vscode for formatting, validation and testing")
190+
.arg(
191+
Arg::with_name("force-override")
192+
.long("force-override")
193+
.short("f")
194+
.help("Forces the override of existing vscode tasks")
195+
.required(false),
196+
),
184197
),
185198
)
186199
.subcommand(
187200
SubCommand::with_name("remove")
188201
.about("Support for undoing changes done by the setup command")
189202
.setting(AppSettings::ArgRequiredElseHelp)
190203
.subcommand(SubCommand::with_name("git-hook").about("Remove any existing pre-commit git hook"))
204+
.subcommand(SubCommand::with_name("vscode-tasks").about("Remove any existing vscode tasks"))
191205
.subcommand(
192206
SubCommand::with_name("intellij")
193207
.about("Removes rustc source paths added via `cargo dev setup intellij`"),

clippy_dev/src/setup/git_hook.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::fs;
22
use std::path::Path;
33

4+
use super::verify_inside_clippy_dir;
5+
46
/// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo.
57
/// I've decided against this for the sake of simplicity and to make sure that it doesn't install
68
/// 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) {
3638
}
3739

3840
fn check_precondition(force_override: bool) -> bool {
41+
if !verify_inside_clippy_dir() {
42+
return false;
43+
}
44+
3945
// Make sure that we can find the git repository
4046
let git_path = Path::new(REPO_GIT_DIR);
4147
if !git_path.exists() || !git_path.is_dir() {

clippy_dev/src/setup/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
11
pub mod git_hook;
22
pub mod intellij;
3+
pub mod vscode;
4+
5+
use std::path::Path;
6+
7+
const CLIPPY_DEV_DIR: &str = "clippy_dev";
8+
9+
/// This function verifies that the tool is being executed in the clippy directory.
10+
/// This is useful to ensure that setups only modify Clippys resources. The verification
11+
/// is done by checking that `clippy_dev` is a sub directory of the current directory.
12+
///
13+
/// It will print an error message and return `false` if the directory could not be
14+
/// verified.
15+
fn verify_inside_clippy_dir() -> bool {
16+
let path = Path::new(CLIPPY_DEV_DIR);
17+
if path.exists() && path.is_dir() {
18+
true
19+
} else {
20+
eprintln!("error: unable to verify that the working directory is clippys directory");
21+
false
22+
}
23+
}

clippy_dev/src/setup/vscode.rs

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
use std::fs;
2+
use std::path::Path;
3+
4+
use super::verify_inside_clippy_dir;
5+
6+
const VSCODE_DIR: &str = ".vscode";
7+
const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json";
8+
const TASK_TARGET_FILE: &str = ".vscode/tasks.json";
9+
10+
pub fn install_tasks(force_override: bool) {
11+
if !check_install_precondition(force_override) {
12+
return;
13+
}
14+
15+
match fs::copy(TASK_SOURCE_FILE, TASK_TARGET_FILE) {
16+
Ok(_) => {
17+
println!("info: the task file can be removed with `cargo dev remove vscode-tasks`");
18+
println!("vscode tasks successfully installed");
19+
},
20+
Err(err) => eprintln!(
21+
"error: unable to copy `{}` to `{}` ({})",
22+
TASK_SOURCE_FILE, TASK_TARGET_FILE, err
23+
),
24+
}
25+
}
26+
27+
fn check_install_precondition(force_override: bool) -> bool {
28+
if !verify_inside_clippy_dir() {
29+
return false;
30+
}
31+
32+
let vs_dir_path = Path::new(VSCODE_DIR);
33+
if vs_dir_path.exists() {
34+
// verify the target will be valid
35+
if !vs_dir_path.is_dir() {
36+
eprintln!("error: the `.vscode` path exists but seems to be a file");
37+
return false;
38+
}
39+
40+
// make sure that we don't override any existing tasks by accident
41+
let path = Path::new(TASK_TARGET_FILE);
42+
if path.exists() {
43+
if force_override {
44+
return delete_vs_task_file(path);
45+
}
46+
47+
eprintln!(
48+
"error: there is already a `task.json` file inside the `{}` directory",
49+
VSCODE_DIR
50+
);
51+
println!("info: use the `--force-override` flag to override the existing `task.json` file");
52+
return false;
53+
}
54+
} else {
55+
match fs::create_dir(vs_dir_path) {
56+
Ok(_) => {
57+
println!("info: created `{}` directory for clippy", VSCODE_DIR);
58+
},
59+
Err(err) => {
60+
eprintln!(
61+
"error: the task target directory `{}` could not be created ({})",
62+
VSCODE_DIR, err
63+
);
64+
},
65+
}
66+
}
67+
68+
true
69+
}
70+
71+
pub fn remove_tasks() {
72+
let path = Path::new(TASK_TARGET_FILE);
73+
if path.exists() {
74+
if delete_vs_task_file(path) {
75+
try_delete_vs_directory_if_empty();
76+
println!("vscode tasks successfully removed");
77+
}
78+
} else {
79+
println!("no vscode tasks were found");
80+
}
81+
}
82+
83+
fn delete_vs_task_file(path: &Path) -> bool {
84+
if let Err(err) = fs::remove_file(path) {
85+
eprintln!("error: unable to delete the existing `tasks.json` file ({})", err);
86+
return false;
87+
}
88+
89+
true
90+
}
91+
92+
/// This function will try to delete the `.vscode` directory if it's empty.
93+
/// It may fail silently.
94+
fn try_delete_vs_directory_if_empty() {
95+
let path = Path::new(VSCODE_DIR);
96+
if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) {
97+
// The directory is empty. We just try to delete it but allow a silence
98+
// fail as an empty `.vscode` directory is still valid
99+
let _silence_result = fs::remove_dir(path);
100+
} else {
101+
// The directory is not empty or could not be read. Either way don't take
102+
// any further actions
103+
}
104+
}

util/etc/vscode-tasks.json

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "cargo check",
6+
"type": "shell",
7+
"command": "cargo check",
8+
"problemMatcher": [],
9+
"group": {
10+
"kind": "build",
11+
"isDefault": true,
12+
},
13+
},
14+
{
15+
"label": "cargo dev fmt",
16+
"type": "shell",
17+
"command": "cargo dev fmt",
18+
"problemMatcher": [],
19+
"group": "none",
20+
},
21+
{
22+
"label": "cargo uitest",
23+
"type": "shell",
24+
"command": "cargo uitest",
25+
"options": {
26+
"env": {
27+
"RUST_BACKTRACE": "1",
28+
// This task will usually execute all UI tests inside `tests/ui` you can
29+
// optionally uncomment the line below and only run a specific test.
30+
//
31+
// See: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md#testing
32+
//
33+
// "TESTNAME": "<TODO>",
34+
},
35+
},
36+
"problemMatcher": [],
37+
"group": {
38+
"kind": "test",
39+
"isDefault": true,
40+
}
41+
},
42+
{
43+
"label": "cargo test",
44+
"type": "shell",
45+
"command": "cargo test",
46+
"problemMatcher": [],
47+
"group": "test",
48+
},
49+
{
50+
"label": "cargo dev bless",
51+
"type": "shell",
52+
"command": "cargo dev bless",
53+
"problemMatcher": [],
54+
"group": "none",
55+
},
56+
],
57+
}

0 commit comments

Comments
 (0)