diff options
| author | Emil Lauridsen <mine809@gmail.com> | 2020-01-29 13:40:27 +0100 |
|---|---|---|
| committer | Emil Lauridsen <mine809@gmail.com> | 2020-01-29 13:40:27 +0100 |
| commit | 8ffbe86dfd24ffcc11ec37bceca9102260d59db2 (patch) | |
| tree | 9b21617545fc358ebf2a47c8f28bf663a5a9afbc | |
| parent | 6fd29651b4f2bca8a36685a49d35cd349692984a (diff) | |
| download | rust-8ffbe86dfd24ffcc11ec37bceca9102260d59db2.tar.gz rust-8ffbe86dfd24ffcc11ec37bceca9102260d59db2.zip | |
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
| -rw-r--r-- | crates/ra_cargo_watch/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/ra_cargo_watch/src/lib.rs | 26 |
2 files changed, 22 insertions, 5 deletions
diff --git a/crates/ra_cargo_watch/Cargo.toml b/crates/ra_cargo_watch/Cargo.toml index 49e06e0d3c7..dd814fc9d9a 100644 --- a/crates/ra_cargo_watch/Cargo.toml +++ b/crates/ra_cargo_watch/Cargo.toml @@ -11,6 +11,7 @@ log = "0.4.3" cargo_metadata = "0.9.1" jod-thread = "0.1.0" parking_lot = "0.10.0" +serde_json = "1.0.45" [dev-dependencies] insta = "0.13.0" diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index 9af9c347dfa..e015692fa98 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs @@ -9,7 +9,7 @@ use lsp_types::{ }; use std::{ collections::HashMap, - io::BufReader, + io::{BufRead, BufReader}, path::PathBuf, process::{Command, Stdio}, sync::Arc, @@ -350,13 +350,29 @@ impl WatchThread { // which will break out of the loop, and continue the shutdown let _ = message_send.send(CheckEvent::Begin); - for message in - cargo_metadata::parse_messages(BufReader::new(command.stdout.take().unwrap())) - { + // We manually read a line at a time, instead of using serde's + // stream deserializers, because the deserializer cannot recover + // from an error, resulting in it getting stuck, because we try to + // be resillient against failures. + // + // Because cargo only outputs one JSON object per line, we can + // simply skip a line if it doesn't parse, which just ignores any + // erroneus output. + let stdout = BufReader::new(command.stdout.take().unwrap()); + for line in stdout.lines() { + let line = match line { + Ok(line) => line, + Err(err) => { + log::error!("Couldn't read line from cargo: {:?}", err); + continue; + } + }; + + let message = serde_json::from_str::<cargo_metadata::Message>(&line); let message = match message { Ok(message) => message, Err(err) => { - log::error!("Invalid json from cargo check, ignoring: {}", err); + log::error!("Invalid json from cargo check, ignoring ({}): {} ", err, line); continue; } }; |
