In a previous post, I mentioned we would revisit chezmoi templates. Today, let’s explore how to use these templates to manage your tool versions with asdf.
Data
Chezmoi lets you define a mini database to store whatever you want! These data must be defined in the .chezmoidata/ folder.
Let’s start by creating an asdf.yaml
file in this folder to store our tool versions.
asdf:
version: 0.18.0
tools:
- name: age
version: 1.2.1
plugin_url:
- name: bat
version: 0.25.0
plugin_url:
- name: chezmoi
version: 2.64.0
plugin_url:
- name: github-cli
version: 2.76.2
plugin_url:
- name: golang
version: 1.25.0
plugin_url:
- name: hugo
version: 0.148.2
plugin_url:
- name: lazygit
version: 0.54.2
plugin_url:
- name: lsd
plugin_url: https://github.com/ossareh/asdf-lsd.git
version: 1.1.5
- name: neovim
version: 0.11.3
plugin_url:
- name: nodejs
version: 24.6.0
plugin_url:
- name: rclone
version: 1.70.3
plugin_url:
- name: shellcheck
version: 0.11.0
plugin_url:
- name: shfmt
version: 3.12.0
plugin_url:
- name: upx
version: 5.0.2
plugin_url:
- name: yq
version: 4.47.1
plugin_url:
- name: gum
version: 0.16.2
plugin_url:
- name: starship
version: 1.23.0
plugin_url:
Templates
Chezmoi allows you to use templates to customize your configuration files. You can use variables to replace values in your files.
Chezmoi templates use the Go template language. More precisely, they use Go’s text/template library for rendering. This means you can use all the features of this library, including functions, pipelines, and conditions. See the documentation
Here, we’ll generate the ~/.tool-versions
file from the data defined in asdf.yaml
.
Quick reminder: the file starts with a dot 👉 so we need to use dot
to symbolize it. Add .tmpl
to indicate it’s a template.
{{ range .asdf.tools -}}
{{ .name }} {{ .version }}
{{ end -}}
Simple, right?
Template explanation
{{ range .asdf.tools -}}
creates a loop to iterate over each tool defined inasdf.yaml
.{{ .name }} {{ .version }}
displays the name and version of each tool.{{ end }}
ends the loop.
Scripts
Where chezmoi excels is in script management. You can easily define scripts to run when certain files are modified.
In our case, chezmoi will update our .tool-versions
, but it can also run the necessary commands for asdf to install the tools!
Even better, you can combine templates and scripts to further automate your workflow.
Let’s create the file run_onchange_dot_tool-versions.sh.tmpl
in the .chezmoiscripts/
folder.
.chezmoiscripts/run_onchange_dot_tool-versions.sh.tmpl
:
{{- if eq .chezmoi.os "linux" -}}
#!/bin/bash
# function install_asdf
function install_asdf() {
base_url="https://github.com/asdf-vm/asdf/releases/download/"
rm -f asdf-v{{ .asdf.version }}-{{ .chezmoi.os }}-{{ .chezmoi.arch }}.tar.gz*
wget "${base_url}v{{ .asdf.version }}/asdf-v{{ .asdf.version }}-{{ .chezmoi.os }}-{{ .chezmoi.arch }}.tar.gz"
tar -xvzf asdf-v{{ .asdf.version }}-{{ .chezmoi.os }}-{{ .chezmoi.arch }}.tar.gz -C ~/.asdf/bin
# clean up
rm -f asdf-v{{ .asdf.version }}-{{ .chezmoi.os }}-{{ .chezmoi.arch }}.tar.gz*
export ASDF_DATA_DIR={{ .chezmoi.config.destDir }}/.asdf
export PATH="$ASDF_DATA_DIR/shims:$ASDF_DATA_DIR/bin:$PATH"
}
# install asdf
# if ~/.asdf not exist then install asdf
if [ ! -d ~/.asdf ]; then
mkdir -p ~/.asdf/bin
fi
# if ~/.asdf/bin/asdf not exist or not executable then install asdf
if [ ! -x ~/.asdf/bin/asdf ]; then
install_asdf
fi
# if asdf version is not the right one then install asdf
if [ "$(~/.asdf/bin/asdf --version | cut -d ' ' -f 3)" != "v{{ .asdf.version }}" ]; then
install_asdf
fi
{{ range .asdf.tools -}}
# install plugins
# if .plugin_url does not exist then use ""
if [ -z "$(~/.asdf/bin/asdf plugin list | grep {{ .name }})" ]; then
echo "installing {{.name}} plugin"
~/.asdf/bin/asdf plugin add {{ .name }} {{ .plugin_url | default "" }}
else
# if plugin is already installed then update it
~/.asdf/bin/asdf plugin update {{ .name }}
fi
{{ end -}}
{{ range .asdf.tools -}}
# install tool
# if tool is not installed then install it
echo "installing {{.name}} {{.version}}"
if [ -z "$(~/.asdf/bin/asdf list {{ .name }} | grep {{ .version }})" ]; then
~/.asdf/bin/asdf install {{ .name }} {{ .version }}
fi
# remove old versions
for mytool in $(asdf list {{ .name }} | grep -v {{ .version }} | sed -e s/\*//); do
echo "removing {{ .name }} $mytool"
asdf uninstall {{ .name }} $mytool;
done;
{{ end -}}
{{ end -}}
Script explanation
I’ll just cover the main points:
- The script starts by checking if the operating system is Linux.
- It defines a function to install asdf.
- It ensures the folder needed for asdf installation exists.
- It checks if asdf is already installed, and if not, installs it.
- For each tool, it checks that the plugin is installed and up to date.
- For each tool, it ensures the version specified in
~/.tool-versions
is installed. - Finally, for each tool, it cleans up old versions.
Conclusion
We’ve seen how to use chezmoi to manage tool versions with asdf. By combining templates and scripts, you can automate your workflow and ensure your tools are always up to date. Feel free to explore more chezmoi features and adapt them to your needs.
Note: data files cannot be templated (at least for now).
Once again, you can get inspiration from my dotfiles.