diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index ecb6378f31fb4..a7a2db6210005 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -3,6 +3,7 @@ use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; +use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType}; @@ -266,6 +267,34 @@ crate struct RenderOptions { /// If `true`, generate a JSON file in the crate folder instead of HTML redirection files. crate generate_redirect_map: bool, crate unstable_features: rustc_feature::UnstableFeatures, + crate emit: Vec, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +crate enum EmitType { + Unversioned, + Toolchain, + CrateSpecific, +} + +impl FromStr for EmitType { + type Err = (); + + fn from_str(s: &str) -> Result { + use EmitType::*; + match s { + "unversioned-shared-resources" => Ok(Unversioned), + "toolchain-shared-resources" => Ok(Toolchain), + "crate-specific" => Ok(CrateSpecific), + _ => Err(()), + } + } +} + +impl RenderOptions { + crate fn should_emit_crate(&self) -> bool { + self.emit.is_empty() || self.emit.contains(&EmitType::CrateSpecific) + } } impl Options { @@ -334,6 +363,19 @@ impl Options { // check for deprecated options check_deprecated_options(&matches, &diag); + let mut emit = Vec::new(); + for list in matches.opt_strs("emit") { + for kind in list.split(',') { + match kind.parse() { + Ok(kind) => emit.push(kind), + Err(()) => { + diag.err(&format!("unrecognized emission type: {}", kind)); + return Err(1); + } + } + } + } + let to_check = matches.opt_strs("check-theme"); if !to_check.is_empty() { let paths = theme::load_css_paths(static_files::themes::LIGHT.as_bytes()); @@ -641,6 +683,7 @@ impl Options { unstable_features: rustc_feature::UnstableFeatures::from_environment( crate_name.as_deref(), ), + emit, }, crate_name, output_format, diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 9dcef3a20d6c0..f0b390add73d5 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -58,10 +58,15 @@ crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( ) -> Result<(), Error> { let prof = &tcx.sess.prof; + let emit_crate = options.should_emit_crate(); let (mut format_renderer, krate) = prof .extra_verbose_generic_activity("create_renderer", T::descr()) .run(|| T::init(krate, options, edition, cache, tcx))?; + if !emit_crate { + return Ok(()); + } + // Render the crate documentation let crate_name = krate.name; let mut work = vec![(format_renderer.make_child_renderer(), krate.module)]; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 468bd9997a64a..17cedeb5a511a 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -288,6 +288,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { ) -> Result<(Self, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); + let emit_crate = options.should_emit_crate(); let RenderOptions { output, external_html, @@ -393,7 +394,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let dst = output; scx.ensure_dir(&dst)?; - krate = sources::render(&dst, &mut scx, krate)?; + if emit_crate { + krate = sources::render(&dst, &mut scx, krate)?; + } // Build our search index let index = build_index(&krate, &mut cache, tcx); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 2ab423c238c40..af346bb82256e 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -13,7 +13,7 @@ use serde::Serialize; use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS}; use crate::clean::Crate; -use crate::config::RenderOptions; +use crate::config::{EmitType, RenderOptions}; use crate::docfs::PathError; use crate::error::Error; use crate::formats::FormatRenderer; @@ -72,6 +72,18 @@ impl SharedResource<'_> { SharedResource::CrateSpecific { basename } => cx.suffix_path(basename), } } + + fn should_emit(&self, emit: &[EmitType]) -> bool { + if emit.is_empty() { + return true; + } + let kind = match self { + SharedResource::Unversioned { .. } => EmitType::Unversioned, + SharedResource::ToolchainSpecific { .. } => EmitType::Toolchain, + SharedResource::CrateSpecific { .. } => EmitType::CrateSpecific, + }; + emit.contains(&kind) + } } impl Context<'_> { @@ -86,9 +98,17 @@ impl Context<'_> { self.dst.join(&filename) } - fn write_shared>(&self, resource: SharedResource<'_>, contents: C) -> Result<(), Error> - { - self.shared.fs.write(resource.path(self), contents) + fn write_shared>( + &self, + resource: SharedResource<'_>, + contents: C, + emit: &[EmitType], + ) -> Result<(), Error> { + if resource.should_emit(emit) { + self.shared.fs.write(resource.path(self), contents) + } else { + Ok(()) + } } fn write_minify( @@ -96,6 +116,7 @@ impl Context<'_> { resource: SharedResource<'_>, contents: &str, minify: bool, + emit: &[EmitType], ) -> Result<(), Error> { let tmp; let contents = if minify { @@ -111,7 +132,7 @@ impl Context<'_> { contents.as_bytes() }; - self.write_shared(resource, contents) + self.write_shared(resource, contents, emit) } } @@ -133,10 +154,14 @@ pub(super) fn write_shared( SharedResource::ToolchainSpecific { basename: p }, c, options.enable_minification, + &options.emit, ) }; - let write_toolchain = - |p: &_, c: &_| cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c); + let write_toolchain = |p: &_, c: &_| { + cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit) + }; + let write_crate = + |p, c: &_| cx.write_shared(SharedResource::CrateSpecific { basename: p }, c, &options.emit); // Add all the static files. These may already exist, but we just // overwrite them anyway to make sure that they're fresh and up-to-date. @@ -214,7 +239,7 @@ pub(super) fn write_shared( } write_minify("normalize.css", static_files::NORMALIZE_CSS)?; for (name, contents) in &*FILES_UNVERSIONED { - cx.write_shared(SharedResource::Unversioned { name }, contents)?; + cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?; } fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec, Vec)> { @@ -354,7 +379,7 @@ pub(super) fn write_shared( "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n", all_sources.join("\n") ); - cx.write_shared(SharedResource::CrateSpecific { basename: "source-files.js" }, v)?; + write_crate("source-files.js", &v)?; } // Update the search index and crate list. @@ -371,12 +396,12 @@ pub(super) fn write_shared( let mut v = String::from("var searchIndex = JSON.parse('{\\\n"); v.push_str(&all_indexes.join(",\\\n")); v.push_str("\\\n}');\ninitSearch(searchIndex);"); - cx.write_shared(SharedResource::CrateSpecific { basename: "search-index.js" }, v)?; + write_crate("search-index.js", &v)?; } let crate_list = format!("window.ALL_CRATES = [{}];", krates.iter().map(|k| format!("\"{}\"", k)).join(",")); - cx.write_shared(SharedResource::CrateSpecific { basename: "crates.js" }, crate_list)?; + write_crate("crates.js", &crate_list)?; if options.enable_index_page { if let Some(index_page) = options.index_page.clone() { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index dabc21e3a447c..ebdd56611db71 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -527,6 +527,14 @@ fn opts() -> Vec { unstable("print", |o| { o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]") }), + unstable("emit", |o| { + o.optmulti( + "", + "emit", + "Comma separated list of types of output for rustdoc to emit", + "[unversioned-shared-resources,toolchain-shared-resources,crate-specific]", + ) + }), ] } diff --git a/src/test/run-make/emit-shared-files/Makefile b/src/test/run-make/emit-shared-files/Makefile new file mode 100644 index 0000000000000..06358f6eb2c98 --- /dev/null +++ b/src/test/run-make/emit-shared-files/Makefile @@ -0,0 +1,32 @@ +-include ../../run-make-fulldeps/tools.mk + +CRATE_ONLY = $(TMPDIR)/crate-only +TOOLCHAIN_ONLY = $(TMPDIR)/toolchain-only +ALL_SHARED = $(TMPDIR)/all-shared + +all: crate-only toolchain-only all-shared + +crate-only: + $(RUSTDOC) -Z unstable-options --emit=crate-specific --output $(CRATE_ONLY) --resource-suffix=-xxx x.rs + [ -e $(CRATE_ONLY)/search-index-xxx.js ] + [ -e $(CRATE_ONLY)/settings.html ] + [ -e $(CRATE_ONLY)/x/all.html ] + [ -e $(CRATE_ONLY)/x/index.html ] + ! [ -e $(CRATE_ONLY)/storage-xxx.js ] + ! [ -e $(CRATE_ONLY)/SourceSerifPro-It.ttf.woff ] + +toolchain-only: + $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx x.rs + [ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ] + ! [ -e $(TOOLCHAIN_ONLY)/SourceSerifPro-It.ttf.woff ] + ! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ] + ! [ -e $(TOOLCHAIN_ONLY)/x/index.html ] + +all-shared: + $(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx x.rs + [ -e $(ALL_SHARED)/storage-xxx.js ] + [ -e $(ALL_SHARED)/SourceSerifPro-It.ttf.woff ] + ! [ -e $(ALL_SHARED)/search-index-xxx.js ] + ! [ -e $(ALL_SHARED)/settings.html ] + ! [ -e $(ALL_SHARED)/x ] + ! [ -e $(ALL_SHARED)/src ] diff --git a/src/test/run-make/emit-shared-files/x.rs b/src/test/run-make/emit-shared-files/x.rs new file mode 100644 index 0000000000000..5df7576133a68 --- /dev/null +++ b/src/test/run-make/emit-shared-files/x.rs @@ -0,0 +1 @@ +// nothing to see here