Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl fmt::Debug for Options {
#[derive(Clone, Debug)]
pub(crate) struct RenderOptions {
/// Output directory to generate docs into. Defaults to `doc`.
pub(crate) output: PathBuf,
pub(crate) output: Output,
/// External files to insert into generated pages.
pub(crate) external_html: ExternalHtml,
/// A pre-populated `IdMap` with the default headings and any headings added by Markdown files
Expand Down Expand Up @@ -288,9 +288,6 @@ pub(crate) struct RenderOptions {
pub(crate) no_emit_shared: bool,
/// If `true`, HTML source code pages won't be generated.
pub(crate) html_no_source: bool,
/// This field is only used for the JSON output. If it's set to true, no file will be created
/// and content will be displayed in stdout directly.
pub(crate) output_to_stdout: bool,
/// Whether we should read or write rendered cross-crate info in the doc root.
pub(crate) should_merge: ShouldMerge,
/// Path to crate-info for external crates.
Expand All @@ -303,6 +300,27 @@ pub(crate) struct RenderOptions {
pub(crate) generate_macro_expansion: bool,
}

#[derive(Clone, Debug)]
pub(crate) enum Output {
/// `-o` / `--output`
Output(PathBuf),
/// `--out-dir`
OutDir(PathBuf),
}

impl Output {
/// The output directory, assuming we're in the HTML backend.
///
/// This should *not* be called from the JSON backend, as that treets
/// `--output` and `--output-dir` differently
pub fn output_dir_html(&self) -> &Path {
match self {
Output::Output(o) => Path::new(o),
Output::OutDir(o) => Path::new(o),
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) enum ModuleSorting {
DeclarationOrder,
Expand Down Expand Up @@ -346,6 +364,11 @@ impl RenderOptions {
}
None
}

/// See [`Output::output_dir_html`].
pub(crate) fn output_dir_html(&self) -> &Path {
self.output.output_dir_html()
}
}

/// Create the input (string or file path)
Expand Down Expand Up @@ -632,18 +655,15 @@ impl Options {
dcx.fatal("the `--test` flag must be passed to enable `--no-run`");
}

let mut output_to_stdout = false;
let test_builder_wrappers =
matches.opt_strs("test-builder-wrapper").iter().map(PathBuf::from).collect();
let output = match (matches.opt_str("out-dir"), matches.opt_str("output")) {
(Some(_), Some(_)) => {
dcx.fatal("cannot use both 'out-dir' and 'output' at once");
}
(Some(out_dir), None) | (None, Some(out_dir)) => {
output_to_stdout = out_dir == "-";
PathBuf::from(out_dir)
}
(None, None) => PathBuf::from("doc"),
(Some(out_dir), None) => Output::OutDir(PathBuf::from(out_dir)),
(None, Some(output)) => Output::Output(PathBuf::from(output)),
(None, None) => Output::OutDir(PathBuf::from("doc")),
};

let cfgs = matches.opt_strs("cfg");
Expand Down Expand Up @@ -897,7 +917,6 @@ impl Options {
call_locations,
no_emit_shared: false,
html_no_source,
output_to_stdout,
should_merge,
include_parts_dir,
parts_out_dir,
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/formats/cache.rs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an alternative here: #83784 (comment).

What about we expanding --emit to have per-emit-type output path. That is pretty similar to rustc --emit. Having a similar behavior across for the same CLI options could be a win and lower the learning cost. That we also can cut off two CLI options (--output-format and this --output options)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, that's worth at least considering. It might also resolve that --output-format=json is used both for "major mode" settings like json and doctest, but also "minor mode" like when giving doc-coverage information.

Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl Cache {
cx.cache.traits = mem::take(&mut krate.external_traits);

let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
let dst = &render_options.output;
let dst = render_options.output_dir_html(); // FIXME: This is sus for json

// Make `--extern-html-root-url` support the same names as `--extern` whenever possible
let cstore = CStore::from_tcx(tcx);
Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,12 +580,12 @@ impl<'tcx> Context<'tcx> {
expanded_codes,
};

let dst = output;
scx.ensure_dir(&dst)?;
let dst = output.output_dir_html();
scx.ensure_dir(dst)?;

let mut cx = Context {
current: Vec::new(),
dst,
dst: dst.to_path_buf(),
id_map: RefCell::new(id_map),
deref_id_map: Default::default(),
shared: scx,
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/html/render/write_shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use serde::{Deserialize, Serialize, Serializer};

use super::{Context, RenderMode, collect_paths_for_type, ensure_trailing_slash};
use crate::clean::{Crate, Item, ItemId, ItemKind};
use crate::config::{EmitType, PathToParts, RenderOptions, ShouldMerge};
use crate::config::{self, EmitType, PathToParts, RenderOptions, ShouldMerge};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::Impl;
Expand Down Expand Up @@ -109,7 +109,7 @@ pub(crate) fn write_shared(
match &opt.index_page {
Some(index_page) if opt.enable_index_page => {
let mut md_opts = opt.clone();
md_opts.output = cx.dst.clone();
md_opts.output = config::Output::OutDir(cx.dst.clone());
md_opts.external_html = cx.shared.layout.external_html.clone();
try_err!(
crate::markdown::render_and_write(index_page, md_opts, cx.shared.edition()),
Expand Down
53 changes: 33 additions & 20 deletions src/librustdoc/json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use tracing::{debug, trace};

use crate::clean::ItemKind;
use crate::clean::types::{ExternalCrate, ExternalLocation};
use crate::config::RenderOptions;
use crate::config::{self, RenderOptions};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::FormatRenderer;
Expand All @@ -40,10 +40,7 @@ pub(crate) struct JsonRenderer<'tcx> {
/// A mapping of IDs that contains all local items for this crate which gets output as a top
/// level field of the JSON blob.
index: FxHashMap<types::Id, types::Item>,
/// The directory where the JSON blob should be written to.
///
/// If this is `None`, the blob will be printed to `stdout` instead.
out_dir: Option<PathBuf>,
output: config::Output,
cache: Rc<Cache>,
imported_items: DefIdSet,
id_interner: RefCell<ids::IdInterner>,
Expand Down Expand Up @@ -137,7 +134,7 @@ impl<'tcx> JsonRenderer<'tcx> {
JsonRenderer {
tcx,
index: FxHashMap::default(),
out_dir: if options.output_to_stdout { None } else { Some(options.output) },
output: options.output,
cache: Rc::new(cache),
imported_items,
id_interner: Default::default(),
Expand Down Expand Up @@ -316,20 +313,36 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
target,
format_version: types::FORMAT_VERSION,
};
if let Some(ref out_dir) = self.out_dir {
try_err!(create_dir_all(out_dir), out_dir);

let mut p = out_dir.clone();
p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
p.set_extension("json");

self.serialize_and_write(
output_crate,
try_err!(File::create_buffered(&p), p),
&p.display().to_string(),
)
} else {
self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "<stdout>")

match &self.output {
config::Output::OutDir(out_dir) => {
try_err!(create_dir_all(out_dir), out_dir);

let mut p = PathBuf::from(out_dir);
p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
p.set_extension("json");

self.serialize_and_write(
output_crate,
try_err!(File::create_buffered(&p), p),
&p.display().to_string(),
)
}
config::Output::Output(p) => {
if p == "-" {
self.serialize_and_write(
output_crate,
BufWriter::new(stdout().lock()),
"<stdout>",
)
} else {
self.serialize_and_write(
output_crate,
try_err!(File::create_buffered(p), p),
&p.display().to_string(),
)
}
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,12 @@ fn opts() -> Vec<RustcOptGroup> {
opt(
Stable,
Opt,
"",
"o",
"output",
"Which directory to place the output. This option is deprecated, use --out-dir instead.",
"PATH",
),
opt(Stable, Opt, "o", "out-dir", "which directory to place the output", "PATH"),
opt(Stable, Opt, "", "out-dir", "which directory to place the output", "PATH"),
opt(Stable, Opt, "", "crate-name", "specify the name of this crate", "NAME"),
make_crate_type_option(),
opt(Stable, Multi, "L", "library-path", "directory to add to crate search path", "DIR"),
Expand Down Expand Up @@ -757,7 +757,7 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
let include_sources = !opt.html_no_source;
html::render::write_not_crate_specific(
&crates,
&opt.output,
&opt.output_dir_html(),
&opt,
&opt.themes,
opt.extension_css.as_deref(),
Expand Down
6 changes: 3 additions & 3 deletions src/librustdoc/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
options: RenderOptions,
edition: Edition,
) -> Result<(), String> {
if let Err(e) = create_dir_all(&options.output) {
return Err(format!("{output}: {e}", output = options.output.display()));
let mut output = options.output_dir_html().to_path_buf();
if let Err(e) = create_dir_all(&output) {
return Err(format!("{output}: {e}", output = output.display()));
}

let input = input.as_ref();
let mut output = options.output;
output.push(input.file_name().unwrap());
output.set_extension("html");

Expand Down
9 changes: 2 additions & 7 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ impl<'test> TestCx<'test> {
.arg(self.config.run_lib_path.as_path())
.arg("-L")
.arg(aux_dir)
.arg("-o")
.arg("--out-dir")
.arg(out_dir.as_ref())
.arg("--deny")
.arg("warnings")
Expand Down Expand Up @@ -1806,12 +1806,7 @@ impl<'test> TestCx<'test> {
rustc.arg("-o").arg(path);
}
TargetLocation::ThisDirectory(path) => {
if is_rustdoc {
// `rustdoc` uses `-o` for the output directory.
rustc.arg("-o").arg(path);
} else {
rustc.arg("--out-dir").arg(path);
}
rustc.arg("--out-dir").arg(path);
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/run-make/rustdoc-default-output/output-default.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Options:
-v, --verbose use verbose output
-w, --output-format [html]
the output type to write
--output PATH Which directory to place the output. This option is
-o, --output PATH Which directory to place the output. This option is
deprecated, use --out-dir instead.
-o, --out-dir PATH which directory to place the output
--out-dir PATH which directory to place the output
--crate-name NAME
specify the name of this crate
--crate-type <bin|lib|rlib|dylib|cdylib|staticlib|proc-macro>
Expand Down
22 changes: 14 additions & 8 deletions tests/run-make/rustdoc-output-stdout/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,22 @@ use run_make_support::path_helpers::{cwd, has_extension, read_dir_entries_recurs
use run_make_support::{rustdoc, serde_json};

fn main() {
check("-o");
check("--output");

// Then we check it didn't generate any JSON file.
read_dir_entries_recursive(cwd(), |path| {
if path.is_file() && has_extension(path, "json") {
panic!("Found a JSON file {path:?}");
}
});
}

fn check(out_arg: &str) {
let json_string = rustdoc()
.input("foo.rs")
.out_dir("-")
.arg(out_arg)
.arg("-")
.arg("-Zunstable-options")
.output_format("json")
.run()
Expand All @@ -26,11 +39,4 @@ fn main() {
.as_i64()
.expect("json output should contain format_version field");
assert!(format_version > 30);

// Then we check it didn't generate any JSON file.
read_dir_entries_recursive(cwd(), |path| {
if path.is_file() && has_extension(path, "json") {
panic!("Found a JSON file {path:?}");
}
});
}
Loading