Implementing dotfile templates in jinja for dotdrop. #
Only the developer, and maybe perhaps God, knows why dotdrop uses a custom version of the Jinja templating system, but here we are. Isn't it bloody glorious?
You would think there would have been a better option?
Chezmoi is looking real good right about now.
Creating your new abomination of markup #
So, let's get down to business and run this railroad right into the ground.
Delimiters #
Well, as you know, delimiters delimit things. Which means they indicate a beginning and an end to a region or section of text that needs distinction from the text around it. The delimiters used by dotdrop are what makes it distinct from standard jinja templating markup. Here they are.
- Block/Statement start =
{%@@ - Block/Statement end =
@@%} - Variable/Expression start =
{{@@ - Variable/Expression end =
@@}} - Comment start =
{#@@ - Comment end =
@@#}
The Header #
Although, not required, it is reccommended to begin your dotdrop template with a bloody header, like so:
1{{@@ header() @@}}
Variables #
[!info] I Shamelessly copied this directly from the dotdrop docs to save time.
Template variables #
Available variables #
The following variables are available in templates:
{{@@ profile @@}}contains the profile provided to dotdrop.{{@@ env['MY_VAR'] @@}}contains environment variables (see Environment variables).{{@@ header() @@}}contains the dotdrop header (see Dotdrop header).{{@@ _dotdrop_dotpath @@}}contains the dotpath absolute path.{{@@ _dotdrop_cfgpath @@}}contains the config file absolute path.{{@@ _dotdrop_workdir @@}}contains the workdir absolute path.- All variables defined in the config
- Dotfile specific variables (see Dotfile variables)
Enriched variables #
The below variables are added to the available variables within templates. If the variable is already set by the user (through the config file for example) it will not be overwritten.
{{@@ os @@}}will contain the OS name as provided by https://docs.python.org/3/library/platform.html#platform.system{{@@ release @@}}will contain the OS release version as provided by https://docs.python.org/3/library/platform.html#platform.release{{@@ distro_id @@}}will contain the distribution ID as provided by https://distro.readthedocs.io/en/latest/#distro.id{{@@ distro_version @@}}will contain the distribution version as provided by https://distro.readthedocs.io/en/latest/#distro.version{{@@ distro_like @@}}will contain a space-separated list of distro IDs that are closely related to the current OS distro as provided by https://distro.readthedocs.io/en/latest/#distro.like
Dotfile variables #
When a dotfile is handled by dotdrop, the following variables are also available for templating:
{{@@ _dotfile_abs_src @@}}contains the processed dotfile absolute source path.{{@@ _dotfile_abs_dst @@}}contains the processed dotfile absolute destination path.{{@@ _dotfile_key @@}}contains the processed dotfile key.{{@@ _dotfile_link @@}}contains the processed dotfilelinkstring value.
In addition to the above, the following variables are set in each file processed by dotdrop:
{{@@ _dotfile_sub_abs_src @@}}contains the absolute source path of each file when handled by dotdrop.{{@@ _dotfile_sub_abs_dst @@}}contains the absolute destination path of each file when handled by dotdrop.
For example, a directory dotfile (like ~/.ssh) would process several files
(~/.ssh/config and ~/.ssh/authorized_keys, for example). In ~/.ssh/config:
_dotfile_abs_dstwould be/home/user/.ssh_dotfile_sub_abs_dstwould be/home/user/.ssh/config
Environment variables #
It's possible to access environment variables inside the templates:
{{@@ env['MY_VAR'] @@}}
This allows for storing host-specific properties and/or secrets in environment variables.
It is recommended to use variables (see config variables)
instead of environment variables unless these contain sensitive information that
shouldn't be versioned in Git (see handle secrets doc).
Variables dictionary #
All variables are also available through the dictionary _vars
{%@@ for key in _vars @@%}
key:{{@@ key @@}} - value:{{@@ _vars[key] @@}}
{%@@ endfor @@%}
Methods #
[!info] I did the same thing here.
Besides Jinja2 global functions, the following methods can be used within templates:
exists(path): returns true when path exists
{%@@ if exists('/dev/null') @@%}
it does exist
{%@@ endif @@%}
exists_in_path(name, path=None): returns true when executable exists in$PATH
{%@@ if exists_in_path('exa') @@%}
alias ls='exa --git --color=always'
{%@@ endif @@%}
basename(path): returns thebasenameof the path argument
{%@@ set dotfile_filename = basename( _dotfile_abs_dst ) @@%}
dotfile dst filename: {{@@ dotfile_filename @@}}
dirname(path): returns thedirnameof the path argument
{%@@ set dotfile_dirname = dirname( _dotfile_abs_dst ) @@%}
dotfile dst dirname: {{@@ dotfile_dirname @@}}
Custom user-defined functions can be loaded with the help of the
config entry func_file.
Example:
The config file:
1config:
2 func_file:
3 - /tmp/myfuncs_file.py
The python function under /tmp/myfuncs_file.py:
1def myfunc(arg):
2 return not arg
The dotfile content:
{%@@ if myfunc(False) @@%}
this should exist
{%@@ endif @@%}
Filters #
[!info] And I could have been different and written this out, but I didn't.
Besides Jinja2 builtin filters,
custom user-defined filter functions can be loaded using the config entry filter_file:
Example:
The config file:
1config:
2 filter_file:
3 - /tmp/myfilter_file.py
The python filter under /tmp/myfilter_file.py:
1def myfilter(arg1):
2 return str(int(arg1) - 10)
The dotfile content:
{{@@ "13" | myfilter() @@}}
For more information on how to create filters, see the Jinja2 official docs.