Skip to content

Commit

Permalink
Fix cachebust for files in the output path (#1586)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
InputUsername committed Aug 19, 2021
1 parent c658d17 commit 5ca2b29
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 67 deletions.
20 changes: 17 additions & 3 deletions components/site/src/tpls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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(())
Expand Down
67 changes: 45 additions & 22 deletions components/templates/src/global_fns/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ pub struct GetUrl {
base_path: PathBuf,
config: Config,
permalinks: HashMap<String, String>,
output_path: PathBuf,
}

impl GetUrl {
pub fn new(base_path: PathBuf, config: Config, permalinks: HashMap<String, String>) -> Self {
Self { base_path, config, permalinks }
pub fn new(
base_path: PathBuf,
config: Config,
permalinks: HashMap<String, String>,
output_path: PathBuf,
) -> Self {
Self { base_path, config, permalinks, output_path }
}
}

Expand Down Expand Up @@ -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::<Sha256>(f, false).ok())
Expand Down Expand Up @@ -142,10 +148,11 @@ impl TeraFn for GetUrl {
pub struct GetFileHash {
base_path: PathBuf,
theme: Option<String>,
output_path: PathBuf,
}
impl GetFileHash {
pub fn new(base_path: PathBuf, theme: Option<String>) -> Self {
Self { base_path, theme }
pub fn new(base_path: PathBuf, theme: Option<String>, output_path: PathBuf) -> Self {
Self { base_path, theme, output_path }
}
}

Expand All @@ -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,
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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");
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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!(
Expand All @@ -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());
Expand All @@ -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());
Expand All @@ -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());
Expand Down
10 changes: 6 additions & 4 deletions components/templates/src/global_fns/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -18,8 +19,9 @@ pub fn search_for_file(
base_path: &Path,
path: &str,
theme: &Option<String>,
output_path: &Path,
) -> Result<Option<(PathBuf, String)>> {
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"));
}
Expand All @@ -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() {
Expand Down
18 changes: 11 additions & 7 deletions components/templates/src/global_fns/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ pub struct ResizeImage {
base_path: PathBuf,
theme: Option<String>,
imageproc: Arc<Mutex<imageproc::Processor>>,
output_path: PathBuf,
}

impl ResizeImage {
pub fn new(
base_path: PathBuf,
imageproc: Arc<Mutex<imageproc::Processor>>,
theme: Option<String>,
output_path: PathBuf,
) -> Self {
Self { base_path, imageproc, theme }
Self { base_path, imageproc, theme, output_path }
}
}

Expand Down Expand Up @@ -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,
Expand All @@ -83,11 +85,12 @@ pub struct GetImageMetadata {
base_path: PathBuf,
theme: Option<String>,
result_cache: Arc<Mutex<HashMap<String, Value>>>,
output_path: PathBuf,
}

impl GetImageMetadata {
pub fn new(base_path: PathBuf, theme: Option<String>) -> Self {
Self { base_path, result_cache: Arc::new(Mutex::new(HashMap::new())), theme }
pub fn new(base_path: PathBuf, theme: Option<String>, output_path: PathBuf) -> Self {
Self { base_path, result_cache: Arc::new(Mutex::new(HashMap::new())), theme, output_path }
}
}

Expand All @@ -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),
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 5ca2b29

Please sign in to comment.