diff options
Diffstat (limited to 'xtask/src/main.rs')
-rw-r--r-- | xtask/src/main.rs | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/xtask/src/main.rs b/xtask/src/main.rs new file mode 100644 index 000000000..623058436 --- /dev/null +++ b/xtask/src/main.rs | |||
@@ -0,0 +1,218 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod help; | ||
4 | |||
5 | use core::fmt::Write; | ||
6 | use core::str; | ||
7 | use pico_args::Arguments; | ||
8 | use std::{env, path::PathBuf}; | ||
9 | use xtask::{ | ||
10 | gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, | ||
11 | Cmd, Overwrite, Result, | ||
12 | }; | ||
13 | |||
14 | struct InstallOpt { | ||
15 | client: Option<ClientOpt>, | ||
16 | server: Option<ServerOpt>, | ||
17 | } | ||
18 | |||
19 | enum ClientOpt { | ||
20 | VsCode, | ||
21 | } | ||
22 | |||
23 | struct ServerOpt { | ||
24 | jemalloc: bool, | ||
25 | } | ||
26 | |||
27 | fn main() -> Result<()> { | ||
28 | let subcommand = match std::env::args_os().nth(1) { | ||
29 | None => { | ||
30 | eprintln!("{}", help::GLOBAL_HELP); | ||
31 | return Ok(()); | ||
32 | } | ||
33 | Some(s) => s, | ||
34 | }; | ||
35 | let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect()); | ||
36 | let subcommand = &*subcommand.to_string_lossy(); | ||
37 | match subcommand { | ||
38 | "install" => { | ||
39 | if matches.contains(["-h", "--help"]) { | ||
40 | eprintln!("{}", help::INSTALL_HELP); | ||
41 | return Ok(()); | ||
42 | } | ||
43 | let server = matches.contains("--server"); | ||
44 | let client_code = matches.contains("--client-code"); | ||
45 | if server && client_code { | ||
46 | eprintln!("{}", help::INSTALL_RA_CONFLICT); | ||
47 | return Ok(()); | ||
48 | } | ||
49 | let jemalloc = matches.contains("--jemalloc"); | ||
50 | matches.finish().or_else(handle_extra_flags)?; | ||
51 | let opts = InstallOpt { | ||
52 | client: if server { None } else { Some(ClientOpt::VsCode) }, | ||
53 | server: if client_code { None } else { Some(ServerOpt { jemalloc: jemalloc }) }, | ||
54 | }; | ||
55 | install(opts)? | ||
56 | } | ||
57 | "gen-tests" => { | ||
58 | if matches.contains(["-h", "--help"]) { | ||
59 | help::print_no_param_subcommand_help(&subcommand); | ||
60 | return Ok(()); | ||
61 | } | ||
62 | gen_tests(Overwrite)? | ||
63 | } | ||
64 | "codegen" => { | ||
65 | if matches.contains(["-h", "--help"]) { | ||
66 | help::print_no_param_subcommand_help(&subcommand); | ||
67 | return Ok(()); | ||
68 | } | ||
69 | generate_boilerplate(Overwrite)? | ||
70 | } | ||
71 | "format" => { | ||
72 | if matches.contains(["-h", "--help"]) { | ||
73 | help::print_no_param_subcommand_help(&subcommand); | ||
74 | return Ok(()); | ||
75 | } | ||
76 | run_rustfmt(Overwrite)? | ||
77 | } | ||
78 | "format-hook" => { | ||
79 | if matches.contains(["-h", "--help"]) { | ||
80 | help::print_no_param_subcommand_help(&subcommand); | ||
81 | return Ok(()); | ||
82 | } | ||
83 | install_format_hook()? | ||
84 | } | ||
85 | "lint" => { | ||
86 | if matches.contains(["-h", "--help"]) { | ||
87 | help::print_no_param_subcommand_help(&subcommand); | ||
88 | return Ok(()); | ||
89 | } | ||
90 | run_clippy()? | ||
91 | } | ||
92 | "fuzz-tests" => { | ||
93 | if matches.contains(["-h", "--help"]) { | ||
94 | help::print_no_param_subcommand_help(&subcommand); | ||
95 | return Ok(()); | ||
96 | } | ||
97 | run_fuzzer()? | ||
98 | } | ||
99 | _ => eprintln!("{}", help::GLOBAL_HELP), | ||
100 | } | ||
101 | Ok(()) | ||
102 | } | ||
103 | |||
104 | fn handle_extra_flags(e: pico_args::Error) -> Result<()> { | ||
105 | if let pico_args::Error::UnusedArgsLeft(flags) = e { | ||
106 | let mut invalid_flags = String::new(); | ||
107 | for flag in flags { | ||
108 | write!(&mut invalid_flags, "{}, ", flag)?; | ||
109 | } | ||
110 | let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); | ||
111 | Err(format!("Invalid flags: {}", invalid_flags).into()) | ||
112 | } else { | ||
113 | Err(e.to_string().into()) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | fn install(opts: InstallOpt) -> Result<()> { | ||
118 | if cfg!(target_os = "macos") { | ||
119 | fix_path_for_mac()? | ||
120 | } | ||
121 | if let Some(server) = opts.server { | ||
122 | install_server(server)?; | ||
123 | } | ||
124 | if let Some(client) = opts.client { | ||
125 | install_client(client)?; | ||
126 | } | ||
127 | Ok(()) | ||
128 | } | ||
129 | |||
130 | fn fix_path_for_mac() -> Result<()> { | ||
131 | let mut vscode_path: Vec<PathBuf> = { | ||
132 | const COMMON_APP_PATH: &str = | ||
133 | r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin"; | ||
134 | const ROOT_DIR: &str = ""; | ||
135 | let home_dir = match env::var("HOME") { | ||
136 | Ok(home) => home, | ||
137 | Err(e) => Err(format!("Failed getting HOME from environment with error: {}.", e))?, | ||
138 | }; | ||
139 | |||
140 | [ROOT_DIR, &home_dir] | ||
141 | .iter() | ||
142 | .map(|dir| String::from(*dir) + COMMON_APP_PATH) | ||
143 | .map(PathBuf::from) | ||
144 | .filter(|path| path.exists()) | ||
145 | .collect() | ||
146 | }; | ||
147 | |||
148 | if !vscode_path.is_empty() { | ||
149 | let vars = match env::var_os("PATH") { | ||
150 | Some(path) => path, | ||
151 | None => Err("Could not get PATH variable from env.")?, | ||
152 | }; | ||
153 | |||
154 | let mut paths = env::split_paths(&vars).collect::<Vec<_>>(); | ||
155 | paths.append(&mut vscode_path); | ||
156 | let new_paths = env::join_paths(paths)?; | ||
157 | env::set_var("PATH", &new_paths); | ||
158 | } | ||
159 | |||
160 | Ok(()) | ||
161 | } | ||
162 | |||
163 | fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | ||
164 | Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm.cmd ci", work_dir: "./editors/code" }.run()?; | ||
165 | Cmd { | ||
166 | unix: r"npm run package", | ||
167 | windows: r"cmd.exe /c npm.cmd run package", | ||
168 | work_dir: "./editors/code", | ||
169 | } | ||
170 | .run()?; | ||
171 | |||
172 | let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| { | ||
173 | Cmd { | ||
174 | unix: &format!("{} --version", bin), | ||
175 | windows: &format!("cmd.exe /c {}.cmd --version", bin), | ||
176 | work_dir: "./editors/code", | ||
177 | } | ||
178 | .run() | ||
179 | .is_ok() | ||
180 | }); | ||
181 | |||
182 | let code_binary = match code_binary { | ||
183 | Some(it) => it, | ||
184 | None => Err("Can't execute `code --version`. Perhaps it is not in $PATH?")?, | ||
185 | }; | ||
186 | |||
187 | Cmd { | ||
188 | unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary), | ||
189 | windows: &format!( | ||
190 | r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force", | ||
191 | code_binary | ||
192 | ), | ||
193 | work_dir: "./editors/code", | ||
194 | } | ||
195 | .run()?; | ||
196 | |||
197 | let output = Cmd { | ||
198 | unix: &format!(r"{} --list-extensions", code_binary), | ||
199 | windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary), | ||
200 | work_dir: ".", | ||
201 | } | ||
202 | .run_with_output()?; | ||
203 | |||
204 | if !str::from_utf8(&output.stdout)?.contains("ra-lsp") { | ||
205 | Err("Could not install the Visual Studio Code extension. \ | ||
206 | Please make sure you have at least NodeJS 10.x installed and try again.")?; | ||
207 | } | ||
208 | |||
209 | Ok(()) | ||
210 | } | ||
211 | |||
212 | fn install_server(opts: ServerOpt) -> Result<()> { | ||
213 | if opts.jemalloc { | ||
214 | run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") | ||
215 | } else { | ||
216 | run("cargo install --path crates/ra_lsp_server --locked --force", ".") | ||
217 | } | ||
218 | } | ||