diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-04-01 12:15:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-01 12:15:37 +0100 |
commit | d03d638cc3803a4994cef01b889cd1eaf20e7e01 (patch) | |
tree | d6f25e08d77a45c70754d7e2b91a7be9897b0ce3 /crates/ra_flycheck/src | |
parent | aad0e63d744e5220fae38f61e1adf7654fb618bd (diff) | |
parent | cc8113dd464fdce61fd425157e1145404be3b568 (diff) |
Merge #3804
3804: Generalize flycheck to arbitrary commands r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_flycheck/src')
-rw-r--r-- | crates/ra_flycheck/src/lib.rs | 89 |
1 files changed, 37 insertions, 52 deletions
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index ee09d8de3..13494a731 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs | |||
@@ -4,8 +4,8 @@ | |||
4 | mod conv; | 4 | mod conv; |
5 | 5 | ||
6 | use std::{ | 6 | use std::{ |
7 | env, error, fmt, | 7 | env, |
8 | io::{BufRead, BufReader}, | 8 | io::{self, BufRead, BufReader}, |
9 | path::PathBuf, | 9 | path::PathBuf, |
10 | process::{Command, Stdio}, | 10 | process::{Command, Stdio}, |
11 | time::Instant, | 11 | time::Instant, |
@@ -23,10 +23,9 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic}; | |||
23 | pub use crate::conv::url_from_path_with_drive_lowercasing; | 23 | pub use crate::conv::url_from_path_with_drive_lowercasing; |
24 | 24 | ||
25 | #[derive(Clone, Debug)] | 25 | #[derive(Clone, Debug)] |
26 | pub struct FlycheckConfig { | 26 | pub enum FlycheckConfig { |
27 | pub command: String, | 27 | CargoCommand { command: String, all_targets: bool, extra_args: Vec<String> }, |
28 | pub all_targets: bool, | 28 | CustomCommand { command: String, args: Vec<String> }, |
29 | pub extra_args: Vec<String>, | ||
30 | } | 29 | } |
31 | 30 | ||
32 | /// Flycheck wraps the shared state and communication machinery used for | 31 | /// Flycheck wraps the shared state and communication machinery used for |
@@ -215,18 +214,25 @@ impl FlycheckThread { | |||
215 | self.message_recv = never(); | 214 | self.message_recv = never(); |
216 | self.check_process = None; | 215 | self.check_process = None; |
217 | 216 | ||
218 | let cmd = { | 217 | let mut cmd = match &self.config { |
219 | let mut cmd = Command::new(cargo_binary()); | 218 | FlycheckConfig::CargoCommand { command, all_targets, extra_args } => { |
220 | cmd.arg(&self.config.command); | 219 | let mut cmd = Command::new(cargo_binary()); |
221 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]); | 220 | cmd.arg(command); |
222 | cmd.arg(self.workspace_root.join("Cargo.toml")); | 221 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]); |
223 | if self.config.all_targets { | 222 | cmd.arg(self.workspace_root.join("Cargo.toml")); |
224 | cmd.arg("--all-targets"); | 223 | if *all_targets { |
224 | cmd.arg("--all-targets"); | ||
225 | } | ||
226 | cmd.args(extra_args); | ||
227 | cmd | ||
228 | } | ||
229 | FlycheckConfig::CustomCommand { command, args } => { | ||
230 | let mut cmd = Command::new(command); | ||
231 | cmd.args(args); | ||
232 | cmd | ||
225 | } | 233 | } |
226 | cmd.args(self.config.extra_args.iter()); | ||
227 | cmd.current_dir(&self.workspace_root); | ||
228 | cmd | ||
229 | }; | 234 | }; |
235 | cmd.current_dir(&self.workspace_root); | ||
230 | 236 | ||
231 | let (message_send, message_recv) = unbounded(); | 237 | let (message_send, message_recv) = unbounded(); |
232 | self.message_recv = message_recv; | 238 | self.message_recv = message_recv; |
@@ -273,27 +279,12 @@ enum CheckEvent { | |||
273 | End, | 279 | End, |
274 | } | 280 | } |
275 | 281 | ||
276 | #[derive(Debug)] | ||
277 | pub struct CargoError(String); | ||
278 | |||
279 | impl fmt::Display for CargoError { | ||
280 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
281 | write!(f, "Cargo failed: {}", self.0) | ||
282 | } | ||
283 | } | ||
284 | impl error::Error for CargoError {} | ||
285 | |||
286 | fn run_cargo( | 282 | fn run_cargo( |
287 | mut command: Command, | 283 | mut command: Command, |
288 | on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, | 284 | on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, |
289 | ) -> Result<(), CargoError> { | 285 | ) -> io::Result<()> { |
290 | dbg!(&command); | 286 | let mut child = |
291 | let mut child = command | 287 | command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?; |
292 | .stdout(Stdio::piped()) | ||
293 | .stderr(Stdio::null()) | ||
294 | .stdin(Stdio::null()) | ||
295 | .spawn() | ||
296 | .expect("couldn't launch cargo"); | ||
297 | 288 | ||
298 | // We manually read a line at a time, instead of using serde's | 289 | // We manually read a line at a time, instead of using serde's |
299 | // stream deserializers, because the deserializer cannot recover | 290 | // stream deserializers, because the deserializer cannot recover |
@@ -307,13 +298,7 @@ fn run_cargo( | |||
307 | let mut read_at_least_one_message = false; | 298 | let mut read_at_least_one_message = false; |
308 | 299 | ||
309 | for line in stdout.lines() { | 300 | for line in stdout.lines() { |
310 | let line = match line { | 301 | let line = line?; |
311 | Ok(line) => line, | ||
312 | Err(err) => { | ||
313 | log::error!("Couldn't read line from cargo: {}", err); | ||
314 | continue; | ||
315 | } | ||
316 | }; | ||
317 | 302 | ||
318 | let message = serde_json::from_str::<cargo_metadata::Message>(&line); | 303 | let message = serde_json::from_str::<cargo_metadata::Message>(&line); |
319 | let message = match message { | 304 | let message = match message { |
@@ -334,20 +319,20 @@ fn run_cargo( | |||
334 | // It is okay to ignore the result, as it only errors if the process is already dead | 319 | // It is okay to ignore the result, as it only errors if the process is already dead |
335 | let _ = child.kill(); | 320 | let _ = child.kill(); |
336 | 321 | ||
337 | let err_msg = match child.wait() { | 322 | let exit_status = child.wait()?; |
338 | Ok(exit_code) if !exit_code.success() && !read_at_least_one_message => { | 323 | if !exit_status.success() && !read_at_least_one_message { |
339 | // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: | 324 | // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment: |
340 | // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 | 325 | // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298 |
326 | return Err(io::Error::new( | ||
327 | io::ErrorKind::Other, | ||
341 | format!( | 328 | format!( |
342 | "the command produced no valid metadata (exit code: {:?}): {:?}", | 329 | "the command produced no valid metadata (exit code: {:?}): {:?}", |
343 | exit_code, command | 330 | exit_status, command |
344 | ) | 331 | ), |
345 | } | 332 | )); |
346 | Err(err) => format!("io error: {:?}", err), | 333 | } |
347 | Ok(_) => return Ok(()), | ||
348 | }; | ||
349 | 334 | ||
350 | Err(CargoError(err_msg)) | 335 | Ok(()) |
351 | } | 336 | } |
352 | 337 | ||
353 | fn cargo_binary() -> String { | 338 | fn cargo_binary() -> String { |