From 54a21e38d7760a8e997ca80c7a92796ad3af8fc4 Mon Sep 17 00:00:00 2001 From: mash Date: Fri, 29 Jun 2018 15:36:12 +0000 Subject: [PATCH 1/2] Add partial support for multiple template dirs --- askama/src/lib.rs | 8 +++++--- askama_shared/Cargo.toml | 6 ++++-- askama_shared/src/lib.rs | 4 +++- askama_shared/src/path.rs | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/askama/src/lib.rs b/askama/src/lib.rs index f64fa682c..aaa1c3bad 100644 --- a/askama/src/lib.rs +++ b/askama/src/lib.rs @@ -393,7 +393,9 @@ fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> { /// that have templates, to make sure the crate gets rebuilt when template /// source code changes. pub fn rerun_if_templates_changed() { - visit_dirs(&path::template_dir(), &|e: &DirEntry| { - println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap()); - }).unwrap(); + for template_dir in path::template_dirs().iter() { + visit_dirs(template_dir, &|e: &DirEntry| { + println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap()); + }).unwrap(); + } } diff --git a/askama_shared/Cargo.toml b/askama_shared/Cargo.toml index 8b1880504..cd052cfae 100644 --- a/askama_shared/Cargo.toml +++ b/askama_shared/Cargo.toml @@ -10,10 +10,12 @@ workspace = ".." [features] default = [] -serde-json = ["serde", "serde_json"] +serde-json = ["serde_json"] iron = [] rocket = [] [dependencies] -serde = { version = "1.0", optional = true } +serde = "1.0" +serde_derive = "1.0" serde_json = { version = "1.0", optional = true } +toml = "0.4" diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index 9427dff6c..64d8d25b1 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -1,9 +1,11 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_parens))] -#[cfg(feature = "serde-json")] extern crate serde; +#[macro_use] +extern crate serde_derive; #[cfg(feature = "serde-json")] extern crate serde_json; +extern crate toml; pub use error::{Error, Result}; pub use escaping::MarkupDisplay; diff --git a/askama_shared/src/path.rs b/askama_shared/src/path.rs index 8b92250af..37fb261c1 100644 --- a/askama_shared/src/path.rs +++ b/askama_shared/src/path.rs @@ -3,6 +3,8 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; +use toml; + pub fn get_template_source(tpl_path: &Path) -> String { let mut path = template_dir(); path.push(tpl_path); @@ -52,6 +54,36 @@ pub fn template_dir() -> PathBuf { path } +#[derive(Deserialize)] +struct Config { + dirs: Option>, +} + +pub fn template_dirs() -> Vec { + let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let askama = root.join("askama.toml"); + let default = vec![root.join("templates")]; + if askama.exists() { + let mut contents = String::new(); + File::open(askama).unwrap().read_to_string(&mut contents).unwrap(); + let config: Config = toml::from_str(&contents).unwrap(); + if let Some(dirs) = config.dirs { + let paths: Vec = dirs.into_iter().map(|directory| { + root.join(directory) + }).collect(); + if paths.len() > 0 { + paths + } else { + default + } + } else { + default + } + } else { + vec![root.join("templates")] + } +} + #[cfg(test)] mod tests { use super::Path; From 40bb6f79e05cd47ce79ea3661ec4b354804ed43f Mon Sep 17 00:00:00 2001 From: mash Date: Wed, 4 Jul 2018 15:41:58 +0000 Subject: [PATCH 2/2] Add complete support for multiple template dirs --- askama_shared/src/path.rs | 106 ++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/askama_shared/src/path.rs b/askama_shared/src/path.rs index 37fb261c1..6b3ed0c0b 100644 --- a/askama_shared/src/path.rs +++ b/askama_shared/src/path.rs @@ -5,9 +5,18 @@ use std::path::{Path, PathBuf}; use toml; +fn search_template_in_dirs<'a>(dirs: &'a [PathBuf], path: &Path) -> Option<&'a PathBuf> { + dirs.iter().find(|dir| dir.join(path).exists()) +} + pub fn get_template_source(tpl_path: &Path) -> String { - let mut path = template_dir(); - path.push(tpl_path); + let dirs = template_dirs(); + let path = search_template_in_dirs(&dirs, tpl_path) + .map(|dir| dir.join(tpl_path)) + .expect(&format!( + "template file '{}' does not exist", + tpl_path.to_str().unwrap() + )); let mut f = match File::open(&path) { Err(_) => { let msg = format!("unable to open template file '{}'", &path.to_str().unwrap()); @@ -24,66 +33,77 @@ pub fn get_template_source(tpl_path: &Path) -> String { } pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf { - let root = template_dir(); + let dirs = template_dirs(); if let Some(rel) = start_at { - let mut fs_rel_path = root.clone(); - fs_rel_path.push(rel); - fs_rel_path = fs_rel_path.with_file_name(path); + let root = search_template_in_dirs(&dirs, rel).expect(&format!( + "unable to find previously available template file '{}'", + rel.to_str().unwrap() + )); + let fs_rel_path = root.join(rel).with_file_name(path); if fs_rel_path.exists() { return fs_rel_path.strip_prefix(&root).unwrap().to_owned(); } } - let mut fs_abs_path = root.clone(); let path = Path::new(path); - fs_abs_path.push(Path::new(path)); - if fs_abs_path.exists() { - path.to_owned() - } else { - panic!(format!( - "template {:?} not found at {:?}", - path.to_str().unwrap(), - fs_abs_path - )); - } + search_template_in_dirs(&dirs, &path).expect(&format!( + "template {:?} not found in directories {:?}", + path.to_str().unwrap(), + dirs + )); + path.to_owned() } -pub fn template_dir() -> PathBuf { - let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - path.push("templates"); - path -} +static CONFIG_FILE_NAME: &str = "askama.toml"; #[derive(Deserialize)] -struct Config { +struct RawConfig { dirs: Option>, } -pub fn template_dirs() -> Vec { - let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - let askama = root.join("askama.toml"); - let default = vec![root.join("templates")]; - if askama.exists() { - let mut contents = String::new(); - File::open(askama).unwrap().read_to_string(&mut contents).unwrap(); - let config: Config = toml::from_str(&contents).unwrap(); - if let Some(dirs) = config.dirs { - let paths: Vec = dirs.into_iter().map(|directory| { - root.join(directory) - }).collect(); - if paths.len() > 0 { - paths - } else { - default - } +struct Config { + dirs: Vec, +} + +impl RawConfig { + fn from_file(filename: &PathBuf) -> Option { + if filename.exists() { + let mut contents = String::new(); + File::open(filename) + .unwrap() + .read_to_string(&mut contents) + .unwrap(); + Some(toml::from_str(&contents).unwrap()) } else { - default + None } - } else { - vec![root.join("templates")] } } +impl Config { + fn from_file() -> Config { + let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let filename = root.join(CONFIG_FILE_NAME); + RawConfig::from_file(&filename).map_or_else( + || Config { + dirs: vec![root.join("templates")], + }, + |config| Config { + dirs: config + .dirs + .unwrap_or_else(|| Vec::new()) + .into_iter() + .map(|directory| root.join(directory)) + .collect(), + }, + ) + } +} + +pub fn template_dirs() -> Vec { + Config::from_file().dirs +} + #[cfg(test)] mod tests { use super::Path;