Extract some Tera logic out of site/lib.rs

This commit is contained in:
Vincent Prouillet 2020-07-24 23:44:00 +02:00
parent d9123a8ca4
commit 5fe1036a1d
6 changed files with 122 additions and 105 deletions

View file

@ -1,6 +1,7 @@
pub mod link_checking;
pub mod sass; pub mod sass;
pub mod sitemap; pub mod sitemap;
pub mod link_checking; pub mod tpls;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::{copy, remove_dir_all}; use std::fs::{copy, remove_dir_all};
@ -12,6 +13,8 @@ use rayon::prelude::*;
use serde_derive::Serialize; use serde_derive::Serialize;
use tera::{Context, Tera}; use tera::{Context, Tera};
use crate::link_checking::{check_external_links, check_internal_links_with_anchors};
use crate::tpls::{load_tera, register_early_global_fns, register_tera_global_fns};
use config::{get_config, Config, Taxonomy as TaxonomyConfig}; use config::{get_config, Config, Taxonomy as TaxonomyConfig};
use errors::{bail, Error, Result}; use errors::{bail, Error, Result};
use front_matter::InsertAnchor; use front_matter::InsertAnchor;
@ -19,11 +22,10 @@ use library::{
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy, find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
TaxonomyItem, TaxonomyItem,
}; };
use templates::{global_fns, render_redirect_template, ZOLA_TERA}; use templates::render_redirect_template;
use utils::fs::{copy_directory, create_directory, create_file, ensure_directory_exists}; use utils::fs::{copy_directory, create_directory, create_file, ensure_directory_exists};
use utils::net::get_available_port; use utils::net::get_available_port;
use utils::templates::{render_template, rewrite_theme_paths}; use utils::templates::render_template;
use crate::link_checking::{check_internal_links_with_anchors, check_external_links};
#[derive(Debug)] #[derive(Debug)]
pub struct Site { pub struct Site {
@ -74,45 +76,12 @@ impl Site {
let mut config = get_config(config_file); let mut config = get_config(config_file);
config.load_extra_syntaxes(path)?; config.load_extra_syntaxes(path)?;
let tpl_glob =
format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml");
// Only parsing as we might be extending templates from themes and that would error
// as we haven't loaded them yet
let mut tera =
Tera::parse(&tpl_glob).map_err(|e| Error::chain("Error parsing templates", e))?;
if let Some(theme) = config.theme.clone() { if let Some(theme) = config.theme.clone() {
// Grab data from the extra section of the theme // Grab data from the extra section of the theme
config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?; config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?;
// Test that the templates folder exist for that theme
let theme_path = path.join("themes").join(&theme);
if !theme_path.join("templates").exists() {
bail!("Theme `{}` is missing a templates folder", theme);
}
let theme_tpl_glob = format!(
"{}/{}",
path.to_string_lossy().replace("\\", "/"),
format!("themes/{}/templates/**/*.*ml", theme)
);
let mut tera_theme = Tera::parse(&theme_tpl_glob)
.map_err(|e| Error::chain("Error parsing templates from themes", e))?;
rewrite_theme_paths(&mut tera_theme, &theme);
// TODO: we do that twice, make it dry?
if theme_path.join("templates").join("robots.txt").exists() {
tera_theme
.add_template_file(theme_path.join("templates").join("robots.txt"), None)?;
}
tera.extend(&tera_theme)?;
} }
tera.extend(&ZOLA_TERA)?;
tera.build_inheritance_chains()?;
// TODO: Tera doesn't use globset right now so we can load the robots.txt as part let tera = load_tera(path, &config)?;
// of the glob above, therefore we load it manually if it exists.
if path.join("templates").join("robots.txt").exists() {
tera.add_template_file(path.join("templates").join("robots.txt"), Some("robots.txt"))?;
}
let content_path = path.join("content"); let content_path = path.join("content");
let static_path = path.join("static"); let static_path = path.join("static");
@ -145,7 +114,7 @@ impl Site {
} }
/// The index sections are ALWAYS at those paths /// The index sections are ALWAYS at those paths
/// There are one index section for the basic language + 1 per language /// There are one index section for the default language + 1 per language
fn index_section_paths(&self) -> Vec<(PathBuf, Option<String>)> { fn index_section_paths(&self) -> Vec<(PathBuf, Option<String>)> {
let mut res = vec![(self.content_path.join("_index.md"), None)]; let mut res = vec![(self.content_path.join("_index.md"), None)];
for language in &self.config.languages { for language in &self.config.languages {
@ -164,11 +133,6 @@ impl Site {
self.live_reload = get_available_port(port_to_avoid); self.live_reload = get_available_port(port_to_avoid);
} }
/// Get the number of orphan (== without section) pages in the site
pub fn get_number_orphan_pages(&self) -> usize {
self.library.read().unwrap().get_all_orphan_pages().len()
}
pub fn set_base_url(&mut self, base_url: String) { pub fn set_base_url(&mut self, base_url: String) {
let mut imageproc = self.imageproc.lock().expect("Couldn't lock imageproc (set_base_url)"); let mut imageproc = self.imageproc.lock().expect("Couldn't lock imageproc (set_base_url)");
imageproc.set_base_url(&base_url); imageproc.set_base_url(&base_url);
@ -359,58 +323,14 @@ impl Site {
Ok(()) Ok(())
} }
/// Adds global fns that are to be available to shortcodes while // TODO: remove me in favour of the direct call to the fn once rebuild has changed
/// markdown
pub fn register_early_global_fns(&mut self) { pub fn register_early_global_fns(&mut self) {
self.tera.register_function( register_early_global_fns(self);
"get_url",
global_fns::GetUrl::new(
self.config.clone(),
self.permalinks.clone(),
vec![self.static_path.clone(), self.output_path.clone(), self.content_path.clone()],
),
);
self.tera.register_function(
"resize_image",
global_fns::ResizeImage::new(self.imageproc.clone()),
);
self.tera.register_function(
"get_image_metadata",
global_fns::GetImageMeta::new(self.content_path.clone()),
);
self.tera.register_function("load_data", global_fns::LoadData::new(self.base_path.clone()));
self.tera.register_function("trans", global_fns::Trans::new(self.config.clone()));
self.tera.register_function(
"get_taxonomy_url",
global_fns::GetTaxonomyUrl::new(&self.config.default_language, &self.taxonomies),
);
self.tera.register_function(
"get_file_hash",
global_fns::GetFileHash::new(vec![
self.static_path.clone(),
self.output_path.clone(),
self.content_path.clone(),
]),
);
} }
// TODO: remove me in favour of the direct call to the fn once rebuild has changed
pub fn register_tera_global_fns(&mut self) { pub fn register_tera_global_fns(&mut self) {
self.tera.register_function( register_tera_global_fns(self);
"get_page",
global_fns::GetPage::new(self.base_path.clone(), self.library.clone()),
);
self.tera.register_function(
"get_section",
global_fns::GetSection::new(self.base_path.clone(), self.library.clone()),
);
self.tera.register_function(
"get_taxonomy",
global_fns::GetTaxonomy::new(
&self.config.default_language,
self.taxonomies.clone(),
self.library.clone(),
),
);
} }
/// Add a page to the site /// Add a page to the site
@ -703,6 +623,8 @@ impl Site {
) )
} }
/// Renders all the aliases for each page/section: a magic HTML template that redirects to
/// the canonical one
pub fn render_aliases(&self) -> Result<()> { pub fn render_aliases(&self) -> Result<()> {
ensure_directory_exists(&self.output_path)?; ensure_directory_exists(&self.output_path)?;
let library = self.library.read().unwrap(); let library = self.library.read().unwrap();
@ -837,6 +759,7 @@ impl Site {
sitemap_url.pop(); // Remove trailing slash sitemap_url.pop(); // Remove trailing slash
sitemap_index.push(sitemap_url); sitemap_index.push(sitemap_url);
} }
// Create main sitemap that reference numbered sitemaps // Create main sitemap that reference numbered sitemaps
let mut main_context = Context::new(); let mut main_context = Context::new();
main_context.insert("sitemaps", &sitemap_index); main_context.insert("sitemaps", &sitemap_index);
@ -993,6 +916,7 @@ impl Site {
Ok(()) Ok(())
} }
// TODO: remove me when reload has changed
/// Used only on reload /// Used only on reload
pub fn render_index(&self) -> Result<()> { pub fn render_index(&self) -> Result<()> {
self.render_section( self.render_section(
@ -1061,5 +985,3 @@ impl Site {
.collect::<Result<()>>() .collect::<Result<()>>()
} }
} }
impl Site {}

View file

@ -1,9 +1,7 @@
use rayon::prelude::*; use rayon::prelude::*;
use errors::{Error, ErrorKind, Result};
use crate::Site; use crate::Site;
use errors::{Error, ErrorKind, Result};
/// Very similar to check_external_links but can't be merged as far as I can see since we always /// Very similar to check_external_links but can't be merged as far as I can see since we always
/// want to check the internal links but only the external in zola check :/ /// want to check the internal links but only the external in zola check :/
@ -152,11 +150,7 @@ pub fn check_external_links(site: &Site) -> Result<()> {
.collect() .collect()
}); });
println!( println!("> Checked {} external link(s): {} error(s) found.", all_links.len(), errors.len());
"> Checked {} external link(s): {} error(s) found.",
all_links.len(),
errors.len()
);
if errors.is_empty() { if errors.is_empty() {
return Ok(()); return Ok(());

View file

@ -18,7 +18,7 @@ pub fn compile_sass(base_path: &Path, output_path: &Path) -> Result<()> {
let mut options = Options::default(); let mut options = Options::default();
options.output_style = OutputStyle::Compressed; options.output_style = OutputStyle::Compressed;
let mut compiled_paths = compile_sass_glob(&sass_path, output_path, "scss", &options.clone())?; let mut compiled_paths = compile_sass_glob(&sass_path, output_path, "scss", &options)?;
options.indented_syntax = true; options.indented_syntax = true;
compiled_paths.extend(compile_sass_glob(&sass_path, output_path, "sass", &options)?); compiled_paths.extend(compile_sass_glob(&sass_path, output_path, "sass", &options)?);

101
components/site/src/tpls.rs Normal file
View file

@ -0,0 +1,101 @@
use std::path::Path;
use tera::Tera;
use crate::Site;
use config::Config;
use errors::{bail, Error, Result};
use templates::{global_fns, ZOLA_TERA};
use utils::templates::rewrite_theme_paths;
pub fn load_tera(path: &Path, config: &Config) -> Result<Tera> {
let tpl_glob =
format!("{}/{}", path.to_string_lossy().replace("\\", "/"), "templates/**/*.*ml");
// Only parsing as we might be extending templates from themes and that would error
// as we haven't loaded them yet
let mut tera =
Tera::parse(&tpl_glob).map_err(|e| Error::chain("Error parsing templates", e))?;
if let Some(ref theme) = config.theme {
// Test that the templates folder exist for that theme
let theme_path = path.join("themes").join(&theme);
if !theme_path.join("templates").exists() {
bail!("Theme `{}` is missing a templates folder", theme);
}
let theme_tpl_glob = format!(
"{}/{}",
path.to_string_lossy().replace("\\", "/"),
format!("themes/{}/templates/**/*.*ml", theme)
);
let mut tera_theme = Tera::parse(&theme_tpl_glob)
.map_err(|e| Error::chain("Error parsing templates from themes", e))?;
rewrite_theme_paths(&mut tera_theme, &theme);
if theme_path.join("templates").join("robots.txt").exists() {
tera_theme.add_template_file(theme_path.join("templates").join("robots.txt"), None)?;
}
tera.extend(&tera_theme)?;
}
tera.extend(&ZOLA_TERA)?;
tera.build_inheritance_chains()?;
if path.join("templates").join("robots.txt").exists() {
tera.add_template_file(path.join("templates").join("robots.txt"), Some("robots.txt"))?;
}
Ok(tera)
}
/// Adds global fns that are to be available to shortcodes while rendering markdown
pub fn register_early_global_fns(site: &mut Site) {
site.tera.register_function(
"get_url",
global_fns::GetUrl::new(
site.config.clone(),
site.permalinks.clone(),
vec![site.static_path.clone(), site.output_path.clone(), site.content_path.clone()],
),
);
site.tera
.register_function("resize_image", global_fns::ResizeImage::new(site.imageproc.clone()));
site.tera.register_function(
"get_image_metadata",
global_fns::GetImageMeta::new(site.content_path.clone()),
);
site.tera.register_function("load_data", global_fns::LoadData::new(site.base_path.clone()));
site.tera.register_function("trans", global_fns::Trans::new(site.config.clone()));
site.tera.register_function(
"get_taxonomy_url",
global_fns::GetTaxonomyUrl::new(&site.config.default_language, &site.taxonomies),
);
site.tera.register_function(
"get_file_hash",
global_fns::GetFileHash::new(vec![
site.static_path.clone(),
site.output_path.clone(),
site.content_path.clone(),
]),
);
}
/// Functions filled once we have parsed all the pages/sections only, so not available in shortcodes
pub fn register_tera_global_fns(site: &mut Site) {
site.tera.register_function(
"get_page",
global_fns::GetPage::new(site.base_path.clone(), site.library.clone()),
);
site.tera.register_function(
"get_section",
global_fns::GetSection::new(site.base_path.clone(), site.library.clone()),
);
site.tera.register_function(
"get_taxonomy",
global_fns::GetTaxonomy::new(
&site.config.default_language,
site.taxonomies.clone(),
site.library.clone(),
),
);
}

View file

@ -42,8 +42,8 @@ use ws::{Message, Sender, WebSocket};
use errors::{Error as ZolaError, Result}; use errors::{Error as ZolaError, Result};
use globset::GlobSet; use globset::GlobSet;
use site::Site;
use site::sass::compile_sass; use site::sass::compile_sass;
use site::Site;
use utils::fs::copy_file; use utils::fs::copy_file;
use crate::console; use crate::console;

View file

@ -54,7 +54,7 @@ pub fn notify_site_size(site: &Site) {
println!( println!(
"-> Creating {} pages ({} orphan), {} sections, and processing {} images", "-> Creating {} pages ({} orphan), {} sections, and processing {} images",
library.pages().len(), library.pages().len(),
site.get_number_orphan_pages(), library.get_all_orphan_pages().len(),
library.sections().len() - 1, // -1 since we do not count the index as a section there library.sections().len() - 1, // -1 since we do not count the index as a section there
site.num_img_ops(), site.num_img_ops(),
); );