Skip to content

Commit f4e2eac

Browse files
committed
Auto merge of #12252 - charmitro:master, r=weihanglo
Add unstable `--output-format` option to `cargo rustdoc` Add unstable `--output-format` option to "rustdoc" We achieved this by: * Handle `--output-format` argument, accepting `html` or `json` * A new field `json` in `CompileMode::Doc`. * If `json` is passed, we append the following in `prepare_rustdoc`: 1. `-Zunstable-options` 2. `--output-format=json` Fixes #12103
2 parents 4eef543 + 9276399 commit f4e2eac

File tree

17 files changed

+244
-15
lines changed

17 files changed

+244
-15
lines changed

src/bin/cargo/commands/doc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,15 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
4949
let ws = args.workspace(config)?;
5050
let mode = CompileMode::Doc {
5151
deps: !args.flag("no-deps"),
52+
json: false,
5253
};
5354
let mut compile_opts =
5455
args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?;
5556
compile_opts.rustdoc_document_private_items = args.flag("document-private-items");
5657

5758
let doc_opts = DocOptions {
5859
open_result: args.flag("open"),
60+
output_format: ops::OutputFormat::Html,
5961
compile_opts,
6062
};
6163
ops::doc(&ws, &doc_opts)?;

src/bin/cargo/commands/rustdoc.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use cargo::ops::{self, DocOptions};
1+
use cargo::ops::{self, DocOptions, OutputFormat};
22

33
use crate::command_prelude::*;
44

