After rendering a template, `tmpl` will now run any commands specified
in the `hooks` property of a template instruction. Hooks can either be
"immediate," meaning they will run as soon as the new file is written,
or "deferred," and will run after all templates have been rendered.
Deferred hooks are deduplicated: if multiple templates specify the
exact same command, it will only be run once. Hook commands can include
the `%s` placeholder, which will be replaced by the path of the rendered
file.
The `to_string()` method of `tera::Error` structures only returns the
string value for itself; the messages from the underlying errors are
not included. This effectively means any error from Tera just becomes
"failed to render template." To provide a complete message, we have to
recursively call `source()` on the error chain and append its string
representation to the error message.
The `decrypt` filter can be used in Tera templates to decrypt a string
using `age`. This will allow the template context to contain encrypted
vaules that are only decrypted if they are actually used to render a
template.
I considered using the [age] crate to implement this filter, rather
than using the `age` command, but I decided against it for two reasons:
1. The way I intend for the `keys.txt` file to be populated is by
fetching the keys from *keyserv.pyrocufflink.blue*, which returns
an encrypted file that has to be decrypted with the `age` command
before it can be used. Since that means `age` will always be
available, it makes less sense to increase the size of the `tmpl`
binary with what is effectively duplicate code.
2. The Rust API for *age* is rather un-ergonomic, particularly with
respect to loading identites from a file. It's much easier to
[age]: https://crates.io/crates/age