Skip to content

Commit abc5828

Browse files
bors[bot]kiljacken
andauthored
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]>
2 parents 9f68f7a + 4ec5f6e commit abc5828

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

crates/ra_cargo_watch/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ log = "0.4.3"
1111
cargo_metadata = "0.9.1"
1212
jod-thread = "0.1.0"
1313
parking_lot = "0.10.0"
14+
serde_json = "1.0.45"
1415

1516
[dev-dependencies]
1617
insta = "0.13.0"

crates/ra_cargo_watch/src/lib.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use lsp_types::{
99
};
1010
use std::{
1111
collections::HashMap,
12-
io::BufReader,
12+
io::{BufRead, BufReader},
1313
path::PathBuf,
1414
process::{Command, Stdio},
1515
sync::Arc,
@@ -350,13 +350,33 @@ impl WatchThread {
350350
// which will break out of the loop, and continue the shutdown
351351
let _ = message_send.send(CheckEvent::Begin);
352352

353-
for message in
354-
cargo_metadata::parse_messages(BufReader::new(command.stdout.take().unwrap()))
355-
{
353+
// We manually read a line at a time, instead of using serde's
354+
// stream deserializers, because the deserializer cannot recover
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);
356372
let message = match message {
357373
Ok(message) => message,
358374
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+
);
360380
continue;
361381
}
362382
};

0 commit comments

Comments
 (0)