@@ -14,7 +14,7 @@ use serde::Serialize;
1414use super :: { collect_paths_for_type, ensure_trailing_slash, Context , BASIC_KEYWORDS } ;
1515use crate :: clean:: Crate ;
1616use crate :: config:: RenderOptions ;
17- use crate :: docfs:: { DocFS , PathError } ;
17+ use crate :: docfs:: PathError ;
1818use crate :: error:: Error ;
1919use crate :: formats:: FormatRenderer ;
2020use 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+
43118pub ( 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 {}\n createSourceSidebar();\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 }');\n initSearch(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