Skip to content

Commit 7c89cc4

Browse files
committed
Add SharedResource abstraction and use it in write_shared
This cleans up the code quite a bit, and also makes the next commit much easier.
1 parent bba4088 commit 7c89cc4

File tree

2 files changed

+115
-115
lines changed

2 files changed

+115
-115
lines changed

src/librustdoc/html/render/context.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,6 @@ crate struct Context<'tcx> {
7979
rustc_data_structures::static_assert_size!(Context<'_>, 152);
8080

8181
impl<'tcx> Context<'tcx> {
82-
pub(super) fn path(&self, filename: &str) -> PathBuf {
83-
// We use splitn vs Path::extension here because we might get a filename
84-
// like `style.min.css` and we want to process that into
85-
// `style-suffix.min.css`. Path::extension would just return `css`
86-
// which would result in `style.min-suffix.css` which isn't what we
87-
// want.
88-
let (base, ext) = filename.split_once('.').unwrap();
89-
let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext);
90-
self.dst.join(&filename)
91-
}
92-
9382
pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
9483
self.shared.tcx
9584
}
@@ -487,7 +476,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
487476
|buf: &mut Buffer| all.print(buf),
488477
&self.shared.style_files,
489478
);
490-
self.shared.fs.write(&final_file, v.as_bytes())?;
479+
self.shared.fs.write(final_file, v.as_bytes())?;
491480

492481
// Generating settings page.
493482
page.title = "Rustdoc settings";

src/librustdoc/html/render/write_shared.rs

+114-103
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use serde::Serialize;
1414
use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
1515
use crate::clean::Crate;
1616
use crate::config::RenderOptions;
17-
use crate::docfs::{DocFS, PathError};
17+
use crate::docfs::PathError;
1818
use crate::error::Error;
1919
use crate::formats::FormatRenderer;
2020
use crate::html::{layout, static_files};
@@ -40,6 +40,81 @@ crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
4040
}
4141
});
4242

