dustin/tmpl/pipeline/head This commit looks goodDetails
The `buildContainerImage2` function assumes the default branch name is
*main*, but it's *master* for this repository. If this is not correct,
the `latest` tag will not be updated in the container registry.
dustin/tmpl/pipeline/head This commit looks goodDetails
The `buildContainerImage2` function now accepts a `pi` argument, which
controls whether or not the build can run on a Raspberry Pi. Since the
only reason we were not using this function before was to avoid building
on a Pi, we no longer need the custom code.
Building a static executable and distributing it in a "from scratch"
container image dramatically reduces the image size: down to 8 MB from
102 MB.
Reimplementing this change because this image is no longer the base for
*infra/cfg*. That image is now based on Alpine and copies in the `tmpl`
executable.
Iterating over a `HashSet` produces items in an arbitrary order. A
`BTreeSet`, on the other hand, produces items in the same order they
were inserted. Thus, this structure is more appropriate, since the
execution order of hooks may be important in some cases.
The `write_file` function will no longer overwrite existing files if the
content has not changed. This will ensure file metadata timestamps are
accurate, and reduce unnecessary filesystem activity.
Using `Read::read_exact` is not the correct way to read a file in
chunks. When it returns `UnexpectedEof`, the buffer has data in it, but
is zero-padded to the end. This causes the calculated checksum to be
incorrect.
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