From de48fc6a5620f804a5c7facf3b0274a1d807686e Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 15 Apr 2026 20:27:12 -0700 Subject: [PATCH] rustdoc: fix a few spots where emit isn't respected --- src/librustdoc/html/render/write_shared.rs | 52 +++++++++--------- src/librustdoc/lib.rs | 7 ++- .../{theme.css => custom_theme.css} | 0 tests/run-make/rustdoc-dep-info/rmake.rs | 53 +++++++++++++++---- 4 files changed, 77 insertions(+), 35 deletions(-) rename tests/run-make/rustdoc-dep-info/{theme.css => custom_theme.css} (100%) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 8cb43e002870..8de899ea0eef 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -153,7 +153,7 @@ pub(crate) fn write_not_crate_specific( include_sources: bool, ) -> Result<(), Error> { write_rendered_cross_crate_info(crates, dst, opt, include_sources, resource_suffix)?; - write_static_files(dst, opt, style_files, css_file_extension, resource_suffix)?; + write_resources(dst, opt, style_files, css_file_extension, resource_suffix)?; Ok(()) } @@ -183,43 +183,45 @@ fn write_rendered_cross_crate_info( /// Writes the static files, the style files, and the css extensions. /// Have to be careful about these, because they write to the root out dir. -fn write_static_files( +fn write_resources( dst: &Path, opt: &RenderOptions, style_files: &[StylePath], css_file_extension: Option<&Path>, resource_suffix: &str, ) -> Result<(), Error> { - let static_dir = dst.join("static.files"); - try_err!(fs::create_dir_all(&static_dir), &static_dir); + if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlNonStaticFiles) { + // Handle added third-party themes + for entry in style_files { + let theme = entry.basename()?; + let extension = + try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path); - // Handle added third-party themes - for entry in style_files { - let theme = entry.basename()?; - let extension = - try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path); + // Skip the official themes. They are written below as part of STATIC_FILES_LIST. + if matches!(theme.as_str(), "light" | "dark" | "ayu") { + continue; + } - // Skip the official themes. They are written below as part of STATIC_FILES_LIST. - if matches!(theme.as_str(), "light" | "dark" | "ayu") { - continue; + let bytes = try_err!(fs::read(&entry.path), &entry.path); + let filename = format!("{theme}{resource_suffix}.{extension}"); + let dst_filename = dst.join(filename); + try_err!(fs::write(&dst_filename, bytes), &dst_filename); } - let bytes = try_err!(fs::read(&entry.path), &entry.path); - let filename = format!("{theme}{resource_suffix}.{extension}"); - let dst_filename = dst.join(filename); - try_err!(fs::write(&dst_filename, bytes), &dst_filename); - } - - // When the user adds their own CSS files with --extend-css, we write that as an - // invocation-specific file (that is, with a resource suffix). - if let Some(css) = css_file_extension { - let buffer = try_err!(fs::read_to_string(css), css); - let path = static_files::suffix_path("theme.css", resource_suffix); - let dst_path = dst.join(path); - try_err!(fs::write(&dst_path, buffer), &dst_path); + // When the user adds their own CSS files with --extend-css, we write that as an + // invocation-specific file (that is, with a resource suffix). + if let Some(css) = css_file_extension { + let buffer = try_err!(fs::read_to_string(css), css); + let path = static_files::suffix_path("theme.css", resource_suffix); + let dst_path = dst.join(path); + try_err!(fs::write(&dst_path, buffer), &dst_path); + } } if opt.emit.is_empty() || opt.emit.contains(&EmitType::HtmlStaticFiles) { + let static_dir = dst.join("static.files"); + try_err!(fs::create_dir_all(&static_dir), &static_dir); + static_files::for_each(|f: &static_files::StaticFile| { let filename = static_dir.join(f.output_filename()); let contents: &[u8] = diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 750ce27ea796..87de4244b5c8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -81,6 +81,7 @@ use tracing::info; use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION; +use crate::config::EmitType; use crate::error::Error; use crate::formats::cache::Cache; @@ -868,7 +869,11 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { }; rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { let has_dep_info = render_options.dep_info().is_some(); - markdown::render_and_write(file, render_options, edition)?; + if render_options.emit.contains(&EmitType::HtmlNonStaticFiles) + || render_options.emit.is_empty() + { + markdown::render_and_write(file, render_options, edition)?; + } if has_dep_info { // Register the loaded external files in the source map so they show up in depinfo. // We can't load them via the source map because it gets created after we process the options. diff --git a/tests/run-make/rustdoc-dep-info/theme.css b/tests/run-make/rustdoc-dep-info/custom_theme.css similarity index 100% rename from tests/run-make/rustdoc-dep-info/theme.css rename to tests/run-make/rustdoc-dep-info/custom_theme.css diff --git a/tests/run-make/rustdoc-dep-info/rmake.rs b/tests/run-make/rustdoc-dep-info/rmake.rs index 233225fde869..fbeac251f5f9 100644 --- a/tests/run-make/rustdoc-dep-info/rmake.rs +++ b/tests/run-make/rustdoc-dep-info/rmake.rs @@ -9,8 +9,6 @@ fn main() { rfs::create_dir("doc"); - // We're only emitting dep info, so we shouldn't be running static analysis to - // figure out that this program is erroneous. // Ensure that all kinds of input reading flags end up in dep-info. rustdoc() .input("lib.rs") @@ -18,7 +16,7 @@ fn main() { .arg("--html-before-content=before.html") .arg("--markdown-after-content=after.md") .arg("--extend-css=extend.css") - .arg("--theme=theme.css") + .arg("--theme=custom_theme.css") .arg("--index-page=index-page.md") .emit("dep-info") .run(); @@ -31,8 +29,31 @@ fn main() { assert_contains(&content, "after.md:"); assert_contains(&content, "before.html:"); assert_contains(&content, "extend.css:"); - assert_contains(&content, "theme.css:"); + assert_contains(&content, "custom_theme.css:"); assert_contains(&content, "index-page.md:"); + // Only emit dep-info. Don't emit the actual page. + assert!(!path("doc/foo/index.html").exists()); + assert!(!path("doc/custom_theme.css").exists()); + // weird that --extend-css generates a file named theme.css + assert!(!path("doc/theme.css").exists()); + + // Now try emitting dep-info and html files at the same time. + rustdoc() + .input("lib.rs") + .arg("-Zunstable-options") + .arg("--html-before-content=before.html") + .arg("--markdown-after-content=after.md") + .arg("--extend-css=extend.css") + .arg("--theme=custom_theme.css") + .arg("--index-page=index-page.md") + .emit("dep-info,html-non-static-files,html-static-files") + .run(); + assert!(path("doc/foo/index.html").exists()); + // These files are copied into the doc output folder, + // which is why they show up in dep-info. + assert!(path("doc/custom_theme.css").exists()); + // weird that --extend-css generates a file named theme.css + assert!(path("doc/theme.css").exists()); // Now we check that we can provide a file name to the `dep-info` argument. rustdoc().input("lib.rs").arg("-Zunstable-options").emit("dep-info=bla.d").run(); @@ -72,7 +93,9 @@ fn main() { assert_not_contains(&content, "after.md:"); assert_not_contains(&content, "before.html:"); assert_not_contains(&content, "extend.css:"); - assert_not_contains(&content, "theme.css:"); + assert_not_contains(&content, "custom_theme.css:"); + // Only emit dep-info, not the actual html. + assert!(!path("doc/example.html").exists()); // combine --emit=dep-info=filename with plain markdown input rustdoc() @@ -81,10 +104,12 @@ fn main() { .arg("--html-before-content=before.html") .arg("--markdown-after-content=after.md") .arg("--extend-css=extend.css") - .arg("--theme=theme.css") + .arg("--theme=custom_theme.css") + .arg("--markdown-css=markdown.css") .arg("--index-page=index-page.md") - .emit("dep-info=example.d") + .emit("dep-info=example.d,html-non-static-files,html-static-files") .run(); + assert!(path("doc/example.html").exists()); let content = rfs::read_to_string("example.d"); assert_contains(&content, "example.md:"); assert_not_contains(&content, "lib.rs:"); @@ -93,7 +118,17 @@ fn main() { assert_not_contains(&content, "doc.md:"); assert_contains(&content, "after.md:"); assert_contains(&content, "before.html:"); - assert_contains(&content, "extend.css:"); - assert_contains(&content, "theme.css:"); assert_contains(&content, "index-page.md:"); + // This is a hotlink, not a file that gets copied, + // so it shouldn't add to the dep-info, it shouldn't be copied, + // and it shouldn't be resolved relative to the root path. + // + // It's weird that this is different from the other two css + // files, but it's stable, so I can't change it. + assert!(!path("doc/markdown.css").exists()); + assert_not_contains(&content, "markdown.css:"); + // These files aren't actually used, and the fact that they show up + // is arguably a bug, but test it anyway. + assert_contains(&content, "extend.css:"); + assert_contains(&content, "custom_theme.css:"); }