43+
enum SharedResource<'a> {
44+
/// This file will never change, no matter what toolchain is used to build it.
45+
///
46+
/// It does not have a resource suffix.
47+
Unversioned { name: &'a str },
48+
/// This file may change depending on the toolchain.
49+
///
50+
/// It has a resource suffix.
51+
ToolchainSpecific { basename: &'a str },
52+
/// This file may change for any crate within a build.
53+
///
54+
/// This differs from normal crate-specific files because it has a resource suffix.
55+
CrateSpecific { basename: &'a str },
56+
}
57+
58+
impl SharedResource<'_> {
59+
fn extension(&self) -> Option<&OsStr> {
60+
use SharedResource::*;
61+
match self {
62+
Unversioned { name }
63+
| ToolchainSpecific { basename: name }
64+
| CrateSpecific { basename: name } => Path::new(name).extension(),
65+
}
66+
}
67+
68+
fn path(&self, cx: &Context<'_>) -> PathBuf {
69+
match self {
70+
SharedResource::Unversioned { name } => cx.dst.join(name),
71+
SharedResource::ToolchainSpecific { basename } => cx.suffix_path(basename),
72+
SharedResource::CrateSpecific { basename } => cx.suffix_path(basename),
73+
}
74+
}
75+
}
76+
77+
impl Context<'_> {
78+
fn suffix_path(&self, filename: &str) -> PathBuf {
79+
// We use splitn vs Path::extension here because we might get a filename
80+
// like `style.min.css` and we want to process that into
81+
// `style-suffix.min.css`. Path::extension would just return `css`
82+
// which would result in `style.min-suffix.css` which isn't what we
83+
// want.
84+
let (base, ext) = filename.split_once('.').unwrap();
85+
let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext);
86+
self.dst.join(&filename)
87+
}
88+
89+
fn write_shared<C: AsRef<[u8]>>(&self, resource: SharedResource<'_>, contents: C) -> Result<(), Error>
90+
{
91+
self.shared.fs.write(resource.path(self), contents)
92+
}
93+
94+
fn write_minify(
95+
&self,
96+
resource: SharedResource<'_>,
97+
contents: &str,
98+
minify: bool,
99+
) -> Result<(), Error> {
100+
let tmp;
101+
let contents = if minify {
102+
tmp = if resource.extension() == Some(&OsStr::new("css")) {
103+
minifier::css::minify(contents).map_err(|e| {
104+
Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
105+
})?
106+
} else {
107+
minifier::js::minify(contents)
108+
};
109+
tmp.as_bytes()
110+
} else {
111+
contents.as_bytes()
112+
};
113+
114+
self.write_shared(resource, contents)
115+
}
116+
}
117+
43118
pub(super) fn write_shared(
44119
cx: &Context<'_>,
45120
krate: &Crate,
@@ -52,27 +127,22 @@ pub(super) fn write_shared(
52127
let lock_file = cx.dst.join(".lock");
53128
let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
54129

130+
// The weird `: &_` is to work around a borrowck bug: https://github.com/rust-lang/rust/issues/41078#issuecomment-293646723
131+
let write_minify = |p, c: &_| {
132+
cx.write_minify(
133+
SharedResource::ToolchainSpecific { basename: p },
134+
c,
135+
options.enable_minification,
136+
)
137+
};
138+
let write_toolchain =
139+
|p: &_, c: &_| cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c);
140+
55141
// Add all the static files. These may already exist, but we just
56142
// overwrite them anyway to make sure that they're fresh and up-to-date.
57-
58-
write_minify(
59-
&cx.shared.fs,
60-
cx.path("rustdoc.css"),
61-
static_files::RUSTDOC_CSS,
62-
options.enable_minification,
63-
)?;
64-
write_minify(
65-
&cx.shared.fs,
66-
cx.path("settings.css"),
67-
static_files::SETTINGS_CSS,
68-
options.enable_minification,
69-
)?;
70-
write_minify(
71-
&cx.shared.fs,
72-
cx.path("noscript.css"),
73-
static_files::NOSCRIPT_CSS,
74-
options.enable_minification,
75-
)?;
143+
write_minify("rustdoc.css", static_files::RUSTDOC_CSS)?;
144+
write_minify("settings.css", static_files::SETTINGS_CSS)?;
145+
write_minify("noscript.css", static_files::NOSCRIPT_CSS)?;
76146

77147
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
78148
// then we'll run over the "official" styles.
@@ -85,106 +155,66 @@ pub(super) fn write_shared(
85155

86156
// Handle the official themes
87157
match theme {
88-
"light" => write_minify(
89-
&cx.shared.fs,
90-
cx.path("light.css"),
91-
static_files::themes::LIGHT,
92-
options.enable_minification,
93-
)?,
94-
"dark" => write_minify(
95-
&cx.shared.fs,
96-
cx.path("dark.css"),
97-
static_files::themes::DARK,
98-
options.enable_minification,
99-
)?,
100-
"ayu" => write_minify(
101-
&cx.shared.fs,
102-
cx.path("ayu.css"),
103-
static_files::themes::AYU,
104-
options.enable_minification,
105-
)?,
158+
"light" => write_minify("light.css", static_files::themes::LIGHT)?,
159+
"dark" => write_minify("dark.css", static_files::themes::DARK)?,
160+
"ayu" => write_minify("ayu.css", static_files::themes::AYU)?,
106161
_ => {
107162
// Handle added third-party themes
108163
let content = try_err!(fs::read(&entry.path), &entry.path);
109-
cx.shared
110-
.fs
111-
.write(cx.path(&format!("{}.{}", theme, extension)), content.as_slice())?;
164+
// This is not exactly right: if compiled a second time with the same toolchain but different CLI args, the file could be different.
165+
// But docs.rs doesn't use this, so hopefully the issue doesn't come up.
166+
write_toolchain(&format!("{}.{}", theme, extension), content.as_slice())?;
112167
}
113168
};
114169

115170
themes.insert(theme.to_owned());
116171
}
117172

118-
let write = |p, c| cx.shared.fs.write(p, c);
119173
if (*cx.shared).layout.logo.is_empty() {
120-
write(cx.path("rust-logo.png"), static_files::RUST_LOGO)?;
174+
write_toolchain("rust-logo.png", static_files::RUST_LOGO)?;
121175
}
122176
if (*cx.shared).layout.favicon.is_empty() {
123-
write(cx.path("favicon.svg"), static_files::RUST_FAVICON_SVG)?;
124-
write(cx.path("favicon-16x16.png"), static_files::RUST_FAVICON_PNG_16)?;
125-
write(cx.path("favicon-32x32.png"), static_files::RUST_FAVICON_PNG_32)?;
177+
write_toolchain("favicon.svg", static_files::RUST_FAVICON_SVG)?;
178+
write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?;
179+
write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?;
126180
}
127-
write(cx.path("brush.svg"), static_files::BRUSH_SVG)?;
128-
write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?;
129-
write(cx.path("down-arrow.svg"), static_files::DOWN_ARROW_SVG)?;
181+
write_toolchain("brush.svg", static_files::BRUSH_SVG)?;
182+
write_toolchain("wheel.svg", static_files::WHEEL_SVG)?;
183+
write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
130184

131185
let mut themes: Vec<&String> = themes.iter().collect();
132186
themes.sort();
133187

134188
write_minify(
135-
&cx.shared.fs,
136-
cx.path("main.js"),
189+
"main.js",
137190
&static_files::MAIN_JS.replace(
138191
"/* INSERT THEMES HERE */",
139192
&format!(" = {}", serde_json::to_string(&themes).unwrap()),
140193
),
141-
options.enable_minification,
142-
)?;
143-
write_minify(
144-
&cx.shared.fs,
145-
cx.path("settings.js"),
146-
static_files::SETTINGS_JS,
147-
options.enable_minification,
148194
)?;
195+
write_minify("settings.js", static_files::SETTINGS_JS)?;
149196
if cx.shared.include_sources {
150-
write_minify(
151-
&cx.shared.fs,
152-
cx.path("source-script.js"),
153-
static_files::sidebar::SOURCE_SCRIPT,
154-
options.enable_minification,
155-
)?;
197+
write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
156198
}
157199

158200
{
159201
write_minify(
160-
&cx.shared.fs,
161-
cx.path("storage.js"),
202+
"storage.js",
162203
&format!(
163204
"var resourcesSuffix = \"{}\";{}",
164205
cx.shared.resource_suffix,
165206
static_files::STORAGE_JS
166207
),
167-
options.enable_minification,
168208
)?;
169209
}
170210

171211
if let Some(ref css) = cx.shared.layout.css_file_extension {
172-
let out = cx.path("theme.css");
173212
let buffer = try_err!(fs::read_to_string(css), css);
174-
if !options.enable_minification {
175-
cx.shared.fs.write(&out, &buffer)?;
176-
} else {
177-
write_minify(&cx.shared.fs, out, &buffer, options.enable_minification)?;
178-
}
213+
write_minify("theme.css", &buffer)?;
179214
}
180-
write_minify(
181-
&cx.shared.fs,
182-
cx.path("normalize.css"),
183-
static_files::NORMALIZE_CSS,
184-
options.enable_minification,
185-
)?;
186-
for (file, contents) in &*FILES_UNVERSIONED {
187-
write(cx.dst.join(file), contents)?;
215+
write_minify("normalize.css", static_files::NORMALIZE_CSS)?;
216+
for (name, contents) in &*FILES_UNVERSIONED {
217+
cx.write_shared(SharedResource::Unversioned { name }, contents)?;
188218
}
189219

190220
fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
@@ -324,7 +354,7 @@ pub(super) fn write_shared(
324354
"var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
325355
all_sources.join("\n")
326356
);
327-
cx.shared.fs.write(&dst, v.as_bytes())?;
357+
cx.write_shared(SharedResource::CrateSpecific { basename: "source-files.js" }, v)?;
328358
}
329359

330360
// Update the search index and crate list.
@@ -341,13 +371,12 @@ pub(super) fn write_shared(
341371
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
342372
v.push_str(&all_indexes.join(",\\\n"));
343373
v.push_str("\\\n}');\ninitSearch(searchIndex);");
344-
cx.shared.fs.write(&dst, &v)?;
374+
cx.write_shared(SharedResource::CrateSpecific { basename: "search-index.js" }, v)?;
345375
}
346376

347-
let crate_list_dst = cx.dst.join(&format!("crates{}.js", cx.shared.resource_suffix));
348377
let crate_list =
349378
format!("window.ALL_CRATES = [{}];", krates.iter().map(|k| format!("\"{}\"", k)).join(","));
350-
cx.shared.fs.write(&crate_list_dst, &crate_list)?;
379+
cx.write_shared(SharedResource::CrateSpecific { basename: "crates.js" }, crate_list)?;
351380

352381
if options.enable_index_page {
353382
if let Some(index_page) = options.index_page.clone() {
@@ -481,21 +510,3 @@ pub(super) fn write_shared(
481510
}
482511
Ok(())
483512
}
484-
485-
fn write_minify(
486-
fs: &DocFS,
487-
dst: PathBuf,
488-
contents: &str,
489-
enable_minification: bool,
490-
) -> Result<(), Error> {
491-
if enable_minification {
492-
if dst.extension() == Some(&OsStr::new("css")) {
493-
let res = try_none!(minifier::css::minify(contents).ok(), &dst);
494-
fs.write(dst, res.as_bytes())
495-
} else {
496-
fs.write(dst, minifier::js::minify(contents).as_bytes())
497-
}
498-
} else {
499-
fs.write(dst, contents.as_bytes())
500-
}
501-
}

0 commit comments

Comments
 (0)