-
Notifications
You must be signed in to change notification settings - Fork 991
/
Copy pathhelpers.rs
59 lines (53 loc) · 1.92 KB
/
helpers.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use std::borrow::Cow;
use std::path::{Path, PathBuf};
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 5 different spots:
/// 1. base_path + path
/// 2. base_path + static + path
/// 3. base_path + content + 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.
/// It will error if the file is not contained in the Zola directory.
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"), base_path.join(output_path)];
if let Some(t) = theme {
search_paths.push(base_path.join("themes").join(t).join("static"));
}
let actual_path = if path.starts_with("@/") {
Cow::Owned(path.replace("@/", "content/"))
} else {
Cow::Borrowed(path.trim_start_matches('/'))
};
let mut file_path = base_path.join(&*actual_path);
let mut file_exists = file_path.exists();
if file_exists && !is_path_in_directory(base_path, &file_path)? {
bail!("{:?} is not inside the base site directory {:?}", path, base_path);
}
if !file_exists {
// we need to search in all search folders now
for dir in &search_paths {
let p = dir.join(&*actual_path);
if p.exists() {
file_path = p;
file_exists = true;
break;
}
}
}
if file_exists {
Ok(Some((file_path, actual_path.into_owned())))
} else {
Ok(None)
}
}