From 27bbd83397d399b30626f432b1e7dffb855f9dd0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Apr 2020 11:55:58 +0200 Subject: [PATCH] Fix busy-loop when proc-macro prints to stdout --- src/lib.rs | 9 +++++---- src/messages.rs | 27 ++++++++++++++++++++++++++- tests/test_samples.rs | 11 +++++++++-- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 84d64d8d..2dd6ea82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,8 @@ //! .spawn() //! .unwrap(); //! -//! for message in cargo_metadata::parse_messages(command.stdout.take().unwrap()) { +//! let reader = std::io::BufReader::new(command.stdout.take().unwrap()); +//! for message in cargo_metadata::Message::parse_stream(reader) { //! match message.unwrap() { //! Message::CompilerMessage(msg) => { //! println!("{:?}", msg); @@ -92,9 +93,9 @@ use semver::Version; pub use dependency::{Dependency, DependencyKind}; use diagnostic::Diagnostic; pub use errors::{Error, Result}; -pub use messages::{ - parse_messages, Artifact, ArtifactProfile, BuildScript, CompilerMessage, Message, -}; +pub use messages::{Artifact, ArtifactProfile, BuildScript, CompilerMessage, Message, MessageIter}; +#[allow(deprecated)] +pub use messages::parse_messages; mod dependency; pub mod diagnostic; diff --git a/src/messages.rs b/src/messages.rs index 06c1943d..a05405eb 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,7 +1,7 @@ use super::{Diagnostic, PackageId, Target}; use serde_json; use std::fmt; -use std::io::Read; +use std::io::{self, BufRead, Lines, Read}; use std::path::PathBuf; /// Profile settings used to determine which compiler flags to use for a @@ -100,18 +100,43 @@ pub enum Message { Unknown, } +impl Message { + /// Creates an iterator of Message from a Read outputting a stream of JSON + /// messages. For usage information, look at the top-level documentation. + pub fn parse_stream(input: R) -> MessageIter { + MessageIter { + lines: input.lines(), + } + } +} + impl fmt::Display for CompilerMessage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.message) } } +/// An iterator of Messages. +pub struct MessageIter { + lines: Lines, +} + +impl Iterator for MessageIter { + type Item = io::Result; + fn next(&mut self) -> Option { + let line = self.lines.next()?; + let message = line.and_then(|it| serde_json::from_str(&it).map_err(io::Error::from)); + Some(message) + } +} + /// An iterator of Message. type MessageIterator = serde_json::StreamDeserializer<'static, serde_json::de::IoRead, Message>; /// Creates an iterator of Message from a Read outputting a stream of JSON /// messages. For usage information, look at the top-level documentation. +#[deprecated(note = "Use Message::parse_stream instead")] pub fn parse_messages(input: R) -> MessageIterator { serde_json::Deserializer::from_reader(input).into_iter::() } diff --git a/tests/test_samples.rs b/tests/test_samples.rs index 100b30b8..ee3abc23 100644 --- a/tests/test_samples.rs +++ b/tests/test_samples.rs @@ -483,7 +483,14 @@ fn parse_messages_is_robust() { Evil proc macro was here! {"reason":"compiler-artifact","package_id":"chatty-macro 0.1.0 (path+file:///chatty-macro)","target":{"kind":["lib"],"crate_types":["lib"],"name":"chatty-macro","src_path":"/chatty-macro/src/lib.rs","edition":"2018","doctest":true},"profile":{"opt_level":"0","debuginfo":2,"debug_assertions":true,"overflow_checks":true,"test":false},"features":[],"filenames":["/chatty-macro/target/debug/libchatty_macro.rlib","/chatty-macro/target/debug/deps/libchatty_macro-cb5956ed52a11fb6.rmeta"],"executable":null,"fresh":false} "##; - for m in cargo_metadata::parse_messages(json_output.as_bytes()) { - eprintln!("m = {:?}", m); + let mut good = 0; + let mut bad = 0; + for m in cargo_metadata::Message::parse_stream(json_output.as_bytes()) { + match m { + Ok(_) => good += 1, + Err(_) => bad += 1, + } } + assert_eq!(good, 2); + assert_eq!(bad, 1); }