mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-17 02:08:30 +00:00
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 <mine809@gmail.com>
This commit is contained in:
commit
abc5828c05
2 changed files with 26 additions and 5 deletions
|
@ -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"
|
||||
|
|
|
@ -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,33 @@ 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;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue