about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-12-23 00:07:55 +0800
committerkennytm <kennytm@gmail.com>2018-12-23 02:12:16 +0800
commit4446c65d9b6971ec80684ef5c299ab56cb1d16d8 (patch)
tree0a353b0fcafe99f1f9632be02c4bbe6aa42b01f1
parent5ba6a3438b990f7ede56491d77ee722651a6b3d7 (diff)
parent8dc8d7ac512b831705da9bf7ef4601fdc6adcb25 (diff)
downloadrust-4446c65d9b6971ec80684ef5c299ab56cb1d16d8.tar.gz
rust-4446c65d9b6971ec80684ef5c299ab56cb1d16d8.zip
Rollup merge of #57011 - QuietMisdreavus:static-root-path, r=GuillaumeGomez
rustdoc: add new CLI flag to load static files from a different location

This PR adds a new CLI flag to rustdoc, `--static-root-path`, which controls how rustdoc links pages to the CSS/JS/font static files bundled with the output. By default, these files are linked with a series of `../` which is calculated per-page to link it to the documentation root - i.e. a relative link to the directory given by `-o`. This is causing problems for docs.rs, because even though docs.rs has saved one copy of these files and is dispatching them dynamically, browsers have no way of knowing that these are the same files and can cache them. This can allow it to link these files as, for example, `/rustdoc.css` instead of `../../rustdoc.css`, creating a single location that the files are loaded from.

I made sure to only change links for the *static* files, those that don't change between crates. Files like the search index, aliases, the source files listing, etc, are still linked with relative links.

r? @GuillaumeGomez

cc @onur
-rw-r--r--src/doc/rustdoc/src/unstable-features.md15
-rw-r--r--src/librustdoc/config.rs5
-rw-r--r--src/librustdoc/html/layout.rs49
-rw-r--r--src/librustdoc/html/render.rs28
-rw-r--r--src/librustdoc/lib.rs8
-rw-r--r--src/test/rustdoc/static-root-path.rs24
6 files changed, 107 insertions, 22 deletions
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 43cdab27e9d..905b0646534 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -402,3 +402,18 @@ Using `index-page` option enables `enable-index-page` option as well.
 ### `--enable-index-page`: generate a default index page for docs
 
 This feature allows the generation of a default index-page which lists the generated crates.