@@ -38,6 +38,11 @@ pub fn cli() -> Command {
3838
.arg_profile("Build artifacts with the specified profile")
3939
.arg_target_triple("Build for the target triple")
4040
.arg_target_dir()
41+
.arg(
42+
opt("output-format", "The output type to write (unstable)")
43+
.value_name("FMT")
44+
.value_parser(OutputFormat::POSSIBLE_VALUES),
45+
)
4146
.arg_unit_graph()
4247
.arg_timings()
4348
.arg_manifest_path()
@@ -48,20 +53,35 @@ pub fn cli() -> Command {
4853

4954
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
5055
let ws = args.workspace(config)?;
56+
let output_format = if let Some(output_format) = args._value_of("output-format") {
57+
config
58+
.cli_unstable()
59+
.fail_if_stable_opt("--output-format", 12103)?;
60+
output_format.parse()?
61+
} else {
62+
OutputFormat::Html
63+
};
64+
5165
let mut compile_opts = args.compile_options_for_single_package(
5266
config,
53-
CompileMode::Doc { deps: false },
67+
CompileMode::Doc {
68+
deps: false,
69+
json: matches!(output_format, OutputFormat::Json),
70+
},
5471
Some(&ws),
5572
ProfileChecking::Custom,
5673
)?;
5774
let target_args = values(args, "args");
75+
5876
compile_opts.target_rustdoc_args = if target_args.is_empty() {
5977
None
6078
} else {
6179
Some(target_args)
6280
};
81+
6382
let doc_opts = DocOptions {
6483
open_result: args.flag("open"),
84+
output_format,
6585
compile_opts,
6686
};
6787
ops::doc(&ws, &doc_opts)?;

src/cargo/core/compiler/build_config.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,10 @@ pub enum CompileMode {
176176
/// allows some de-duping of Units to occur.
177177
Bench,
178178
/// A target that will be documented with `rustdoc`.
179+
179180
/// If `deps` is true, then it will also document all dependencies.
180-
Doc { deps: bool },
181+
/// if `json` is true, the documentation output is in json format.
182+
Doc { deps: bool, json: bool },
181183
/// A target that will be tested with `rustdoc`.
182184
Doctest,
183185
/// An example or library that will be scraped for function calls by `rustdoc`.

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,16 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
435435
bcx: &BuildContext<'a, 'cfg>,
436436
) -> CargoResult<Arc<Vec<OutputFile>>> {
437437
let ret = match unit.mode {
438-
CompileMode::Doc { .. } => {
439-
let path = self
440-
.out_dir(unit)
441-
.join(unit.target.crate_name())
442-
.join("index.html");
438+
CompileMode::Doc { json, .. } => {
439+
let path = if json {
440+
self.out_dir(unit)
441+
.join(format!("{}.json", unit.target.crate_name()))
442+
} else {
443+
self.out_dir(unit)
444+
.join(unit.target.crate_name())
445+
.join("index.html")
446+
};
447+
443448
vec![OutputFile {
444449
path,
445450
hardlink: None,

src/cargo/core/compiler/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,8 @@ fn prepare_rustdoc(cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuil
762762
build_deps_args(&mut rustdoc, cx, unit)?;
763763
rustdoc::add_root_urls(cx, unit, &mut rustdoc)?;
764764

765+
rustdoc::add_output_format(cx, unit, &mut rustdoc)?;
766+
765767
rustdoc.args(bcx.rustdocflags_args(unit));
766768

767769
if !crate_version_flag_already_present(&rustdoc) {

src/cargo/core/compiler/rustdoc.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use std::fmt;
1111
use std::hash;
1212
use url::Url;
1313

14+
use super::CompileMode;
15+
1416
const DOCS_RS_URL: &'static str = "https://docs.rs/";
1517

1618
/// Mode used for `std`. This is for unstable feature [`-Zrustdoc-map`][1].
@@ -204,6 +206,29 @@ pub fn add_root_urls(
204206
Ok(())
205207
}
206208

209+
/// Adds unstable flag [`--output-format`][1] to the given `rustdoc`
210+
/// invocation. This is for unstable feature [`-Zunstable-features`].
211+
///
212+
/// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html?highlight=output-format#-w--output-format-output-format
213+
pub fn add_output_format(
214+
cx: &Context<'_, '_>,
215+
unit: &Unit,
216+
rustdoc: &mut ProcessBuilder,
217+
) -> CargoResult<()> {
218+
let config = cx.bcx.config;
219+
if !config.cli_unstable().unstable_options {
220+
tracing::debug!("`unstable-options` is ignored, required -Zunstable-options flag");
221+
return Ok(());
222+
}
223+
224+
if let CompileMode::Doc { json: true, .. } = unit.mode {
225+
rustdoc.arg("-Zunstable-options");
226+
rustdoc.arg("--output-format=json");
227+
}
228+
229+
Ok(())
230+
}
231+
207232
/// Indicates whether a target should have examples scraped from it by rustdoc.
208233
/// Configured within Cargo.toml and only for unstable feature
209234
/// [`-Zrustdoc-scrape-examples`][1].

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ fn compute_deps_doc(
627627
)?;
628628
ret.push(lib_unit_dep);
629629
if dep_lib.documented() {
630-
if let CompileMode::Doc { deps: true } = unit.mode {
630+
if let CompileMode::Doc { deps: true, .. } = unit.mode {
631631
// Document this lib as well.
632632
let doc_unit_dep = new_unit_dep(
633633
state,

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ pub fn create_bcx<'a, 'cfg>(
420420

421421
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
422422
// what heuristics to use in that case.
423-
if build_config.mode == (CompileMode::Doc { deps: true }) {
423+
if matches!(build_config.mode, CompileMode::Doc { deps: true, .. }) {
424424
remove_duplicate_doc(build_config, &units, &mut unit_graph);
425425
}
426426

src/cargo/ops/cargo_doc.rs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,50 @@ use crate::core::{Shell, Workspace};
22
use crate::ops;
33
use crate::util::config::{Config, PathAndArgs};
44
use crate::util::CargoResult;
5+
use anyhow::{bail, Error};
56
use std::path::Path;
67
use std::path::PathBuf;
78
use std::process::Command;
9+
use std::str::FromStr;
10+
11+
/// Format of rustdoc [`--output-format`][1].
12+
///
13+
/// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#-w--output-format-output-format
14+
#[derive(Debug, Default, Clone)]
15+
pub enum OutputFormat {
16+
#[default]
17+
Html,
18+
Json,
19+
}
20+
21+
impl OutputFormat {
22+
pub const POSSIBLE_VALUES: [&'static str; 2] = ["html", "json"];
23+
}
24+
25+
impl FromStr for OutputFormat {
26+
// bail! error instead of string error like impl FromStr for Edition {
27+
type Err = Error;
28+
29+
fn from_str(s: &str) -> Result<Self, Self::Err> {
30+
match s {
31+
"json" => Ok(OutputFormat::Json),
32+
"html" => Ok(OutputFormat::Html),
33+
_ => bail!(
34+
"supported values for --output-format are `json` and `html`, \
35+
but `{}` is unknown",
36+
s
37+
),
38+
}
39+
}
40+
}
841

942
/// Strongly typed options for the `cargo doc` command.
1043
#[derive(Debug)]
1144
pub struct DocOptions {
1245
/// Whether to attempt to open the browser after compiling the docs
1346
pub open_result: bool,
47+
/// Same as `rustdoc --output-format`
48+
pub output_format: OutputFormat,
1449
/// Options to pass through to the compiler
1550
pub compile_opts: ops::CompileOptions,
1651
}
@@ -25,10 +60,18 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
2560
.get(0)
2661
.ok_or_else(|| anyhow::anyhow!("no crates with documentation"))?;
2762
let kind = options.compile_opts.build_config.single_requested_kind()?;
28-
let path = compilation.root_output[&kind]
29-
.with_file_name("doc")
30-
.join(&name)
31-
.join("index.html");
63+
64+
let path = if matches!(options.output_format, OutputFormat::Json) {
65+
compilation.root_output[&kind]
66+
.with_file_name("doc")
67+
.join(format!("{}.json", &name))
68+
} else {
69+
compilation.root_output[&kind]
70+
.with_file_name("doc")
71+
.join(&name)
72+
.join("index.html")
73+
};
74+
3275
if path.exists() {
3376
let config_browser = {
3477
let cfg: Option<PathAndArgs> = ws.config().get("doc.browser")?;

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub use self::cargo_compile::{
55
compile, compile_with_exec, compile_ws, create_bcx, print, resolve_all_features, CompileOptions,
66
};
77
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
8-
pub use self::cargo_doc::{doc, DocOptions};
8+
pub use self::cargo_doc::{doc, DocOptions, OutputFormat};
99
pub use self::cargo_fetch::{fetch, FetchOptions};
1010
pub use self::cargo_generate_lockfile::generate_lockfile;
1111
pub use self::cargo_generate_lockfile::update_lockfile;

0 commit comments

Comments
 (0)