Skip to content

Commit

Permalink
Add unstable --output-format option to "rustdoc"
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
charmitro committed Jun 30, 2023
1 parent 5b377ce commit bd9ff5b
Show file tree
Hide file tree
Showing 18 changed files with 171 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
let ws = args.workspace(config)?;
let mode = CompileMode::Doc {
deps: !args.flag("no-deps"),
json: false,
};
let mut compile_opts =
args.compile_options(config, mode, Some(&ws), ProfileChecking::Custom)?;
compile_opts.rustdoc_document_private_items = args.flag("document-private-items");

let doc_opts = DocOptions {
open_result: args.flag("open"),
output_format: ops::OutputFormat::Html,
compile_opts,
};
ops::doc(&ws, &doc_opts)?;
Expand Down
32 changes: 29 additions & 3 deletions src/bin/cargo/commands/rustdoc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use cargo::ops::{self, DocOptions};
use std::str::FromStr;

use cargo::ops::{self, DocOptions, OutputFormat};

use crate::command_prelude::*;

Expand Down Expand Up @@ -35,6 +37,10 @@ pub fn cli() -> Command {
.arg_features()
.arg_target_triple("Build for the target triple")
.arg_target_dir()
.arg(
opt("output-format", "the output type to write (unstable)")
.value_parser(["html", "json"]),
)
.arg_manifest_path()
.arg_message_format()
.arg_unit_graph()
Expand All @@ -45,20 +51,40 @@ pub fn cli() -> Command {

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
let ws = args.workspace(config)?;
let output_format = if let Some(output_format) = args._value_of("output-format") {
OutputFormat::from_str(output_format).unwrap()
} else {
OutputFormat::Html
};
let mut compile_opts = args.compile_options_for_single_package(
config,
CompileMode::Doc { deps: false },
CompileMode::Doc {
deps: false,
json: matches!(output_format, OutputFormat::Json),
},
Some(&ws),
ProfileChecking::Custom,
)?;
let target_args = values(args, "args");
let mut target_args = values(args, "args");

if matches!(output_format, OutputFormat::Json) {
config
.cli_unstable()
.fail_if_stable_opt("--output-format", 12103)?;
// Not sure about this. @charmitro
target_args.push("-Zunstable-options".to_string());
target_args.push("--output-format=json".to_string());
}

compile_opts.target_rustdoc_args = if target_args.is_empty() {
None
} else {
Some(target_args)
};

let doc_opts = DocOptions {
open_result: args.flag("open"),
output_format: OutputFormat::Html,
compile_opts,
};
ops::doc(&ws, &doc_opts)?;
Expand Down
3 changes: 2 additions & 1 deletion src/cargo/core/compiler/build_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ pub enum CompileMode {
Bench,
/// A target that will be documented with `rustdoc`.
/// If `deps` is true, then it will also document all dependencies.
Doc { deps: bool },
/// if `json` is true, the documentation output is in json format.
Doc { deps: bool, json: bool },
/// A target that will be tested with `rustdoc`.
Doctest,
/// An example or library that will be scraped for function calls by `rustdoc`.
Expand Down
15 changes: 10 additions & 5 deletions src/cargo/core/compiler/context/compilation_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,16 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
bcx: &BuildContext<'a, 'cfg>,
) -> CargoResult<Arc<Vec<OutputFile>>> {
let ret = match unit.mode {
CompileMode::Doc { .. } => {
let path = self
.out_dir(unit)
.join(unit.target.crate_name())
.join("index.html");
CompileMode::Doc { json, .. } => {
let path = if json {
self.out_dir(unit)
.join(format!("{}.json", unit.target.crate_name()))
} else {
self.out_dir(unit)
.join(unit.target.crate_name())
.join("index.html")
};

vec![OutputFile {
path,
hardlink: None,
Expand Down
6 changes: 5 additions & 1 deletion src/cargo/core/compiler/unit_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,11 @@ fn compute_deps_doc(
)?;
ret.push(lib_unit_dep);
if dep_lib.documented() {
if let CompileMode::Doc { deps: true } = unit.mode {
if let CompileMode::Doc {
deps: true,
json: true | false,
} = unit.mode
{
// Document this lib as well.
let doc_unit_dep = new_unit_dep(
state,
Expand Down
7 changes: 6 additions & 1 deletion src/cargo/ops/cargo_compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,12 @@ pub fn create_bcx<'a, 'cfg>(

// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
// what heuristics to use in that case.
if build_config.mode == (CompileMode::Doc { deps: true }) {
if build_config.mode
== (CompileMode::Doc {
deps: true,
json: true || false,
})
{
remove_duplicate_doc(build_config, &units, &mut unit_graph);
}

Expand Down
31 changes: 30 additions & 1 deletion src/cargo/ops/cargo_doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,50 @@ use crate::util::CargoResult;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;

/// Format of rustdoc [`--output-format`][1].
///
/// [1]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#-w--output-format-output-format
#[derive(Debug, Default, Clone)]
pub enum OutputFormat {
#[default]
Html,
Json,
}

impl FromStr for OutputFormat {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"json" => Ok(Self::Json),
"html" => Ok(Self::Html),
_ => Err(()),
}
}
}

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

/// Main method for `cargo doc`.
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
if options.open_result && matches!(options.output_format, OutputFormat::Json) {
anyhow::bail!("`--open` is not allowed with `json` output format.");
}

let compilation = ops::compile(ws, &options.compile_opts)?;

if options.open_result {
if options.open_result && matches!(options.output_format, OutputFormat::Html) {
let name = &compilation
.root_crate_names
.get(0)
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub use self::cargo_compile::{
compile, compile_with_exec, compile_ws, create_bcx, print, resolve_all_features, CompileOptions,
};
pub use self::cargo_compile::{CompileFilter, FilterRule, LibRule, Packages};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_doc::{doc, DocOptions, OutputFormat};
pub use self::cargo_fetch::{fetch, FetchOptions};
pub use self::cargo_generate_lockfile::generate_lockfile;
pub use self::cargo_generate_lockfile::update_lockfile;
Expand Down
1 change: 1 addition & 0 deletions src/doc/man/cargo-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ and supports common Unix glob patterns.
{{#options}}
{{> options-jobs }}
{{> options-keep-going }}
{{> options-output-format }}
{{/options}}

{{> section-environment }}
Expand Down
1 change: 1 addition & 0 deletions src/doc/man/cargo-rustdoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ if its name is the same as the lib target. Binaries are skipped if they have
{{#options}}
{{> options-jobs }}
{{> options-keep-going }}
{{> options-output-format }}
{{/options}}

{{> section-environment }}
Expand Down
3 changes: 3 additions & 0 deletions src/doc/man/generated_txt/cargo-doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ OPTIONS
than aborting the build on the first one that fails to build.
Unstable, requires -Zunstable-options.

--output-format
The output type to write. Unstable, requires -Zunstable-options.

ENVIRONMENT
See the reference
<https://doc.rust-lang.org/cargo/reference/environment-variables.html>
Expand Down
3 changes: 3 additions & 0 deletions src/doc/man/generated_txt/cargo-rustdoc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ OPTIONS
than aborting the build on the first one that fails to build.
Unstable, requires -Zunstable-options.

--output-format
The output type to write. Unstable, requires -Zunstable-options.

ENVIRONMENT
See the reference
<https://doc.rust-lang.org/cargo/reference/environment-variables.html>
Expand Down
4 changes: 4 additions & 0 deletions src/doc/man/includes/options-output-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{#option "`--output-format`"}}
The output type to write.
Unstable, requires `-Zunstable-options`.
{{/option}}
5 changes: 5 additions & 0 deletions src/doc/src/commands/cargo-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ the build on the first one that fails to build. Unstable, requires
<code>-Zunstable-options</code>.</dd>


<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>
<dd class="option-desc">The output type to write.
Unstable, requires <code>-Zunstable-options</code>.</dd>


</dl>

## ENVIRONMENT
Expand Down
5 changes: 5 additions & 0 deletions src/doc/src/commands/cargo-rustdoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,11 @@ the build on the first one that fails to build. Unstable, requires
<code>-Zunstable-options</code>.</dd>


<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>
<dd class="option-desc">The output type to write.
Unstable, requires <code>-Zunstable-options</code>.</dd>


</dl>

## ENVIRONMENT
Expand Down
6 changes: 6 additions & 0 deletions src/etc/man/cargo-doc.1
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,12 @@ Build as many crates in the dependency graph as possible, rather than aborting
the build on the first one that fails to build. Unstable, requires
\fB\-Zunstable\-options\fR\&.
.RE
.sp
\fB\-\-output\-format\fR
.RS 4
The output type to write.
Unstable, requires \fB\-Zunstable\-options\fR\&.
.RE
.SH "ENVIRONMENT"
See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/environment\-variables.html> for
details on environment variables that Cargo reads.
Expand Down
6 changes: 6 additions & 0 deletions src/etc/man/cargo-rustdoc.1
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,12 @@ Build as many crates in the dependency graph as possible, rather than aborting
the build on the first one that fails to build. Unstable, requires
\fB\-Zunstable\-options\fR\&.
.RE
.sp
\fB\-\-output\-format\fR
.RS 4
The output type to write.
Unstable, requires \fB\-Zunstable\-options\fR\&.
.RE
.SH "ENVIRONMENT"
See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/environment\-variables.html> for
details on environment variables that Cargo reads.
Expand Down
52 changes: 52 additions & 0 deletions tests/testsuite/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,58 @@ fn rustdoc_simple() {
.run();
}

#[cargo_test(nightly, reason = "--output-format is unstable")]
fn rustdoc_simple_json() {
let p = project().file("src/lib.rs", "").build();

p.cargo("rustdoc -Z unstable-options --output-format json -v")
.masquerade_as_nightly_cargo(&["-Zunstable-options"])
.with_stderr(
"\
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc [..]--crate-name foo src/lib.rs [..]\
-o [CWD]/target/doc \
[..] \
-L dependency=[CWD]/target/debug/deps [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
)
.run();
}

#[cargo_test(nightly, reason = "--output-format is unstable")]
fn rustdoc_invalid_output_format() {
let p = project().file("src/lib.rs", "").build();

p.cargo("rustdoc -Z unstable-options --output-format pdf -v")
.masquerade_as_nightly_cargo(&["unstable-options"])
.with_status(1)
.with_stderr(
"\
error: invalid value 'pdf' for '--output-format <output-format>'
[possible values: html, json]
For more information, try '--help'.
",
)
.run();
}

#[cargo_test(nightly, reason = "--output-format is unstable")]
fn rustdoc_simple_json_fail() {
let p = project().file("src/lib.rs", "").build();

p.cargo("rustdoc -Z unstable-options --output-format json -v")
.with_status(101)
.with_stderr(
"\
error: the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel
[..]
",
)
.run();
}

#[cargo_test]
fn rustdoc_args() {
let p = project().file("src/lib.rs", "").build();
Expand Down

0 comments on commit bd9ff5b

Please sign in to comment.