+
+### `--static-root-path`: control how static files are loaded in HTML output
+
+Using this flag looks like this:
+
+```bash
+$ rustdoc src/lib.rs -Z unstable-options --static-root-path '/cache/'
+```
+
+This flag controls how rustdoc links to its static files on HTML pages. If you're hosting a lot of
+crates' docs generated by the same version of rustdoc, you can use this flag to cache rustdoc's CSS,
+JavaScript, and font files in a single location, rather than duplicating it once per "doc root"
+(grouping of crate docs generated into the same output directory, like with `cargo doc`). Per-crate
+files like the search index will still load from the documentation root, but anything that gets
+renamed with `--resource-suffix` will load from the given path.
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index b421f07ddaf..f9a46fe362e 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -181,6 +181,9 @@ pub struct RenderOptions {
     /// A file to use as the index page at the root of the output directory. Overrides
     /// `enable_index_page` to be true if set.
     pub index_page: Option<PathBuf>,
+    /// An optional path to use as the location of static files. If not set, uses combinations of
+    /// `../` to reach the documentation root.
+    pub static_root_path: Option<String>,
 
     // Options specific to reading standalone Markdown files
 
@@ -433,6 +436,7 @@ impl Options {
         let markdown_playground_url = matches.opt_str("markdown-playground-url");
         let crate_version = matches.opt_str("crate-version");
         let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
+        let static_root_path = matches.opt_str("static-root-path");
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
 
@@ -471,6 +475,7 @@ impl Options {
                 enable_minification,
                 enable_index_page,
                 index_page,
+                static_root_path,
                 markdown_no_toc,
                 markdown_css,
                 markdown_playground_url,
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 37ff693bdf1..d8a57bc93fd 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -26,16 +26,20 @@ pub struct Page<'a> {
     pub title: &'a str,
     pub css_class: &'a str,
     pub root_path: &'a str,
+    pub static_root_path: Option<&'a str>,
     pub description: &'a str,
     pub keywords: &'a str,
     pub resource_suffix: &'a str,
+    pub extra_scripts: &'a [&'a str],
+    pub static_extra_scripts: &'a [&'a str],
 }
 
 pub fn render<T: fmt::Display, S: fmt::Display>(
     dst: &mut dyn io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T,
-    css_file_extension: bool, themes: &[PathBuf], extra_scripts: &[&str])
+    css_file_extension: bool, themes: &[PathBuf])
     -> io::Result<()>
 {
+    let static_root_path = page.static_root_path.unwrap_or(page.root_path);
     write!(dst,
 "<!DOCTYPE html>\
 <html lang=\"en\">\
@@ -46,20 +50,20 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
     <meta name=\"description\" content=\"{description}\">\
     <meta name=\"keywords\" content=\"{keywords}\">\
     <title>{title}</title>\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
+    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
+    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
           id=\"mainThemeStyle\">\
     {themes}\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
-    <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
+    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}dark{suffix}.css\">\
+    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}light{suffix}.css\" \
           id=\"themeStyle\">\
-    <script src=\"{root_path}storage{suffix}.js\"></script>\
-    <noscript><link rel=\"stylesheet\" href=\"{root_path}noscript{suffix}.css\"></noscript>\
+    <script src=\"{static_root_path}storage{suffix}.js\"></script>\
+    <noscript><link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\"></noscript>\
     {css_extension}\
     {favicon}\
     {in_header}\
     <style type=\"text/css\">\
-    #crate-search{{background-image:url(\"{root_path}down-arrow{suffix}.svg\");}}\
+    #crate-search{{background-image:url(\"{static_root_path}down-arrow{suffix}.svg\");}}\
     </style>\
 </head>\
 <body class=\"rustdoc {css_class}\">\
@@ -77,11 +81,13 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
     </nav>\
     <div class=\"theme-picker\">\
         <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
-            <img src=\"{root_path}brush{suffix}.svg\" width=\"18\" alt=\"Pick another theme!\">\
+            <img src=\"{static_root_path}brush{suffix}.svg\" \
+                 width=\"18\" \
+                 alt=\"Pick another theme!\">\
         </button>\
         <div id=\"theme-choices\"></div>\
     </div>\
-    <script src=\"{root_path}theme{suffix}.js\"></script>\
+    <script src=\"{static_root_path}theme{suffix}.js\"></script>\
     <nav class=\"sub\">\
         <form class=\"search-form js-only\">\
             <div class=\"search-container\">\
@@ -96,7 +102,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
                            type=\"search\">\
                 </div>\
                 <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
-                    <img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\
+                    <img src=\"{static_root_path}wheel{suffix}.svg\" \
+                         width=\"18\" \
+                         alt=\"Change settings\">\
                 </a>\
             </div>\
         </form>\
@@ -157,19 +165,23 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
         window.currentCrate = \"{krate}\";\
     </script>\
     <script src=\"{root_path}aliases.js\"></script>\
-    <script src=\"{root_path}main{suffix}.js\"></script>\
+    <script src=\"{static_root_path}main{suffix}.js\"></script>\
+    {static_extra_scripts}\
     {extra_scripts}\
     <script defer src=\"{root_path}search-index.js\"></script>\
 </body>\
 </html>",
     css_extension = if css_file_extension {
-        format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
-                root_path = page.root_path,
+        format!("<link rel=\"stylesheet\" \
+                       type=\"text/css\" \
+                       href=\"{static_root_path}theme{suffix}.css\">",
+                static_root_path = static_root_path,
                 suffix=page.resource_suffix)
     } else {
         String::new()
     },
     content   = *t,
+    static_root_path = static_root_path,
     root_path = page.root_path,
     css_class = page.css_class,
     logo      = if layout.logo.is_empty() {
@@ -197,12 +209,17 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
                    .filter_map(|t| t.file_stem())
                    .filter_map(|t| t.to_str())
                    .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
-                                    page.root_path,
+                                    static_root_path,
                                     t,
                                     page.resource_suffix))
                    .collect::<String>(),
     suffix=page.resource_suffix,
-    extra_scripts=extra_scripts.iter().map(|e| {
+    static_extra_scripts=page.static_extra_scripts.iter().map(|e| {
+        format!("<script src=\"{static_root_path}{extra_script}.js\"></script>",
+                static_root_path=static_root_path,
+                extra_script=e)
+    }).collect::<String>(),
+    extra_scripts=page.extra_scripts.iter().map(|e| {
         format!("<script src=\"{root_path}{extra_script}.js\"></script>",
                 root_path=page.root_path,
                 extra_script=e)
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index f0cded97af6..e47ec9ec2f0 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -140,6 +140,9 @@ struct SharedContext {
     /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
     /// "light-v2.css").
     pub resource_suffix: String,
+    /// Optional path string to be used to load static files on output pages. If not set, uses
+    /// combinations of `../` to reach the documentation root.
+    pub static_root_path: Option<String>,
 }
 
 impl SharedContext {
@@ -506,6 +509,7 @@ pub fn run(mut krate: clean::Crate,
         extension_css,
         extern_html_root_urls,
         resource_suffix,
+        static_root_path,
         ..
     } = options;
 
@@ -533,6 +537,7 @@ pub fn run(mut krate: clean::Crate,
         sort_modules_alphabetically,
         themes,
         resource_suffix,
+        static_root_path,
     };
 
     // If user passed in `--playground-url` arg, we fill in crate name here
@@ -1080,9 +1085,12 @@ themePicker.onblur = handleThemeButtonsBlur;
                 title: "Index of crates",
                 css_class: "mod",
                 root_path: "./",
+                static_root_path: cx.shared.static_root_path.deref(),
                 description: "List of crates",
                 keywords: BASIC_KEYWORDS,
                 resource_suffix: &cx.shared.resource_suffix,
+                extra_scripts: &[],
+                static_extra_scripts: &[],
             };
             krates.push(krate.name.clone());
             krates.sort();
@@ -1101,7 +1109,7 @@ themePicker.onblur = handleThemeButtonsBlur;
             try_err!(layout::render(&mut w, &cx.shared.layout,
                                     &page, &(""), &content,
                                     cx.shared.css_file_extension.is_some(),
-                                    &cx.shared.themes, &[]), &dst);
+                                    &cx.shared.themes), &dst);
             try_err!(w.flush(), &dst);
         }
     }
