Skip to content

Commit bd9ff5b

Browse files
committed
Add unstable --output-format option to "rustdoc"
We achieved this by: * Handle `--output-format` argument, accepting `html` or `json` * If `json` is passed, we append the following to `compile_opts.target_rustc_args`: 1. `-Zunstable-commands` 2. `--output-format`
1 parent 5b377ce commit bd9ff5b

File tree

18 files changed

+171
-13
lines changed

18 files changed

+171
-13
lines changed

src/bin/cargo/commands/doc.rs

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

5556
let doc_opts = DocOptions {
5657
open_result: args.flag("open"),
58+
output_format: ops::OutputFormat::Html,
5759
compile_opts,
5860
};
5961
ops::doc(&ws, &doc_opts)?;

src/bin/cargo/commands/rustdoc.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use cargo::ops::{self, DocOptions};
1+
use std::str::FromStr;
2+
3+
use cargo::ops::{self, DocOptions, OutputFormat};
24

35
use crate::command_prelude::*;
46

@@ -35,6 +37,10 @@ pub fn cli() -> Command {
3537
.arg_features()
3638
.arg_target_triple("Build for the target triple")
3739
.arg_target_dir()
40+
.arg(
41+
opt("output-format", "the output type to write (unstable)")
42+
.value_parser(["html", "json"]),
43+
)
3844
.arg_manifest_path()
3945
.arg_message_format()
4046
.arg_unit_graph()
@@ -45,20 +51,40 @@ pub fn cli() -> Command {
4551

4652
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
4753
let ws = args.workspace(config)?;
54+
let output_format = if let Some(output_format) = args._value_of("output-format") {
55+
OutputFormat::from_str(output_format).unwrap()
56+
} else {
57+
OutputFormat::Html
58+
};
4859
let mut compile_opts = args.compile_options_for_single_package(
4960
config,
50-
CompileMode::Doc { deps: false },
61+
CompileMode::Doc {
62+
deps: false,
63+
json: matches!(output_format, OutputFormat::Json),
64+
},
5165
Some(&ws),
5266
ProfileChecking::Custom,
5367
)?;
54-
let target_args = values(args, "args");
68+
let mut target_args = values(args, "args");
69+
70+
if matches!(output_format, OutputFormat::Json) {
71+
config
72+
.cli_unstable()
73+
.fail_if_stable_opt("--output-format", 12103)?;
74+
// Not sure about this. @charmitro
75+
target_args.push("-Zunstable-options".to_string());
76+
target_args.push("--output-format=json".to_string());
77+
}
78+
5579
compile_opts.target_rustdoc_args = if target_args.is_empty() {
5680
None
5781
} else {
5882
Some(target_args)
5983
};
84+
6085
let doc_opts = DocOptions {
6186
open_result: args.flag("open"),
87+
output_format: OutputFormat::Html,
6288
compile_opts,
6389
};
6490
ops::doc(&ws, &doc_opts)?;

src/cargo/core/compiler/build_config.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,8 @@ pub enum CompileMode {
177177
Bench,
178178
/// A target that will be documented with `rustdoc`.
179179
/// If `deps` is true, then it will also document all dependencies.
180-
Doc { deps: bool },
180+
/// if `json` is true, the documentation output is in json format.
181+
Doc { deps: bool, json: bool },
181182
/// A target that will be tested with `rustdoc`.
182183
Doctest,
183184
/// 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/unit_dependencies.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,11 @@ fn compute_deps_doc(
632632
)?;
633633
ret.push(lib_unit_dep);
634634
if dep_lib.documented() {
635-
if let CompileMode::Doc { deps: true } = unit.mode {
635+
if let CompileMode::Doc {
636+
deps: true,
637+
json: true | false,
638+
} = unit.mode
639+
{
636640
// Document this lib as well.
637641
let doc_unit_dep = new_unit_dep(
638642
state,

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,12 @@ pub fn create_bcx<'a, 'cfg>(
417417

418418
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
419419
// what heuristics to use in that case.
420-
if build_config.mode == (CompileMode::Doc { deps: true }) {
420+
if build_config.mode
421+
== (CompileMode::Doc {
422+
deps: true,
423+
json: true || false,
424+
})
425+
{
421426
remove_duplicate_doc(build_config, &units, &mut unit_graph);
422427
}
423428

src/cargo/ops/cargo_doc.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,50 @@ use crate::util::CargoResult;
55
use std::path::Path;
66
use std::path::PathBuf;
77
use std::process::Command;
8+
use std::str::FromStr;
9+
10+
/// Format of rustdoc [`--output-format`][1].
11+
///
12+
/// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#-w--output-format-output-format
13+
#[derive(Debug, Default, Clone)]
14+
pub enum OutputFormat {
15+
#[default]
16+
Html,
17+
Json,
18+
}
19+
20+
impl FromStr for OutputFormat {
21+
type Err = ();
22+
23+
fn from_str(s: &str) -> Result<Self, Self::Err> {
24+
match s {
25+
"json" => Ok(Self::Json),
26+
"html" => Ok(Self::Html),
27+
_ => Err(()),
28+
}
29+
}
30+
}
831

932
/// Strongly typed options for the `cargo doc` command.
1033
#[derive(Debug)]
1134
pub struct DocOptions {
1235
/// Whether to attempt to open the browser after compiling the docs
1336
pub open_result: bool,
37+
/// Same as `rustdoc --output-format`
38+
pub output_format: OutputFormat,
1439
/// Options to pass through to the compiler
1540
pub compile_opts: ops::CompileOptions,
1641
}
1742

1843
/// Main method for `cargo doc`.
1944
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
45+
if options.open_result && matches!(options.output_format, OutputFormat::Json) {
46+
anyhow::bail!("`--open` is not allowed with `json` output format.");
47+
}
48+
2049
let compilation = ops::compile(ws, &options.compile_opts)?;
2150

22-
if options.open_result {
51+
if options.open_result && matches!(options.output_format, OutputFormat::Html) {
2352
let name = &compilation
2453
.root_crate_names
2554
.get(0)

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;

src/doc/man/cargo-doc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ and supports common Unix glob patterns.
112112
{{#options}}
113113
{{> options-jobs }}
114114
{{> options-keep-going }}
115+
{{> options-output-format }}
115116
{{/options}}
116117

117118
{{> section-environment }}

src/doc/man/cargo-rustdoc.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ if its name is the same as the lib target. Binaries are skipped if they have
100100
{{#options}}
101101
{{> options-jobs }}
102102
{{> options-keep-going }}
103+
{{> options-output-format }}
103104
{{/options}}
104105

105106
{{> section-environment }}

src/doc/man/generated_txt/cargo-doc.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ OPTIONS
305305
than aborting the build on the first one that fails to build.
306306
Unstable, requires -Zunstable-options.
307307

308+
--output-format
309+
The output type to write. Unstable, requires -Zunstable-options.
310+
308311
ENVIRONMENT
309312
See the reference
310313
<https://doc.rust-lang.org/cargo/reference/environment-variables.html>

src/doc/man/generated_txt/cargo-rustdoc.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ OPTIONS
321321
than aborting the build on the first one that fails to build.
322322
Unstable, requires -Zunstable-options.
323323

324+
--output-format
325+
The output type to write. Unstable, requires -Zunstable-options.
326+
324327
ENVIRONMENT
325328
See the reference
326329
<https://doc.rust-lang.org/cargo/reference/environment-variables.html>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{{#option "`--output-format`"}}
2+
The output type to write.
3+
Unstable, requires `-Zunstable-options`.
4+
{{/option}}

src/doc/src/commands/cargo-doc.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ the build on the first one that fails to build. Unstable, requires
368368
<code>-Zunstable-options</code>.</dd>
369369

370370

371+
<dt class="option-term" id="option-cargo-doc---output-format"><a class="option-anchor" href="#option-cargo-doc---output-format"></a><code>--output-format</code></dt>
372+
<dd class="option-desc">The output type to write.
373+
Unstable, requires <code>-Zunstable-options</code>.</dd>
374+
375+
371376
</dl>
372377

373378
## ENVIRONMENT

src/doc/src/commands/cargo-rustdoc.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,11 @@ the build on the first one that fails to build. Unstable, requires
387387
<code>-Zunstable-options</code>.</dd>
388388

389389

390+
<dt class="option-term" id="option-cargo-rustdoc---output-format"><a class="option-anchor" href="#option-cargo-rustdoc---output-format"></a><code>--output-format</code></dt>
391+
<dd class="option-desc">The output type to write.
392+
Unstable, requires <code>-Zunstable-options</code>.</dd>
393+
394+
390395
</dl>
391396

392397
## ENVIRONMENT

src/etc/man/cargo-doc.1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@ Build as many crates in the dependency graph as possible, rather than aborting
371371
the build on the first one that fails to build. Unstable, requires
372372
\fB\-Zunstable\-options\fR\&.
373373
.RE
374+
.sp
375+
\fB\-\-output\-format\fR
376+
.RS 4
377+
The output type to write.
378+
Unstable, requires \fB\-Zunstable\-options\fR\&.
379+
.RE
374380
.SH "ENVIRONMENT"
375381
See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/environment\-variables.html> for
376382
details on environment variables that Cargo reads.

src/etc/man/cargo-rustdoc.1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,12 @@ Build as many crates in the dependency graph as possible, rather than aborting
390390
the build on the first one that fails to build. Unstable, requires
391391
\fB\-Zunstable\-options\fR\&.
392392
.RE
393+
.sp
394+
\fB\-\-output\-format\fR
395+
.RS 4
396+
The output type to write.
397+
Unstable, requires \fB\-Zunstable\-options\fR\&.
398+
.RE
393399
.SH "ENVIRONMENT"
394400
See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/environment\-variables.html> for
395401
details on environment variables that Cargo reads.

tests/testsuite/rustdoc.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,58 @@ fn rustdoc_simple() {
2020
.run();
2121
}
2222

23+
#[cargo_test(nightly, reason = "--output-format is unstable")]
24+
fn rustdoc_simple_json() {
25+
let p = project().file("src/lib.rs", "").build();
26+
27+
p.cargo("rustdoc -Z unstable-options --output-format json -v")
28+
.masquerade_as_nightly_cargo(&["-Zunstable-options"])
29+
.with_stderr(
30+
"\
31+
[DOCUMENTING] foo v0.0.1 ([CWD])
32+
[RUNNING] `rustdoc [..]--crate-name foo src/lib.rs [..]\
33+
-o [CWD]/target/doc \
34+
[..] \
35+
-L dependency=[CWD]/target/debug/deps [..]`
36+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
37+
",
38+
)
39+
.run();
40+
}
41+
42+
#[cargo_test(nightly, reason = "--output-format is unstable")]
43+
fn rustdoc_invalid_output_format() {
44+
let p = project().file("src/lib.rs", "").build();
45+
46+
p.cargo("rustdoc -Z unstable-options --output-format pdf -v")
47+
.masquerade_as_nightly_cargo(&["unstable-options"])
48+
.with_status(1)
49+
.with_stderr(
50+
"\
51+
error: invalid value 'pdf' for '--output-format <output-format>'
52+
[possible values: html, json]
53+
54+
For more information, try '--help'.
55+
",
56+
)
57+
.run();
58+
}
59+
60+
#[cargo_test(nightly, reason = "--output-format is unstable")]
61+
fn rustdoc_simple_json_fail() {
62+
let p = project().file("src/lib.rs", "").build();
63+
64+
p.cargo("rustdoc -Z unstable-options --output-format json -v")
65+
.with_status(101)
66+
.with_stderr(
67+
"\
68+
error: the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel
69+
[..]
70+
",
71+
)
72+
.run();
73+
}
74+
2375
#[cargo_test]
2476
fn rustdoc_args() {
2577
let p = project().file("src/lib.rs", "").build();

0 commit comments

Comments
 (0)