Keats / tera

A template engine for Rust based on Jinja2/Django
http://keats.github.io/tera/
MIT License
3.43k stars 280 forks source link

Non existent path causes panic instead of Error result #819

Closed chupaty closed 1 year ago

chupaty commented 1 year ago

New versions of tera panic instead of returning Error when passed an invalid glob path. For example: rsgen-avro

let mut tera = Tera::new("/dev/null/*")?;

Problem caused by use of unwrap() instead of ? operator, for example:

tera.rs let parent_dir = std::fs::canonicalize(parent_dir).unwrap();

Keats commented 1 year ago

That's not good, I'll fix it today unless someone beats me to it

On Wed, 15 Mar 2023, 02:23 chupaty, @.***> wrote:

New versions of tera panic instead of returning Error when passed an invalid glob path. For example: rsgen-avro https://github.com/lerouxrgd/rsgen-avro/blob/9e3eb0bfd0f7ba7a583bb7f3166fd67c41f4e708/src/templates.rs#L338

let mut tera = Tera::new("/dev/null/*")?;

Problem caused by use of unwrap() instead of ? operator, for example:

tera.rs https://github.com/Keats/tera/blob/226d0108cdb64c8d056e46c5c9a67a4a4e8549ea/src/tera.rs#L135 let parent_dir = std::fs::canonicalize(parent_dir).unwrap();

— Reply to this email directly, view it on GitHub https://github.com/Keats/tera/issues/819, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFGDI2UPDC2CXBK4QZ25KLW4EKXVANCNFSM6AAAAAAV3FAIN4 . You are receiving this because you are subscribed to this thread.Message ID: @.***>

vimpostor commented 1 year ago

@Keats

Your fix caused a regression in behaviour (well to be fair, the behaviour regression was already present in #799). Before this patch series, tera would allow invalid globs but expand them to the empty set. Now they always lead to an error.

This feature was useful, because in zola it was possible to remove the templates directory completely of a static website and just use the templates directory of the theme in use.

Now with this change, this is no longer possible and zola always requires the templates directory to exist (it can be empty though). This is because zola calls Tera::parse(&tpl_glob).context("Error parsing templates from the /templates directory"), which will now error with this change. Before the change it would just internally expand the invalid glob to the empty set, which is completely fine, because zola extends it later with the theme's template directory and with zola's builtin templates.

To me this change doesn't make any sense, because it is inconsistent:

In my opinion both cases should have the same behaviour, i.e. both cases should expand to the empty set, and not return an error just because an internal implementation detail (std::fs::canonicalize) requires the path to exist.

Please see the following patch for a simple fix, that will return to the old behaviour but still with the fix from #799 present. If you agree, I can also make a PR.

diff --git a/src/tera.rs b/src/tera.rs
index bf29f6d..1aece99 100644
--- a/src/tera.rs
+++ b/src/tera.rs
@@ -132,7 +132,10 @@ impl Tera {
         // See https://github.com/Keats/tera/issues/574 for the Tera discussion
         // and https://github.com/Gilnaa/globwalk/issues/28 for the upstream issue.
         let (parent_dir, glob_end) = glob.split_at(glob.find('*').unwrap());
-        let parent_dir = std::fs::canonicalize(parent_dir)?;
+        let parent_dir = match std::fs::canonicalize(parent_dir) {
+            Ok(d) => d,
+            Err(_) => std::path::PathBuf::from(parent_dir),
+        };
         let dir = parent_dir.join(glob_end).into_os_string().into_string().unwrap();

         // We are parsing all the templates on instantiation
@@ -1225,6 +1228,6 @@ mod tests {
     fn doesnt_panic_on_invalid_glob() {
         let tera = Tera::new("\\dev/null/*");
         println!("{:?}", tera);
-        assert!(tera.is_err());
+        assert!(tera.is_ok());
     }
 }

Otherwise if you insist this is the correct behaviour in tera, this can also be fixed from zola's side.

Keats commented 1 year ago

I think it makes sense and is consistent for me to return an error if a path doesn't exist? templates/* can perfectly be empty if there are no files, however if the folder doesn't exist I'd want to know rather than silently ignoring whatever is given.

vimpostor commented 1 year ago

Your opinion is perfectly reasonable, it just doesn't match what most other languages do. In Bash it can be controlled with the failglob option, which is off by default. Similarly Python's glob.glob("/dev/null/*") returns the empty list instead of failing. Also note that in Rust globwalk doesn't error as well, the error simply comes from the usage of std::fs::canonicalize.

Maybe it's better to fix the problem in zola.

T3kla commented 10 months ago

I have spent 2 hours searching why the hell my Zola project wasn't building to GitHub Pages. Turns git wasn't pushing the empty templates folder.