diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 3c9c35a0e8f..1427f958288 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -283,36 +283,10 @@ fn rustc<'a, 'cfg>( &package_id, &target, mode, - &mut |line| { - if !line.is_empty() { - Err(internal(&format!( - "compiler stdout is not empty: `{}`", - line - ))) - } else { - Ok(()) - } - }, - &mut |line| { - // stderr from rustc can have a mix of JSON and non-JSON output - if line.starts_with('{') { - // Handle JSON lines - let compiler_message = serde_json::from_str(line).map_err(|_| { - internal(&format!("compiler produced invalid json: `{}`", line)) - })?; - - machine_message::emit(&machine_message::FromCompiler { - package_id: &package_id, - target: &target, - message: compiler_message, - }); - } else { - // Forward non-JSON to stderr - writeln!(io::stderr(), "{}", line)?; - } - Ok(()) - }, - ).map_err(Internal::new).chain_err(|| format!("Could not compile `{}`.", name))?; + &mut assert_is_empty, + &mut |line| json_stderr(line, &package_id, &target), + ).map_err(Internal::new) + .chain_err(|| format!("Could not compile `{}`.", name))?; } else if build_plan { state.build_plan(buildkey, rustc.clone(), outputs.clone()); } else { @@ -631,6 +605,10 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult rustdoc.arg("--cfg").arg(&format!("feature=\"{}\"", feat)); } + if bcx.build_config.json_messages() { + rustdoc.arg("--error-format").arg("json"); + } + if let Some(ref args) = bcx.extra_args_for(unit) { rustdoc.args(args); } @@ -642,6 +620,9 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult let name = unit.pkg.name().to_string(); let build_state = cx.build_state.clone(); let key = (unit.pkg.package_id().clone(), unit.kind); + let json_messages = bcx.build_config.json_messages(); + let package_id = unit.pkg.package_id().clone(); + let target = unit.target.clone(); let should_capture_output = cx.bcx.config.cli_unstable().compile_progress; @@ -656,7 +637,14 @@ fn rustdoc<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) -> CargoResult } state.running(&rustdoc); - let exec_result = if should_capture_output { + let exec_result = if json_messages { + rustdoc + .exec_with_streaming( + &mut assert_is_empty, + &mut |line| json_stderr(line, &package_id, &target), + false, + ).map(drop) + } else if should_capture_output { state.capture_output(rustdoc, false).map(drop) } else { rustdoc.exec() @@ -999,3 +987,33 @@ impl Kind { } } } + +fn assert_is_empty(line: &str) -> CargoResult<()> { + if !line.is_empty() { + Err(internal(&format!( + "compiler stdout is not empty: `{}`", + line + ))) + } else { + Ok(()) + } +} + +fn json_stderr(line: &str, package_id: &PackageId, target: &Target) -> CargoResult<()> { + // stderr from rustc/rustdoc can have a mix of JSON and non-JSON output + if line.starts_with('{') { + // Handle JSON lines + let compiler_message = serde_json::from_str(line) + .map_err(|_| internal(&format!("compiler produced invalid json: `{}`", line)))?; + + machine_message::emit(&machine_message::FromCompiler { + package_id: package_id, + target: target, + message: compiler_message, + }); + } else { + // Forward non-JSON to stderr + writeln!(io::stderr(), "{}", line)?; + } + Ok(()) +} diff --git a/tests/testsuite/doc.rs b/tests/testsuite/doc.rs index 871f459a593..ca212bf2ff6 100644 --- a/tests/testsuite/doc.rs +++ b/tests/testsuite/doc.rs @@ -1359,6 +1359,13 @@ fn doc_private_items() { assert_that(&foo.root().join("target/doc/foo/private/index.html"), existing_file()); } +const BAD_INTRA_LINK_LIB: &'static str = r#" +#![deny(intra_doc_link_resolution_failure)] + +/// [bad_link] +pub fn foo() {} +"#; + #[test] fn doc_cap_lints() { if !is_nightly() { @@ -1366,15 +1373,8 @@ fn doc_cap_lints() { return; } let a = git::new("a", |p| { - p.file("Cargo.toml", &basic_lib_manifest("a")).file( - "src/lib.rs", - " - #![deny(intra_doc_link_resolution_failure)] - - /// [bad_link] - pub fn foo() {} - ", - ) + p.file("Cargo.toml", &basic_lib_manifest("a")) + .file("src/lib.rs", BAD_INTRA_LINK_LIB) }).unwrap(); let p = project() @@ -1419,5 +1419,34 @@ fn doc_cap_lints() { ", ), ); +} +#[test] +fn doc_message_format() { + if !is_nightly() { + // This can be removed once 1.30 is stable (rustdoc --error-format stabilized). + return; + } + let p = project().file("src/lib.rs", BAD_INTRA_LINK_LIB).build(); + + assert_that( + p.cargo("doc --message-format=json"), + execs().with_status(101).with_json( + r#" + { + "message": { + "children": "{...}", + "code": "{...}", + "level": "error", + "message": "[..]", + "rendered": "[..]", + "spans": "{...}" + }, + "package_id": "foo [..]", + "reason": "compiler-message", + "target": "{...}" + } + "#, + ), + ); }