about summary refs log tree commit diff
path: root/clippy_dev/src/setup/vscode.rs
blob: d59001b2c66afc49b6cfc7c8fa230f2bc7b50446 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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
    }
}