From 5ca2b29c498f973bca4c76cffbde448f49c1beaa Mon Sep 17 00:00:00 2001 From: Koen Bolhuis Date: Thu, 19 Aug 2021 07:55:40 +0200 Subject: [PATCH] Fix cachebust for files in the output path (#1586) * Consider the site's output path in search_for_file The search_for_file helper function now accepts an optional output path. If passed, the file will also be searched there. This is used in the get_url function to search in the Site::output_path. In practice, this means cachebust works for files in the output path. * Make output_dir required in search_for_file * Update docs for file searching logic * Add test for new file searching behavior --- components/site/src/tpls.rs | 20 +++++- components/templates/src/global_fns/files.rs | 67 +++++++++++++------ .../templates/src/global_fns/helpers.rs | 10 +-- components/templates/src/global_fns/images.rs | 18 +++-- .../templates/src/global_fns/load_data.rs | 54 ++++++++------- .../documentation/templates/overview.md | 11 +-- 6 files changed, 113 insertions(+), 67 deletions(-) diff --git a/components/site/src/tpls.rs b/components/site/src/tpls.rs index 7b4a1409..1abee3b2 100644 --- a/components/site/src/tpls.rs +++ b/components/site/src/tpls.rs @@ -23,6 +23,7 @@ pub fn register_early_global_fns(site: &mut Site) -> TeraResult<()> { site.base_path.clone(), site.config.clone(), site.permalinks.clone(), + site.output_path.clone(), ), ); site.tera.register_function( @@ -31,15 +32,24 @@ pub fn register_early_global_fns(site: &mut Site) -> TeraResult<()> { site.base_path.clone(), site.imageproc.clone(), site.config.theme.clone(), + site.output_path.clone(), ), ); site.tera.register_function( "get_image_metadata", - global_fns::GetImageMetadata::new(site.base_path.clone(), site.config.theme.clone()), + global_fns::GetImageMetadata::new( + site.base_path.clone(), + site.config.theme.clone(), + site.output_path.clone(), + ), ); site.tera.register_function( "load_data", - global_fns::LoadData::new(site.base_path.clone(), site.config.theme.clone()), + global_fns::LoadData::new( + site.base_path.clone(), + site.config.theme.clone(), + site.output_path.clone(), + ), ); site.tera.register_function("trans", global_fns::Trans::new(site.config.clone())); site.tera.register_function( @@ -52,7 +62,11 @@ pub fn register_early_global_fns(site: &mut Site) -> TeraResult<()> { ); site.tera.register_function( "get_file_hash", - global_fns::GetFileHash::new(site.base_path.clone(), site.config.theme.clone()), + global_fns::GetFileHash::new( + site.base_path.clone(), + site.config.theme.clone(), + site.output_path.clone(), + ), ); Ok(()) diff --git a/components/templates/src/global_fns/files.rs b/components/templates/src/global_fns/files.rs index ba05b121..09557bca 100644 --- a/components/templates/src/global_fns/files.rs +++ b/components/templates/src/global_fns/files.rs @@ -31,11 +31,17 @@ pub struct GetUrl { base_path: PathBuf, config: Config, permalinks: HashMap, + output_path: PathBuf, } impl GetUrl { - pub fn new(base_path: PathBuf, config: Config, permalinks: HashMap) -> Self { - Self { base_path, config, permalinks } + pub fn new( + base_path: PathBuf, + config: Config, + permalinks: HashMap, + output_path: PathBuf, + ) -> Self { + Self { base_path, config, permalinks, output_path } } } @@ -111,7 +117,7 @@ impl TeraFn for GetUrl { } if cachebust { - match search_for_file(&self.base_path, &path_with_lang, &self.config.theme) + match search_for_file(&self.base_path, &path_with_lang, &self.config.theme, &self.output_path) .map_err(|e| format!("`get_url`: {}", e))? .and_then(|(p, _)| fs::File::open(&p).ok()) .and_then(|f| compute_file_hash::(f, false).ok()) @@ -142,10 +148,11 @@ impl TeraFn for GetUrl { pub struct GetFileHash { base_path: PathBuf, theme: Option, + output_path: PathBuf, } impl GetFileHash { - pub fn new(base_path: PathBuf, theme: Option) -> Self { - Self { base_path, theme } + pub fn new(base_path: PathBuf, theme: Option, output_path: PathBuf) -> Self { + Self { base_path, theme, output_path } } } @@ -169,7 +176,7 @@ impl TeraFn for GetFileHash { ) .unwrap_or(true); - let file_path = match search_for_file(&self.base_path, &path, &self.theme) + let file_path = match search_for_file(&self.base_path, &path, &self.theme, &self.output_path) .map_err(|e| format!("`get_file_hash`: {}", e))? { Some((f, _)) => f, @@ -204,6 +211,8 @@ mod tests { use super::{GetFileHash, GetUrl}; use std::collections::HashMap; + use std::fs::create_dir; + use std::path::PathBuf; use tempfile::{tempdir, TempDir}; use tera::{to_value, Function}; @@ -232,7 +241,7 @@ title = "A title" #[test] fn can_add_cachebust_to_url() { let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("cachebust".to_string(), to_value(true).unwrap()); @@ -242,7 +251,7 @@ title = "A title" #[test] fn can_add_trailing_slashes() { let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("trailing_slash".to_string(), to_value(true).unwrap()); @@ -252,7 +261,7 @@ title = "A title" #[test] fn can_add_slashes_and_cachebust() { let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("trailing_slash".to_string(), to_value(true).unwrap()); @@ -263,7 +272,7 @@ title = "A title" #[test] fn can_link_to_some_static_file() { let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css"); @@ -273,11 +282,25 @@ title = "A title" assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css"); } + #[test] + fn can_link_to_file_in_output_path() { + let dir = create_temp_dir(); + let public = dir.path().join("public"); + create_dir(&public).expect("Failed to create output directory"); + create_file(&public.join("style.css"), "// Hello world") + .expect("Failed to create file in output directory"); + + let static_fn = GetUrl::new(dir.path().to_path_buf(), Config::default(), HashMap::new(), public); + let mut args = HashMap::new(); + args.insert("path".to_string(), to_value("style.css").unwrap()); + assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/style.css"); + } + #[test] fn error_when_language_not_available() { let config = Config::parse(CONFIG_DATA).unwrap(); let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), config, HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), config, HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("@/a_section/a_page.md").unwrap()); args.insert("lang".to_string(), to_value("it").unwrap()); @@ -301,7 +324,7 @@ title = "A title" ); let config = Config::parse(CONFIG_DATA).unwrap(); let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), config, permalinks); + let static_fn = GetUrl::new(dir.path().to_path_buf(), config, permalinks, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("@/a_section/a_page.md").unwrap()); args.insert("lang".to_string(), to_value("fr").unwrap()); @@ -324,7 +347,7 @@ title = "A title" "https://remplace-par-ton-url.fr/en/a_section/a_page/".to_string(), ); let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), config, permalinks); + let static_fn = GetUrl::new(dir.path().to_path_buf(), config, permalinks, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("@/a_section/a_page.md").unwrap()); args.insert("lang".to_string(), to_value("en").unwrap()); @@ -338,7 +361,7 @@ title = "A title" fn can_get_feed_url_with_default_language() { let config = Config::parse(CONFIG_DATA).unwrap(); let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value(config.feed_filename).unwrap()); args.insert("lang".to_string(), to_value("fr").unwrap()); @@ -349,7 +372,7 @@ title = "A title" fn can_get_feed_url_with_other_language() { let config = Config::parse(CONFIG_DATA).unwrap(); let dir = create_temp_dir(); - let static_fn = GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new()); + let static_fn = GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new(), PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value(config.feed_filename).unwrap()); args.insert("lang".to_string(), to_value("en").unwrap()); @@ -359,7 +382,7 @@ title = "A title" #[test] fn can_get_file_hash_sha256_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(256).unwrap()); @@ -373,7 +396,7 @@ title = "A title" #[test] fn can_get_file_hash_sha256_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(256).unwrap()); @@ -384,7 +407,7 @@ title = "A title" #[test] fn can_get_file_hash_sha384_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("base64".to_string(), to_value(false).unwrap()); @@ -397,7 +420,7 @@ title = "A title" #[test] fn can_get_file_hash_sha384() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); assert_eq!( @@ -409,7 +432,7 @@ title = "A title" #[test] fn can_get_file_hash_sha512_no_base64() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(512).unwrap()); @@ -423,7 +446,7 @@ title = "A title" #[test] fn can_get_file_hash_sha512() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("app.css").unwrap()); args.insert("sha_type".to_string(), to_value(512).unwrap()); @@ -436,7 +459,7 @@ title = "A title" #[test] fn error_when_file_not_found_for_hash() { let dir = create_temp_dir(); - let static_fn = GetFileHash::new(dir.into_path(), None); + let static_fn = GetFileHash::new(dir.into_path(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("doesnt-exist").unwrap()); let err = format!("{}", static_fn.call(&args).unwrap_err()); diff --git a/components/templates/src/global_fns/helpers.rs b/components/templates/src/global_fns/helpers.rs index d5cf0ae1..51138e94 100644 --- a/components/templates/src/global_fns/helpers.rs +++ b/components/templates/src/global_fns/helpers.rs @@ -5,11 +5,12 @@ use errors::{bail, Result}; use utils::fs::is_path_in_directory; /// This is used by a few Tera functions to search for files on the filesystem. -/// This does try to find the file in 3 different spots: +/// This does try to find the file in 5 different spots: /// 1. base_path + path /// 2. base_path + static + path /// 3. base_path + content + path -/// 4. base_path + themes + {current_theme} + static + path +/// 4. base_path + {output dir} + path +/// 5. base_path + themes + {current_theme} + static + path /// A path starting with @/ will replace it with `content/` and a path starting with `/` will have /// it removed. /// It also returns the unified path so it can be used as unique hash for a given file. @@ -18,8 +19,9 @@ pub fn search_for_file( base_path: &Path, path: &str, theme: &Option, + output_path: &Path, ) -> Result> { - let mut search_paths = vec![base_path.join("static"), base_path.join("content")]; + let mut search_paths = vec![base_path.join("static"), base_path.join("content"), base_path.join(output_path)]; if let Some(t) = theme { search_paths.push(base_path.join("themes").join(t).join("static")); } @@ -37,7 +39,7 @@ pub fn search_for_file( } if !file_exists { - // we need to search in both search folders now + // we need to search in all search folders now for dir in &search_paths { let p = dir.join(&*actual_path); if p.exists() { diff --git a/components/templates/src/global_fns/images.rs b/components/templates/src/global_fns/images.rs index 6c5392b4..b7718217 100644 --- a/components/templates/src/global_fns/images.rs +++ b/components/templates/src/global_fns/images.rs @@ -12,6 +12,7 @@ pub struct ResizeImage { base_path: PathBuf, theme: Option, imageproc: Arc>, + output_path: PathBuf, } impl ResizeImage { @@ -19,8 +20,9 @@ impl ResizeImage { base_path: PathBuf, imageproc: Arc>, theme: Option, + output_path: PathBuf, ) -> Self { - Self { base_path, imageproc, theme } + Self { base_path, imageproc, theme, output_path } } } @@ -60,7 +62,7 @@ impl TeraFn for ResizeImage { } let mut imageproc = self.imageproc.lock().unwrap(); - let (file_path, unified_path) = match search_for_file(&self.base_path, &path, &self.theme) + let (file_path, unified_path) = match search_for_file(&self.base_path, &path, &self.theme, &self.output_path) .map_err(|e| format!("`resize_image`: {}", e))? { Some(f) => f, @@ -83,11 +85,12 @@ pub struct GetImageMetadata { base_path: PathBuf, theme: Option, result_cache: Arc>>, + output_path: PathBuf, } impl GetImageMetadata { - pub fn new(base_path: PathBuf, theme: Option) -> Self { - Self { base_path, result_cache: Arc::new(Mutex::new(HashMap::new())), theme } + pub fn new(base_path: PathBuf, theme: Option, output_path: PathBuf) -> Self { + Self { base_path, result_cache: Arc::new(Mutex::new(HashMap::new())), theme, output_path } } } @@ -105,7 +108,7 @@ impl TeraFn for GetImageMetadata { ) .unwrap_or(false); - let (src_path, unified_path) = match search_for_file(&self.base_path, &path, &self.theme) + let (src_path, unified_path) = match search_for_file(&self.base_path, &path, &self.theme, &self.output_path) .map_err(|e| format!("`get_image_metadata`: {}", e))? { Some((f, p)) => (f, p), @@ -139,7 +142,7 @@ mod tests { use std::fs::{copy, create_dir_all}; use config::Config; - use std::path::Path; + use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use tempfile::{tempdir, TempDir}; use tera::{to_value, Function}; @@ -172,6 +175,7 @@ mod tests { dir.path().to_path_buf(), Arc::new(Mutex::new(imageproc)), Some("name".to_owned()), + PathBuf::new(), ); let mut args = HashMap::new(); args.insert("height".to_string(), to_value(40).unwrap()); @@ -246,7 +250,7 @@ mod tests { fn can_get_image_metadata() { let dir = create_dir_with_image(); - let static_fn = GetImageMetadata::new(dir.path().to_path_buf(), None); + let static_fn = GetImageMetadata::new(dir.path().to_path_buf(), None, PathBuf::new()); // Let's test a few scenarii let mut args = HashMap::new(); diff --git a/components/templates/src/global_fns/load_data.rs b/components/templates/src/global_fns/load_data.rs index 54c34cae..a26dc2ad 100644 --- a/components/templates/src/global_fns/load_data.rs +++ b/components/templates/src/global_fns/load_data.rs @@ -89,13 +89,14 @@ impl DataSource { url_arg: Option, base_path: &Path, theme: &Option, + output_path: &Path, ) -> Result> { if path_arg.is_some() && url_arg.is_some() { return Err(GET_DATA_ARGUMENT_ERROR_MESSAGE.into()); } if let Some(path) = path_arg { - return match search_for_file(base_path, &path, theme) + return match search_for_file(&base_path, &path, &theme, &output_path) .map_err(|e| format!("`load_data`: {}", e))? { Some((f, _)) => Ok(Some(DataSource::Path(f))), @@ -169,9 +170,10 @@ pub struct LoadData { theme: Option, client: Arc>, result_cache: Arc>>, + output_path: PathBuf, } impl LoadData { - pub fn new(base_path: PathBuf, theme: Option) -> Self { + pub fn new(base_path: PathBuf, theme: Option, output_path: PathBuf) -> Self { let client = Arc::new(Mutex::new( Client::builder() .user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"))) @@ -179,7 +181,7 @@ impl LoadData { .expect("reqwest client build"), )); let result_cache = Arc::new(Mutex::new(HashMap::new())); - Self { base_path, client, result_cache, theme } + Self { base_path, client, result_cache, theme, output_path } } } @@ -224,7 +226,7 @@ impl TeraFn for LoadData { // If the file doesn't exist, source is None let data_source = match ( - DataSource::from_args(path_arg.clone(), url_arg, &self.base_path, &self.theme), + DataSource::from_args(path_arg.clone(), url_arg, &self.base_path, &self.theme, &self.output_path), required, ) { // If the file was not required, return a Null value to the template @@ -478,7 +480,7 @@ mod tests { #[test] fn fails_illegal_method_parameter() { - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value("https://example.com").unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -505,7 +507,7 @@ mod tests { let url = format!("{}{}", mockito::server_url(), "/kr1zdgbm4y"); - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(url).unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -533,7 +535,7 @@ mod tests { let url = format!("{}{}", mockito::server_url(), "/kr1zdgbm4yw"); - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(url).unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -562,7 +564,7 @@ mod tests { let url = format!("{}{}", mockito::server_url(), "/kr1zdgbm4y"); - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(url).unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -578,7 +580,7 @@ mod tests { #[test] fn fails_when_missing_file() { - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("../../../READMEE.md").unwrap()); let result = static_fn.call(&args); @@ -588,7 +590,7 @@ mod tests { #[test] fn doesnt_fail_when_missing_file_is_not_required() { - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("../../../READMEE.md").unwrap()); args.insert("required".to_string(), to_value(false).unwrap()); @@ -607,7 +609,7 @@ mod tests { .unwrap(); copy(get_test_file("test.css"), dir.path().join("static").join("test.css")).unwrap(); - let static_fn = LoadData::new(dir.path().to_path_buf(), None); + let static_fn = LoadData::new(dir.path().to_path_buf(), None, PathBuf::new()); let mut args = HashMap::new(); let val = if cfg!(windows) { ".hello {}\r\n" } else { ".hello {}\n" }; @@ -634,7 +636,7 @@ mod tests { #[test] fn cannot_load_outside_base_dir() { - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("../../README.md").unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -711,7 +713,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/zpydpkjj67"); - let static_fn = LoadData::new(PathBuf::new(), None); + let static_fn = LoadData::new(PathBuf::new(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("json").unwrap()); @@ -728,7 +730,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/aazeow0kog"); - let static_fn = LoadData::new(PathBuf::new(), None); + let static_fn = LoadData::new(PathBuf::new(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("json").unwrap()); @@ -749,7 +751,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/aazeow0kog"); - let static_fn = LoadData::new(PathBuf::new(), None); + let static_fn = LoadData::new(PathBuf::new(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("json").unwrap()); @@ -776,7 +778,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/chu8aizahBiy"); - let static_fn = LoadData::new(PathBuf::new(), None); + let static_fn = LoadData::new(PathBuf::new(), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("json").unwrap()); @@ -786,7 +788,7 @@ mod tests { #[test] fn can_load_toml() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.toml").unwrap()); let result = static_fn.call(&args.clone()).unwrap(); @@ -806,7 +808,7 @@ mod tests { #[test] fn unknown_extension_defaults_to_plain() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.css").unwrap()); let result = static_fn.call(&args.clone()).unwrap(); @@ -821,7 +823,7 @@ mod tests { #[test] fn can_override_known_extension_with_format() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.csv").unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -839,7 +841,7 @@ mod tests { #[test] fn will_use_format_on_unknown_extension() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.css").unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -854,7 +856,7 @@ mod tests { #[test] fn can_load_csv() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.csv").unwrap()); let result = static_fn.call(&args.clone()).unwrap(); @@ -874,7 +876,7 @@ mod tests { // Test points to bad csv file with uneven row lengths #[test] fn bad_csv_should_result_in_error() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("uneven_rows.csv").unwrap()); let result = static_fn.call(&args.clone()); @@ -894,7 +896,7 @@ mod tests { #[test] fn bad_csv_should_result_in_error_even_when_not_required() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("uneven_rows.csv").unwrap()); args.insert("required".to_string(), to_value(false).unwrap()); @@ -915,7 +917,7 @@ mod tests { #[test] fn can_load_json() { - let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None); + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("path".to_string(), to_value("test.json").unwrap()); let result = static_fn.call(&args.clone()).unwrap(); @@ -941,7 +943,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/kr1zdgbm4y3"); - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); @@ -973,7 +975,7 @@ mod tests { .create(); let url = format!("{}{}", mockito::server_url(), "/kr1zdgbm4y2"); - let static_fn = LoadData::new(PathBuf::from("../utils"), None); + let static_fn = LoadData::new(PathBuf::from("../utils"), None, PathBuf::new()); let mut args = HashMap::new(); args.insert("url".to_string(), to_value(&url).unwrap()); args.insert("format".to_string(), to_value("plain").unwrap()); diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index c40bc35b..1cfc83a2 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -109,11 +109,12 @@ logic applies. 1. The base directory is the Zola root directory, where the `config.toml` is 2. For the given path: if it starts with `@/`, replace that with `content/` instead and trim any leading `/` -3. Search in the following 3 or 4 locations in this order, returning the first where the file exists: - a. $base_directory + $path - b. $base_directory + "static/" + $path - c. $base_directory + "content/" + $path - d. $base_directory + "themes" + $theme + "static/" + $path only if using a theme +3. Search in the following locations in this order, returning the first where the file exists: + 1. $base_directory + $path + 2. $base_directory + "static/" + $path + 3. $base_directory + "content/" + $path + 4. $base_directory + $output_path + $path + 5. $base_directory + "themes" + $theme + "static/" + $path (only if using a theme) In practice this means that `@/some/image.jpg`, `/content/some/image.jpg` and `content/some/image.jpg` will point to the same thing.