Emit redirects towards the end of the rendering process

This commit is contained in:
Michael-F-Bryan 2020-05-27 02:23:36 +08:00
parent a5086a1e58
commit b2d50392ea
No known key found for this signature in database
GPG Key ID: E9C602B0D9A998DC
4 changed files with 66 additions and 1 deletions

View File

@ -539,6 +539,7 @@ impl Default for HtmlConfig {
git_repository_url: None, git_repository_url: None,
git_repository_icon: None, git_repository_icon: None,
livereload_url: None, livereload_url: None,
redirect: HashMap::new(),
} }
} }
} }

View File

@ -9,7 +9,7 @@ use crate::utils;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs::{self, File};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use handlebars::Handlebars; use handlebars::Handlebars;
@ -279,6 +279,46 @@ impl HtmlHandlebars {
Ok(()) Ok(())
} }
fn emit_redirects(
&self,
root: &Path,
handlebars: &Handlebars<'_>,
redirects: &HashMap<PathBuf, String>,
) -> 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 // 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"); debug!("Register the head handlebars template");
handlebars.register_partial("head", String::from_utf8(theme.head.clone())?)?; 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"); debug!("Register the header handlebars template");
handlebars.register_partial("header", String::from_utf8(theme.header.clone())?)?; 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 // 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"])?; utils::fs::copy_files_except_ext(&src_dir, &destination, true, Some(&build_dir), &["md"])?;

View File

@ -15,6 +15,7 @@ use crate::errors::*;
pub static INDEX: &[u8] = include_bytes!("index.hbs"); pub static INDEX: &[u8] = include_bytes!("index.hbs");
pub static HEAD: &[u8] = include_bytes!("head.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 HEADER: &[u8] = include_bytes!("header.hbs");
pub static CHROME_CSS: &[u8] = include_bytes!("css/chrome.css"); pub static CHROME_CSS: &[u8] = include_bytes!("css/chrome.css");
pub static GENERAL_CSS: &[u8] = include_bytes!("css/general.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 struct Theme {
pub index: Vec<u8>, pub index: Vec<u8>,
pub head: Vec<u8>, pub head: Vec<u8>,
pub redirect: Vec<u8>,
pub header: Vec<u8>, pub header: Vec<u8>,
pub chrome_css: Vec<u8>, pub chrome_css: Vec<u8>,
pub general_css: Vec<u8>, pub general_css: Vec<u8>,
@ -77,6 +79,7 @@ impl Theme {
let files = vec![ let files = vec![
(theme_dir.join("index.hbs"), &mut theme.index), (theme_dir.join("index.hbs"), &mut theme.index),
(theme_dir.join("head.hbs"), &mut theme.head), (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("header.hbs"), &mut theme.header),
(theme_dir.join("book.js"), &mut theme.js), (theme_dir.join("book.js"), &mut theme.js),
(theme_dir.join("css/chrome.css"), &mut theme.chrome_css), (theme_dir.join("css/chrome.css"), &mut theme.chrome_css),
@ -120,6 +123,7 @@ impl Default for Theme {
Theme { Theme {
index: INDEX.to_owned(), index: INDEX.to_owned(),
head: HEAD.to_owned(), head: HEAD.to_owned(),
redirect: REDIRECT.to_owned(),
header: HEADER.to_owned(), header: HEADER.to_owned(),
chrome_css: CHROME_CSS.to_owned(), chrome_css: CHROME_CSS.to_owned(),
general_css: GENERAL_CSS.to_owned(), general_css: GENERAL_CSS.to_owned(),
@ -175,6 +179,7 @@ mod tests {
let files = [ let files = [
"index.hbs", "index.hbs",
"head.hbs", "head.hbs",
"redirect.hbs",
"header.hbs", "header.hbs",
"favicon.png", "favicon.png",
"css/chrome.css", "css/chrome.css",
@ -203,6 +208,7 @@ mod tests {
let empty = Theme { let empty = Theme {
index: Vec::new(), index: Vec::new(),
head: Vec::new(), head: Vec::new(),
redirect: Vec::new(),
header: Vec::new(), header: Vec::new(),
chrome_css: Vec::new(), chrome_css: Vec::new(),
general_css: Vec::new(), general_css: Vec::new(),

12
src/theme/redirect.hbs Normal file
View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting...</title>
<meta http-equiv="refresh" content="0;URL='{{url}}'">
<meta rel="canonical" href="{{url}}">
</head>
<body>
<p>Redirecting to... <a href="{{url}}">{{url}}</a>.</p>
</body>
</html>