diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-01-29 12:51:52 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-01-29 12:51:52 +0000 |
commit | abc5828c057f65c8caa7e1adaca4d55519be457b (patch) | |
tree | fa72ecad87a91d9613591a464af6a57f723eb65d /crates/ra_cargo_watch/src/lib.rs | |
parent | 9f68f7acf2e4cae65122cae072bae2386f48bff1 (diff) | |
parent | 4ec5f6e25850b3064b258739eabefdeb8a4bd1b5 (diff) |
Merge #2937
2937: Parse cargo output a line at a time. r=kiljacken a=kiljacken
We previously used serde's stream deserializer to read json blobs from
the cargo output. It has an issue though: If the deserializer encounters
invalid input, it gets stuck reporting the same error again and again
because it is unable to foward over the input until it reaches a new
valid object.
Reading a line at a time and manually deserializing fixes this issue,
because cargo makes sure to only outpu one json blob per line, so should
we encounter invalid input, we can just skip a line and continue.
The main reason this would happen is stray printf-debugging in
procedural macros, so we still report that an error occured, but we
handle it gracefully now.
Fixes #2935
Co-authored-by: Emil Lauridsen <[email protected]>
Diffstat (limited to 'crates/ra_cargo_watch/src/lib.rs')
-rw-r--r-- | crates/ra_cargo_watch/src/lib.rs | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index 9af9c347d..ea7ddc86b 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs | |||
@@ -9,7 +9,7 @@ use lsp_types::{ | |||
9 | }; | 9 | }; |
10 | use std::{ | 10 | use std::{ |
11 | collections::HashMap, | 11 | collections::HashMap, |
12 | io::BufReader, | 12 | io::{BufRead, BufReader}, |
13 | path::PathBuf, | 13 | path::PathBuf, |
14 | process::{Command, Stdio}, | 14 | process::{Command, Stdio}, |
15 | sync::Arc, | 15 | sync::Arc, |
@@ -350,13 +350,33 @@ impl WatchThread { | |||
350 | // which will break out of the loop, and continue the shutdown | 350 | // which will break out of the loop, and continue the shutdown |
351 | let _ = message_send.send(CheckEvent::Begin); | 351 | let _ = message_send.send(CheckEvent::Begin); |
352 | 352 | ||
353 | for message in | 353 | // We manually read a line at a time, instead of using serde's |
354 | cargo_metadata::parse_messages(BufReader::new(command.stdout.take().unwrap())) | 354 | // stream deserializers, because the deserializer cannot recover |
355 | { | 355 | // from an error, resulting in it getting stuck, because we try to |
356 | // be resillient against failures. | ||
357 | // | ||
358 | // Because cargo only outputs one JSON object per line, we can | ||
359 | // simply skip a line if it doesn't parse, which just ignores any | ||
360 | // erroneus output. | ||
361 | let stdout = BufReader::new(command.stdout.take().unwrap()); | ||
362 | for line in stdout.lines() { | ||
363 | let line = match line { | ||
364 | Ok(line) => line, | ||
365 | Err(err) => { | ||
366 | log::error!("Couldn't read line from cargo: {}", err); | ||
367 | continue; | ||
368 | } | ||
369 | }; | ||
370 | |||
371 | let message = serde_json::from_str::<cargo_metadata::Message>(&line); | ||
356 | let message = match message { | 372 | let message = match message { |
357 | Ok(message) => message, | 373 | Ok(message) => message, |
358 | Err(err) => { | 374 | Err(err) => { |
359 | log::error!("Invalid json from cargo check, ignoring: {}", err); | 375 | log::error!( |
376 | "Invalid json from cargo check, ignoring ({}): {:?} ", | ||
377 | err, | ||
378 | line | ||
379 | ); | ||
360 | continue; | 380 | continue; |
361 | } | 381 | } |
362 | }; | 382 | }; |