diff options
-rw-r--r-- | xtask/src/help.rs | 33 | ||||
-rw-r--r-- | xtask/src/install.rs | 178 | ||||
-rw-r--r-- | xtask/src/lib.rs | 41 | ||||
-rw-r--r-- | xtask/src/main.rs | 283 | ||||
-rw-r--r-- | xtask/src/pre_commit.rs | 36 |
5 files changed, 290 insertions, 281 deletions
diff --git a/xtask/src/help.rs b/xtask/src/help.rs deleted file mode 100644 index 9c78ba37f..000000000 --- a/xtask/src/help.rs +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | pub const GLOBAL_HELP: &str = "tasks | ||
4 | |||
5 | USAGE: | ||
6 | ra_tools <SUBCOMMAND> | ||
7 | |||
8 | FLAGS: | ||
9 | -h, --help Prints help information | ||
10 | |||
11 | SUBCOMMANDS: | ||
12 | format | ||
13 | install-pre-commit-hook | ||
14 | fuzz-tests | ||
15 | codegen | ||
16 | install | ||
17 | lint"; | ||
18 | |||
19 | pub const INSTALL_HELP: &str = "ra_tools-install | ||
20 | |||
21 | USAGE: | ||
22 | ra_tools.exe install [FLAGS] | ||
23 | |||
24 | FLAGS: | ||
25 | --client-code | ||
26 | -h, --help Prints help information | ||
27 | --jemalloc | ||
28 | --server"; | ||
29 | |||
30 | pub const INSTALL_RA_CONFLICT: &str = | ||
31 | "error: The argument `--server` cannot be used with `--client-code` | ||
32 | |||
33 | For more information try --help"; | ||
diff --git a/xtask/src/install.rs b/xtask/src/install.rs new file mode 100644 index 000000000..ab6ed92f7 --- /dev/null +++ b/xtask/src/install.rs | |||
@@ -0,0 +1,178 @@ | |||
1 | //! Installs rust-analyzer langauge server and/or editor plugin. | ||
2 | |||
3 | use std::{env, path::PathBuf, str}; | ||
4 | |||
5 | use anyhow::{Context, Result}; | ||
6 | |||
7 | use crate::{run, run_with_output, Cmd}; | ||
8 | |||
9 | // Latest stable, feel free to send a PR if this lags behind. | ||
10 | const REQUIRED_RUST_VERSION: u32 = 40; | ||
11 | |||
12 | pub struct InstallCmd { | ||
13 | pub client: Option<ClientOpt>, | ||
14 | pub server: Option<ServerOpt>, | ||
15 | } | ||
16 | |||
17 | pub enum ClientOpt { | ||
18 | VsCode, | ||
19 | } | ||
20 | |||
21 | pub struct ServerOpt { | ||
22 | pub jemalloc: bool, | ||
23 | } | ||
24 | |||
25 | impl InstallCmd { | ||
26 | pub fn run(self) -> Result<()> { | ||
27 | if cfg!(target_os = "macos") { | ||
28 | fix_path_for_mac().context("Fix path for mac")? | ||
29 | } | ||
30 | if let Some(server) = self.server { | ||
31 | install_server(server).context("install server")?; | ||
32 | } | ||
33 | if let Some(client) = self.client { | ||
34 | install_client(client).context("install client")?; | ||
35 | } | ||
36 | Ok(()) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | fn fix_path_for_mac() -> Result<()> { | ||
41 | let mut vscode_path: Vec<PathBuf> = { | ||
42 | const COMMON_APP_PATH: &str = | ||
43 | r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin"; | ||
44 | const ROOT_DIR: &str = ""; | ||
45 | let home_dir = match env::var("HOME") { | ||
46 | Ok(home) => home, | ||
47 | Err(e) => anyhow::bail!("Failed getting HOME from environment with error: {}.", e), | ||
48 | }; | ||
49 | |||
50 | [ROOT_DIR, &home_dir] | ||
51 | .iter() | ||
52 | .map(|dir| String::from(*dir) + COMMON_APP_PATH) | ||
53 | .map(PathBuf::from) | ||
54 | .filter(|path| path.exists()) | ||
55 | .collect() | ||
56 | }; | ||
57 | |||
58 | if !vscode_path.is_empty() { | ||
59 | let vars = match env::var_os("PATH") { | ||
60 | Some(path) => path, | ||
61 | None => anyhow::bail!("Could not get PATH variable from env."), | ||
62 | }; | ||
63 | |||
64 | let mut paths = env::split_paths(&vars).collect::<Vec<_>>(); | ||
65 | paths.append(&mut vscode_path); | ||
66 | let new_paths = env::join_paths(paths).context("build env PATH")?; | ||
67 | env::set_var("PATH", &new_paths); | ||
68 | } | ||
69 | |||
70 | Ok(()) | ||
71 | } | ||
72 | |||
73 | fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | ||
74 | let npm_version = Cmd { | ||
75 | unix: r"npm --version", | ||
76 | windows: r"cmd.exe /c npm --version", | ||
77 | work_dir: "./editors/code", | ||
78 | } | ||
79 | .run(); | ||
80 | |||
81 | if npm_version.is_err() { | ||
82 | eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin") | ||
83 | } | ||
84 | |||
85 | Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" } | ||
86 | .run()?; | ||
87 | Cmd { | ||
88 | unix: r"npm run package --scripts-prepend-node-path", | ||
89 | windows: r"cmd.exe /c npm run package", | ||
90 | work_dir: "./editors/code", | ||
91 | } | ||
92 | .run()?; | ||
93 | |||
94 | let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| { | ||
95 | Cmd { | ||
96 | unix: &format!("{} --version", bin), | ||
97 | windows: &format!("cmd.exe /c {}.cmd --version", bin), | ||
98 | work_dir: "./editors/code", | ||
99 | } | ||
100 | .run() | ||
101 | .is_ok() | ||
102 | }); | ||
103 | |||
104 | let code_binary = match code_binary { | ||
105 | Some(it) => it, | ||
106 | None => anyhow::bail!("Can't execute `code --version`. Perhaps it is not in $PATH?"), | ||
107 | }; | ||
108 | |||
109 | Cmd { | ||
110 | unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary), | ||
111 | windows: &format!( | ||
112 | r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force", | ||
113 | code_binary | ||
114 | ), | ||
115 | work_dir: "./editors/code", | ||
116 | } | ||
117 | .run()?; | ||
118 | |||
119 | let output = Cmd { | ||
120 | unix: &format!(r"{} --list-extensions", code_binary), | ||
121 | windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary), | ||
122 | work_dir: ".", | ||
123 | } | ||
124 | .run_with_output()?; | ||
125 | |||
126 | if !str::from_utf8(&output.stdout)?.contains("ra-lsp") { | ||
127 | anyhow::bail!( | ||
128 | "Could not install the Visual Studio Code extension. \ | ||
129 | Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again." | ||
130 | ); | ||
131 | } | ||
132 | |||
133 | Ok(()) | ||
134 | } | ||
135 | |||
136 | fn install_server(opts: ServerOpt) -> Result<()> { | ||
137 | let mut old_rust = false; | ||
138 | if let Ok(output) = run_with_output("cargo --version", ".") { | ||
139 | if let Ok(stdout) = String::from_utf8(output.stdout) { | ||
140 | println!("{}", stdout); | ||
141 | if !check_version(&stdout, REQUIRED_RUST_VERSION) { | ||
142 | old_rust = true; | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | if old_rust { | ||
148 | eprintln!( | ||
149 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", | ||
150 | REQUIRED_RUST_VERSION, | ||
151 | ) | ||
152 | } | ||
153 | |||
154 | let res = if opts.jemalloc { | ||
155 | run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") | ||
156 | } else { | ||
157 | run("cargo install --path crates/ra_lsp_server --locked --force", ".") | ||
158 | }; | ||
159 | |||
160 | if res.is_err() && old_rust { | ||
161 | eprintln!( | ||
162 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", | ||
163 | REQUIRED_RUST_VERSION, | ||
164 | ) | ||
165 | } | ||
166 | |||
167 | res | ||
168 | } | ||
169 | |||
170 | fn check_version(version_output: &str, min_minor_version: u32) -> bool { | ||
171 | // Parse second the number out of | ||
172 | // cargo 1.39.0-beta (1c6ec66d5 2019-09-30) | ||
173 | let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok()); | ||
174 | match minor { | ||
175 | None => true, | ||
176 | Some(minor) => minor >= min_minor_version, | ||
177 | } | ||
178 | } | ||
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 51a868dee..fb853e71a 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -1,13 +1,14 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | pub mod codegen; | 3 | pub mod codegen; |
4 | pub mod install; | ||
5 | pub mod pre_commit; | ||
4 | mod ast_src; | 6 | mod ast_src; |
5 | 7 | ||
6 | use anyhow::Context; | 8 | use anyhow::Context; |
7 | pub use anyhow::Result; | 9 | pub use anyhow::Result; |
8 | use std::{ | 10 | use std::{ |
9 | env, fs, | 11 | env, |
10 | io::{Error as IoError, ErrorKind}, | ||
11 | path::{Path, PathBuf}, | 12 | path::{Path, PathBuf}, |
12 | process::{Command, Output, Stdio}, | 13 | process::{Command, Output, Stdio}, |
13 | }; | 14 | }; |
@@ -79,23 +80,11 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> { | |||
79 | Ok(()) | 80 | Ok(()) |
80 | } | 81 | } |
81 | 82 | ||
82 | pub fn install_rustfmt() -> Result<()> { | 83 | fn install_rustfmt() -> Result<()> { |
83 | run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?; | 84 | run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?; |
84 | run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".") | 85 | run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".") |
85 | } | 86 | } |
86 | 87 | ||
87 | pub fn install_pre_commit_hook() -> Result<()> { | ||
88 | let result_path = | ||
89 | PathBuf::from(format!("./.git/hooks/pre-commit{}", std::env::consts::EXE_SUFFIX)); | ||
90 | if !result_path.exists() { | ||
91 | let me = std::env::current_exe()?; | ||
92 | fs::copy(me, result_path)?; | ||
93 | } else { | ||
94 | Err(IoError::new(ErrorKind::AlreadyExists, "Git hook already created"))?; | ||
95 | } | ||
96 | Ok(()) | ||
97 | } | ||
98 | |||
99 | pub fn run_clippy() -> Result<()> { | 88 | pub fn run_clippy() -> Result<()> { |
100 | match Command::new("rustup") | 89 | match Command::new("rustup") |
101 | .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"]) | 90 | .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"]) |
@@ -144,28 +133,6 @@ pub fn run_fuzzer() -> Result<()> { | |||
144 | run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax") | 133 | run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax") |
145 | } | 134 | } |
146 | 135 | ||
147 | pub fn reformat_staged_files() -> Result<()> { | ||
148 | run_rustfmt(Mode::Overwrite)?; | ||
149 | let root = project_root(); | ||
150 | let output = Command::new("git") | ||
151 | .arg("diff") | ||
152 | .arg("--diff-filter=MAR") | ||
153 | .arg("--name-only") | ||
154 | .arg("--cached") | ||
155 | .current_dir(&root) | ||
156 | .output()?; | ||
157 | if !output.status.success() { | ||
158 | anyhow::bail!( | ||
159 | "`git diff --diff-filter=MAR --name-only --cached` exited with {}", | ||
160 | output.status | ||
161 | ); | ||
162 | } | ||
163 | for line in String::from_utf8(output.stdout)?.lines() { | ||
164 | run(&format!("git update-index --add {}", root.join(line).to_string_lossy()), ".")?; | ||
165 | } | ||
166 | Ok(()) | ||
167 | } | ||
168 | |||
169 | fn do_run<F>(cmdline: &str, dir: &str, mut f: F) -> Result<Output> | 136 | fn do_run<F>(cmdline: &str, dir: &str, mut f: F) -> Result<Output> |
170 | where | 137 | where |
171 | F: FnMut(&mut Command), | 138 | F: FnMut(&mut Command), |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index b42946a4c..9309b2fbd 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
@@ -7,244 +7,105 @@ | |||
7 | //! | 7 | //! |
8 | //! This binary is integrated into the `cargo` command line by using an alias in | 8 | //! This binary is integrated into the `cargo` command line by using an alias in |
9 | //! `.cargo/config`. | 9 | //! `.cargo/config`. |
10 | mod help; | ||
11 | 10 | ||
12 | use std::{env, fmt::Write, path::PathBuf, str}; | 11 | use std::env; |
13 | 12 | ||
14 | use anyhow::Context; | ||
15 | use pico_args::Arguments; | 13 | use pico_args::Arguments; |
16 | use xtask::{ | 14 | use xtask::{ |
17 | codegen::{self, Mode}, | 15 | codegen::{self, Mode}, |
18 | install_pre_commit_hook, reformat_staged_files, run, run_clippy, run_fuzzer, run_rustfmt, | 16 | install::{ClientOpt, InstallCmd, ServerOpt}, |
19 | run_with_output, Cmd, Result, | 17 | pre_commit, run_clippy, run_fuzzer, run_rustfmt, Result, |
20 | }; | 18 | }; |
21 | 19 | ||
22 | // Latest stable, feel free to send a PR if this lags behind. | ||
23 | const REQUIRED_RUST_VERSION: u32 = 40; | ||
24 | |||
25 | struct InstallOpt { | ||
26 | client: Option<ClientOpt>, | ||
27 | server: Option<ServerOpt>, | ||
28 | } | ||
29 | |||
30 | enum ClientOpt { | ||
31 | VsCode, | ||
32 | } | ||
33 | |||
34 | struct ServerOpt { | ||
35 | jemalloc: bool, | ||
36 | } | ||
37 | |||
38 | fn main() -> Result<()> { | 20 | fn main() -> Result<()> { |
39 | if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) { | 21 | if env::args().next().map(|it| it.contains("pre-commit")) == Some(true) { |
40 | return reformat_staged_files(); | 22 | return pre_commit::run_hook(); |
41 | } | 23 | } |
42 | 24 | ||
43 | let subcommand = match std::env::args_os().nth(1) { | 25 | let subcommand = std::env::args().nth(1).unwrap_or_default(); |
44 | None => { | 26 | let mut args = Arguments::from_vec(std::env::args_os().skip(2).collect()); |
45 | eprintln!("{}", help::GLOBAL_HELP); | 27 | |
46 | return Ok(()); | 28 | match subcommand.as_str() { |
47 | } | ||
48 | Some(s) => s, | ||
49 | }; | ||
50 | let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect()); | ||
51 | let subcommand = &*subcommand.to_string_lossy(); | ||
52 | match subcommand { | ||
53 | "install" => { | 29 | "install" => { |
54 | if matches.contains(["-h", "--help"]) { | 30 | if args.contains(["-h", "--help"]) { |
55 | eprintln!("{}", help::INSTALL_HELP); | 31 | eprintln!( |
32 | "\ | ||
33 | cargo xtask install | ||
34 | Install rust-analyzer server or editor plugin. | ||
35 | |||
36 | USAGE: | ||
37 | cargo xtask install [FLAGS] | ||
38 | |||
39 | FLAGS: | ||
40 | --client-code Install only VS Code plugin | ||
41 | --server Install only the language server | ||
42 | --jemalloc Use jemalloc for server | ||
43 | -h, --help Prints help information | ||
44 | " | ||
45 | ); | ||
56 | return Ok(()); | 46 | return Ok(()); |
57 | } | 47 | } |
58 | let server = matches.contains("--server"); | 48 | let server = args.contains("--server"); |
59 | let client_code = matches.contains("--client-code"); | 49 | let client_code = args.contains("--client-code"); |
60 | if server && client_code { | 50 | if server && client_code { |
61 | eprintln!("{}", help::INSTALL_RA_CONFLICT); | 51 | eprintln!( |
52 | "error: The argument `--server` cannot be used with `--client-code`\n\n\ | ||
53 | For more information try --help" | ||
54 | ); | ||
62 | return Ok(()); | 55 | return Ok(()); |
63 | } | 56 | } |
64 | let jemalloc = matches.contains("--jemalloc"); | 57 | |
65 | matches.finish().or_else(handle_extra_flags)?; | 58 | let jemalloc = args.contains("--jemalloc"); |
66 | let opts = InstallOpt { | 59 | |
60 | args.finish()?; | ||
61 | |||
62 | InstallCmd { | ||
67 | client: if server { None } else { Some(ClientOpt::VsCode) }, | 63 | client: if server { None } else { Some(ClientOpt::VsCode) }, |
68 | server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, | 64 | server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, |
69 | }; | 65 | } |
70 | install(opts)? | 66 | .run() |
71 | } | 67 | } |
72 | "codegen" => { | 68 | "codegen" => { |
69 | args.finish()?; | ||
73 | codegen::generate_syntax(Mode::Overwrite)?; | 70 | codegen::generate_syntax(Mode::Overwrite)?; |
74 | codegen::generate_parser_tests(Mode::Overwrite)?; | 71 | codegen::generate_parser_tests(Mode::Overwrite)?; |
75 | codegen::generate_assists_docs(Mode::Overwrite)?; | 72 | codegen::generate_assists_docs(Mode::Overwrite)?; |
73 | Ok(()) | ||
76 | } | 74 | } |
77 | "format" => run_rustfmt(Mode::Overwrite)?, | 75 | "format" => { |
78 | "install-pre-commit-hook" => install_pre_commit_hook()?, | 76 | args.finish()?; |
79 | "lint" => run_clippy()?, | 77 | run_rustfmt(Mode::Overwrite) |
80 | "fuzz-tests" => run_fuzzer()?, | ||
81 | _ => eprintln!("{}", help::GLOBAL_HELP), | ||
82 | } | ||
83 | Ok(()) | ||
84 | } | ||
85 | |||
86 | fn handle_extra_flags(e: pico_args::Error) -> Result<()> { | ||
87 | if let pico_args::Error::UnusedArgsLeft(flags) = e { | ||
88 | let mut invalid_flags = String::new(); | ||
89 | for flag in flags { | ||
90 | write!(&mut invalid_flags, "{}, ", flag)?; | ||
91 | } | 78 | } |
92 | let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); | 79 | "install-pre-commit-hook" => { |
93 | anyhow::bail!("Invalid flags: {}", invalid_flags) | 80 | args.finish()?; |
94 | } else { | 81 | pre_commit::install_hook() |
95 | anyhow::bail!(e.to_string()) | ||
96 | } | ||
97 | } | ||
98 | |||
99 | fn install(opts: InstallOpt) -> Result<()> { | ||
100 | if cfg!(target_os = "macos") { | ||
101 | fix_path_for_mac().context("Fix path for mac")? | ||
102 | } | ||
103 | if let Some(server) = opts.server { | ||
104 | install_server(server).context("install server")?; | ||
105 | } | ||
106 | if let Some(client) = opts.client { | ||
107 | install_client(client).context("install client")?; | ||
108 | } | ||
109 | Ok(()) | ||
110 | } | ||
111 | |||
112 | fn fix_path_for_mac() -> Result<()> { | ||
113 | let mut vscode_path: Vec<PathBuf> = { | ||
114 | const COMMON_APP_PATH: &str = | ||
115 | r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin"; | ||
116 | const ROOT_DIR: &str = ""; | ||
117 | let home_dir = match env::var("HOME") { | ||
118 | Ok(home) => home, | ||
119 | Err(e) => anyhow::bail!("Failed getting HOME from environment with error: {}.", e), | ||
120 | }; | ||
121 | |||
122 | [ROOT_DIR, &home_dir] | ||
123 | .iter() | ||
124 | .map(|dir| String::from(*dir) + COMMON_APP_PATH) | ||
125 | .map(PathBuf::from) | ||
126 | .filter(|path| path.exists()) | ||
127 | .collect() | ||
128 | }; | ||
129 | |||
130 | if !vscode_path.is_empty() { | ||
131 | let vars = match env::var_os("PATH") { | ||
132 | Some(path) => path, | ||
133 | None => anyhow::bail!("Could not get PATH variable from env."), | ||
134 | }; | ||
135 | |||
136 | let mut paths = env::split_paths(&vars).collect::<Vec<_>>(); | ||
137 | paths.append(&mut vscode_path); | ||
138 | let new_paths = env::join_paths(paths).context("build env PATH")?; | ||
139 | env::set_var("PATH", &new_paths); | ||
140 | } | ||
141 | |||
142 | Ok(()) | ||
143 | } | ||
144 | |||
145 | fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | ||
146 | let npm_version = Cmd { | ||
147 | unix: r"npm --version", | ||
148 | windows: r"cmd.exe /c npm --version", | ||
149 | work_dir: "./editors/code", | ||
150 | } | ||
151 | .run(); | ||
152 | |||
153 | if npm_version.is_err() { | ||
154 | eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin") | ||
155 | } | ||
156 | |||
157 | Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" } | ||
158 | .run()?; | ||
159 | Cmd { | ||
160 | unix: r"npm run package --scripts-prepend-node-path", | ||
161 | windows: r"cmd.exe /c npm run package", | ||
162 | work_dir: "./editors/code", | ||
163 | } | ||
164 | .run()?; | ||
165 | |||
166 | let code_binary = ["code", "code-insiders", "codium"].iter().find(|bin| { | ||
167 | Cmd { | ||
168 | unix: &format!("{} --version", bin), | ||
169 | windows: &format!("cmd.exe /c {}.cmd --version", bin), | ||
170 | work_dir: "./editors/code", | ||
171 | } | 82 | } |
172 | .run() | 83 | "lint" => { |
173 | .is_ok() | 84 | args.finish()?; |
174 | }); | 85 | run_clippy() |
175 | 86 | } | |
176 | let code_binary = match code_binary { | 87 | "fuzz-tests" => { |
177 | Some(it) => it, | 88 | args.finish()?; |
178 | None => anyhow::bail!("Can't execute `code --version`. Perhaps it is not in $PATH?"), | 89 | run_fuzzer() |
179 | }; | 90 | } |
180 | 91 | _ => { | |
181 | Cmd { | 92 | eprintln!( |
182 | unix: &format!(r"{} --install-extension ./ra-lsp-0.0.1.vsix --force", code_binary), | 93 | "\ |
183 | windows: &format!( | 94 | cargo xtask |
184 | r"cmd.exe /c {}.cmd --install-extension ./ra-lsp-0.0.1.vsix --force", | 95 | Run custom build command. |
185 | code_binary | 96 | |
186 | ), | 97 | USAGE: |
187 | work_dir: "./editors/code", | 98 | cargo xtask <SUBCOMMAND> |
188 | } | 99 | |
189 | .run()?; | 100 | SUBCOMMANDS: |
190 | 101 | format | |
191 | let output = Cmd { | 102 | install-pre-commit-hook |
192 | unix: &format!(r"{} --list-extensions", code_binary), | 103 | fuzz-tests |
193 | windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary), | 104 | codegen |
194 | work_dir: ".", | 105 | install |
195 | } | 106 | lint" |
196 | .run_with_output()?; | 107 | ); |
197 | 108 | Ok(()) | |
198 | if !str::from_utf8(&output.stdout)?.contains("ra-lsp") { | ||
199 | anyhow::bail!( | ||
200 | "Could not install the Visual Studio Code extension. \ | ||
201 | Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again." | ||
202 | ); | ||
203 | } | ||
204 | |||
205 | Ok(()) | ||
206 | } | ||
207 | |||
208 | fn install_server(opts: ServerOpt) -> Result<()> { | ||
209 | let mut old_rust = false; | ||
210 | if let Ok(output) = run_with_output("cargo --version", ".") { | ||
211 | if let Ok(stdout) = String::from_utf8(output.stdout) { | ||
212 | println!("{}", stdout); | ||
213 | if !check_version(&stdout, REQUIRED_RUST_VERSION) { | ||
214 | old_rust = true; | ||
215 | } | ||
216 | } | 109 | } |
217 | } | ||
218 | |||
219 | if old_rust { | ||
220 | eprintln!( | ||
221 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", | ||
222 | REQUIRED_RUST_VERSION, | ||
223 | ) | ||
224 | } | ||
225 | |||
226 | let res = if opts.jemalloc { | ||
227 | run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") | ||
228 | } else { | ||
229 | run("cargo install --path crates/ra_lsp_server --locked --force", ".") | ||
230 | }; | ||
231 | |||
232 | if res.is_err() && old_rust { | ||
233 | eprintln!( | ||
234 | "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n", | ||
235 | REQUIRED_RUST_VERSION, | ||
236 | ) | ||
237 | } | ||
238 | |||
239 | res | ||
240 | } | ||
241 | |||
242 | fn check_version(version_output: &str, min_minor_version: u32) -> bool { | ||
243 | // Parse second the number out of | ||
244 | // cargo 1.39.0-beta (1c6ec66d5 2019-09-30) | ||
245 | let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok()); | ||
246 | match minor { | ||
247 | None => true, | ||
248 | Some(minor) => minor >= min_minor_version, | ||
249 | } | 110 | } |
250 | } | 111 | } |
diff --git a/xtask/src/pre_commit.rs b/xtask/src/pre_commit.rs new file mode 100644 index 000000000..7984ba963 --- /dev/null +++ b/xtask/src/pre_commit.rs | |||
@@ -0,0 +1,36 @@ | |||
1 | //! pre-commit hook for code formatting. | ||
2 | |||
3 | use std::{fs, path::PathBuf}; | ||
4 | |||
5 | use anyhow::{bail, Result}; | ||
6 | |||
7 | use crate::{project_root, run, run_rustfmt, run_with_output, Mode}; | ||
8 | |||
9 | // FIXME: if there are changed `.ts` files, also reformat TypeScript (by | ||
10 | // shelling out to `npm fmt`). | ||
11 | pub fn run_hook() -> Result<()> { | ||
12 | run_rustfmt(Mode::Overwrite)?; | ||
13 | |||
14 | let diff = run_with_output("git diff --diff-filter=MAR --name-only --cached", ".")?; | ||
15 | |||
16 | let root = project_root(); | ||
17 | for line in String::from_utf8(diff.stdout)?.lines() { | ||
18 | run(&format!("git update-index --add {}", root.join(line).to_string_lossy()), ".")?; | ||
19 | } | ||
20 | |||
21 | Ok(()) | ||
22 | } | ||
23 | |||
24 | pub fn install_hook() -> Result<()> { | ||
25 | let hook_path: PathBuf = | ||
26 | format!("./.git/hooks/pre-commit{}", std::env::consts::EXE_SUFFIX).into(); | ||
27 | |||
28 | if hook_path.exists() { | ||
29 | bail!("Git hook already created"); | ||
30 | } | ||
31 | |||
32 | let me = std::env::current_exe()?; | ||
33 | fs::copy(me, hook_path)?; | ||
34 | |||
35 | Ok(()) | ||
36 | } | ||