diff options
author | Emil Lauridsen <[email protected]> | 2020-01-29 12:40:27 +0000 |
---|---|---|
committer | Emil Lauridsen <[email protected]> | 2020-01-29 12:40:27 +0000 |
commit | 8ffbe86dfd24ffcc11ec37bceca9102260d59db2 (patch) | |
tree | 9b21617545fc358ebf2a47c8f28bf663a5a9afbc /crates/ra_cargo_watch/src | |
parent | 6fd29651b4f2bca8a36685a49d35cd349692984a (diff) |
Parse cargo output a line at a time.
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
Diffstat (limited to 'crates/ra_cargo_watch/src')
-rw-r--r-- | crates/ra_cargo_watch/src/lib.rs | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index 9af9c347d..e015692fa 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,29 @@ 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!("Invalid json from cargo check, ignoring ({}): {} ", err, line); |
360 | continue; | 376 | continue; |
361 | } | 377 | } |
362 | }; | 378 | }; |