aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch/src
diff options
context:
space:
mode:
authorEmil Lauridsen <[email protected]>2020-01-29 12:40:27 +0000
committerEmil Lauridsen <[email protected]>2020-01-29 12:40:27 +0000
commit8ffbe86dfd24ffcc11ec37bceca9102260d59db2 (patch)
tree9b21617545fc358ebf2a47c8f28bf663a5a9afbc /crates/ra_cargo_watch/src
parent6fd29651b4f2bca8a36685a49d35cd349692984a (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.rs26
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};
10use std::{ 10use 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 };