@@ -1366,15 +1374,17 @@ impl<'a> SourceCollector<'a> {
             title: &title,
             css_class: "source",
             root_path: &root_path,
+            static_root_path: self.scx.static_root_path.deref(),
             description: &desc,
             keywords: BASIC_KEYWORDS,
             resource_suffix: &self.scx.resource_suffix,
+            extra_scripts: &["source-files"],
+            static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)],
         };
         layout::render(&mut w, &self.scx.layout,
                        &page, &(""), &Source(contents),
                        self.scx.css_file_extension.is_some(),
-                       &self.scx.themes, &["source-files",
-                                           &format!("source-script{}", page.resource_suffix)])?;
+                       &self.scx.themes)?;
         w.flush()?;
         self.scx.local_sources.insert(p.clone(), href);
         Ok(())
@@ -1956,9 +1966,12 @@ impl Context {
             title: "List of all items in this crate",
             css_class: "mod",
             root_path: "../",
+            static_root_path: self.shared.static_root_path.deref(),
             description: "List of all items in this crate",
             keywords: BASIC_KEYWORDS,
             resource_suffix: &self.shared.resource_suffix,
+            extra_scripts: &[],
+            static_extra_scripts: &[],
         };
         let sidebar = if let Some(ref version) = cache().crate_version {
             format!("<p class='location'>Crate {}</p>\
@@ -1973,7 +1986,7 @@ impl Context {
         try_err!(layout::render(&mut w, &self.shared.layout,
                                 &page, &sidebar, &all,
                                 self.shared.css_file_extension.is_some(),
-                                &self.shared.themes, &[]),
+                                &self.shared.themes),
                  &final_file);
 
         // Generating settings page.
@@ -1993,7 +2006,7 @@ impl Context {
         try_err!(layout::render(&mut w, &layout,
                                 &page, &sidebar, &settings,
                                 self.shared.css_file_extension.is_some(),
-                                &themes, &[]),
+                                &themes),
                  &settings_file);
 
         Ok(())
@@ -2035,10 +2048,13 @@ impl Context {
         let page = layout::Page {
             css_class: tyname,
             root_path: &self.root_path(),
+            static_root_path: self.shared.static_root_path.deref(),
             title: &title,
             description: &desc,
             keywords: &keywords,
             resource_suffix: &self.shared.resource_suffix,
+            extra_scripts: &[],
+            static_extra_scripts: &[],
         };
 
         {
@@ -2051,7 +2067,7 @@ impl Context {
                            &Sidebar{ cx: self, item: it },
                            &Item{ cx: self, item: it },
                            self.shared.css_file_extension.is_some(),
-                           &self.shared.themes, &[])?;
+                           &self.shared.themes)?;
         } else {
             let mut url = self.root_path();
             if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b0045e41f50..4f59f67e94f 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -25,6 +25,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(const_fn)]
 #![feature(drain_filter)]
+#![feature(inner_deref)]
 
 #![recursion_limit="256"]
 
@@ -338,6 +339,13 @@ fn opts() -> Vec<RustcOptGroup> {
                        "enable-index-page",
                        "To enable generation of the index page")
         }),
+        unstable("static-root-path", |o| {
+            o.optopt("",
+                     "static-root-path",
+                     "Path string to force loading static files from in output pages. \
+                      If not set, uses combinations of '../' to reach the documentation root.",
+                     "PATH")
+        }),
     ]
 }
 
diff --git a/src/test/rustdoc/static-root-path.rs b/src/test/rustdoc/static-root-path.rs
new file mode 100644
index 00000000000..7df3fee3365
--- /dev/null
+++ b/src/test/rustdoc/static-root-path.rs
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Z unstable-options --static-root-path /cache/
+
+// @has static_root_path/struct.SomeStruct.html
+// @matches - '"/cache/main\.js"'
+// @!matches - '"\.\./main\.js"'
+// @matches - '"\.\./search-index\.js"'
+// @!matches - '"/cache/search-index\.js"'
+pub struct SomeStruct;
+
+// @has src/static_root_path/static-root-path.rs.html
+// @matches - '"/cache/source-script\.js"'
+// @!matches - '"\.\./\.\./source-script\.js"'
+// @matches - '"\.\./\.\./source-files.js"'
+// @!matches - '"/cache/source-files\.js"'