From b2d50392eab891a177447225d69a46e97d30a5e8 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Wed, 27 May 2020 02:23:36 +0800 Subject: [PATCH] Emit redirects towards the end of the rendering process --- src/config.rs | 1 + src/renderer/html_handlebars/hbs_renderer.rs | 48 +++++++++++++++++++- src/theme/mod.rs | 6 +++ src/theme/redirect.hbs | 12 +++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/theme/redirect.hbs diff --git a/src/config.rs b/src/config.rs index 15c041cb..71edbaf2 100644 --- a/src/config.rs +++ b/src/config.rs @@ -539,6 +539,7 @@ impl Default for HtmlConfig { git_repository_url: None, git_repository_icon: None, livereload_url: None, + redirect: HashMap::new(), } } } diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index d58bc805..2953f098 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -9,7 +9,7 @@ use crate::utils; use std::borrow::Cow; use std::collections::BTreeMap; use std::collections::HashMap; -use std::fs; +use std::fs::{self, File}; use std::path::{Path, PathBuf}; use handlebars::Handlebars; @@ -279,6 +279,46 @@ impl HtmlHandlebars { Ok(()) } + + fn emit_redirects( + &self, + root: &Path, + handlebars: &Handlebars<'_>, + redirects: &HashMap, + ) -> Result<()> { + if redirects.is_empty() { + return Ok(()); + } + + log::debug!("Emitting redirects"); + + for (original, new) in redirects { + log::debug!("Redirecting \"{}\" → \"{}\"", original.display(), new); + let filename = root.join(original); + self.emit_redirect(handlebars, &filename, new)?; + } + + Ok(()) + } + + fn emit_redirect( + &self, + handlebars: &Handlebars<'_>, + original: &Path, + destination: &str, + ) -> Result<()> { + if let Some(parent) = original.parent() { + std::fs::create_dir_all(parent)?; + } + + let ctx = json!({ + "url": destination, + }); + let f = File::create(original)?; + handlebars.render_to_write("redirect", &ctx, f)?; + + Ok(()) + } } // TODO(mattico): Remove some time after the 0.1.8 release @@ -343,6 +383,10 @@ impl Renderer for HtmlHandlebars { debug!("Register the head handlebars template"); handlebars.register_partial("head", String::from_utf8(theme.head.clone())?)?; + debug!("Register the redirect handlebars template"); + handlebars + .register_template_string("redirect", String::from_utf8(theme.redirect.clone())?)?; + debug!("Register the header handlebars template"); handlebars.register_partial("header", String::from_utf8(theme.header.clone())?)?; @@ -401,6 +445,8 @@ impl Renderer for HtmlHandlebars { } } + self.emit_redirects(&ctx.destination, &handlebars, &html_config.redirect)?; + // Copy all remaining files, avoid a recursive copy from/to the book build dir utils::fs::copy_files_except_ext(&src_dir, &destination, true, Some(&build_dir), &["md"])?; diff --git a/src/theme/mod.rs b/src/theme/mod.rs index b8c496c3..38aa22e9 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -15,6 +15,7 @@ use crate::errors::*; pub static INDEX: &[u8] = include_bytes!("index.hbs"); pub static HEAD: &[u8] = include_bytes!("head.hbs"); +pub static REDIRECT: &[u8] = include_bytes!("redirect.hbs"); pub static HEADER: &[u8] = include_bytes!("header.hbs"); pub static CHROME_CSS: &[u8] = include_bytes!("css/chrome.css"); pub static GENERAL_CSS: &[u8] = include_bytes!("css/general.css"); @@ -46,6 +47,7 @@ pub static FONT_AWESOME_OTF: &[u8] = include_bytes!("FontAwesome/fonts/FontAweso pub struct Theme { pub index: Vec, pub head: Vec, + pub redirect: Vec, pub header: Vec, pub chrome_css: Vec, pub general_css: Vec, @@ -77,6 +79,7 @@ impl Theme { let files = vec![ (theme_dir.join("index.hbs"), &mut theme.index), (theme_dir.join("head.hbs"), &mut theme.head), + (theme_dir.join("redirect.hbs"), &mut theme.redirect), (theme_dir.join("header.hbs"), &mut theme.header), (theme_dir.join("book.js"), &mut theme.js), (theme_dir.join("css/chrome.css"), &mut theme.chrome_css), @@ -120,6 +123,7 @@ impl Default for Theme { Theme { index: INDEX.to_owned(), head: HEAD.to_owned(), + redirect: REDIRECT.to_owned(), header: HEADER.to_owned(), chrome_css: CHROME_CSS.to_owned(), general_css: GENERAL_CSS.to_owned(), @@ -175,6 +179,7 @@ mod tests { let files = [ "index.hbs", "head.hbs", + "redirect.hbs", "header.hbs", "favicon.png", "css/chrome.css", @@ -203,6 +208,7 @@ mod tests { let empty = Theme { index: Vec::new(), head: Vec::new(), + redirect: Vec::new(), header: Vec::new(), chrome_css: Vec::new(), general_css: Vec::new(), diff --git a/src/theme/redirect.hbs b/src/theme/redirect.hbs new file mode 100644 index 00000000..9f49e6d0 --- /dev/null +++ b/src/theme/redirect.hbs @@ -0,0 +1,12 @@ + + + + + Redirecting... + + + + +

Redirecting to... {{url}}.

+ +