-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support JSON with rustdoc. #5878
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is an odd inconsistency. There's an open issue for that (rust-lang/rust#48301). I imagine since the vast majority of people use rustc behind cargo it doesn't really come up often. |
||
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(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to feature-detect support for
json
here, right? The user requests--message-format=json
explicitly, so they'll see an error and that is expected behavior.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the question. This is the code that translates cargo's
--message-format
flag to rustdoc's--error-format
flag.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--error-format
is a recent addition torustdoc
, so, in theory, using new cargo and old rustdoc could result in amessage. However, that should be fine, because the user has to ask for
cargo doc --message-format=json
explicitly. That is, it's not a flag that we add automatically for existing workflows, so we don't have to feature-detect support for it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I understand now. Yea, my understanding is that the version of cargo is tightly wedded to rustc and rustdoc. I think some distributions have attempted to split them, but afaik cargo doesn't really support that use case, right? At least in this case, it wouldn't break the normal usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is at least somewhat supported: you can override compiler & rustdoc with env vars, and we try account for different compilers in Rustc cache. I think the current approach is "don't break things without necessity", and I don't remember any actual CLI changes that could have caused breakage.