This post is a supplemental note for the MacDevOps:YVR 2022 conference talk: Runtime and tools version management on macOSs

The slides for the MacDevOps:YVR talk can be found here

What is asdf?

The tool asdf is an amazing version manager that works on macOS and Linux and helps with version management of many tools which are used by administrators, DevOps practitioners and developers. It helps you manage the desired versions of any of your project runtimes and programming languages with a single CLI tool and command interface. You can easily start installing, manage and switch between local versions of Python, Golang, Terraform and many others in a simple, straightforward workflow.

It pursues the super-simple approach of using a single configuration and versions control via the .tool-versions file. So in practice, this single tool can help alleviate quite tedious tasks when you need proper version control for multiple languages and tools. It is also great for quickly retrieving the latest version of locally installed languages, runtimes and tools.

So again, it’s a single tool that helps you keep the installation of desired versions under control, this applies to e.g. Python, NodeJS, Ruby, golang, but also Terraform, Packer and the whole range of tools in the k8s ecosystem.

It is by no means a replacement for the usual macOS package managers like Homebrew, MacPorts or nixOS, but you can reduce the use of these to a minimum and consider them as special helpers for edge cases. Likely you no longer need the package managers to perform mundane tasks like installing a new version of Python, with the risk that the dependencies will cause trouble afterwards.

So without further ado, let’s look at how to install asdf.

Install asdf

  1. Install Xcode command line tools xcode-select --install
  2. Install coreutils dependency
    • Method A - brew install coreutils
    • Method B - downdload GPGTools for Mac, custom install MacGPG to /usr/local/MacGPG2
  3. Clone asdf git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.10.2
  4. Include asdf in your desired shell, e.g. for zsh add the following to your ~/.zshrc file:
# add to your ~/.zshrc
. $HOME/.asdf/asdf.sh
# append completions to fpath
fpath=(${ASDF_DIR}/completions $fpath)
# initialise completions with ZSH's compinit
autoload -Uz compinit && compinit

Find more specific shell-related details here

Have a look on more details, including Linux and about dependencies mhere

Getting familiar

Some quick facts about the asdf tool. All further and more detailed information can be found in the official documentation.

  • The asdf tool is a shell script

  • The asdf tool is a wrapper that relies heavily on Git under the bonnet, then uses curl to download from the source code and then launches an installer or make file.

  • The plugins are separate Git repositories hosted publicly (most on GitHub), a plugin is a sub-script called by asdf that serves two purposes, discovery to “list all” available versions of a tool, and “install” to download the sources and start an installation by placing the binary/tool or running a make script.

  • Everything that is downloaded, installed and added is stored in a hidden $HOME/.asdf directory.

  • The $HOME/.asdf/installs directory contains the versions of languages, runtimes and tools. Within a version you will find a common structure with specific directories like bin, etc, include, lib, share and possibly also installed dependencies

  • The shell (zsh, bash) to sources . $HOME/.asdf/asdf.sh and automatically reads out the .tool-versions in home directory or whenever a .tool-versions file is present in a directory, the tool versions it declares will be used in that directory and any subdirectories.

  • You a version with asdf global <name> <version> which writes the desired version to $HOME/.tool-versions.

  • In a project directory, you can pin a specific version with asdf local <name> <version> which writes the version to $PWD/.tool-versions, creating it as needed.

asdf global <name> <version> 
asdf shell <name> <version> 
asdf local <name> <version> 
# asdf global python 3.10.5

asdf global <name> latest
asdf local <name> latest
# asdf global python latest

Here are some commands that are used more often:

  • asdf list <name> - List Installed Versions
  • asdf list all <name> - List All Available Versions
  • asdf plugin list all - List plugins registered on asdf-plugins repository with URLs
  • asdf latest <name> - Show Latest Stable Version
  • asdf install <name> latest - Install Latest Stable Version
  • asdf current- Display current version set or being used for all packages
  • asdf reshim <name> <version> - Recreate shims for version of a package, find out more here

The Quick Installation Guides

With asdf installed you have usually just a 3 step process to install a new tool.

  1. Install a plugin
  2. Install a version
  3. Set a version

There exists a long list of plugins for almost all the popular tools, the complete list can be found here. The following is a short list of some starters that can be useful in the macOS context.

Python

Install latest Python 3

asdf plugin add python
asdf install python latest
asdf global python latest 

Extra default installation, e.g. Ansible, pipenv with each python version, requires creating $HOME/.default-python-packages first.

# add defaults to $HOME/.default-python-packages
ansible
pipenv

Install specific Python 3 version:

asdf install python 3.9.13
asdf global python 3.9.13 

List all local versions (e.g. of a specific samatic version)

asdf list python 3.9

  3.9.5
  3.9.6
  3.9.13

Remove a specific version:

asdf uninstall python 3.9.5

golang

  • The Go programming language is an open source project to make programmers more productive.

https://github.com/kennyp/asdf-golang

asdf plugin add golang 
asdf install golang latest
asdf global golang latest

Install with an plugin specific overwrite ASDF_GOLANG_OVERWRITE_ARCH:

asdf plugin add golang 
# ENV override for Apple Silicon Architecture download, no longer needed lately
ASDF_GOLANG_OVERWRITE_ARCH=arm64 asdf install golang latest
asdf global golang latest

The above was initially required when golang builds became available for Apple Silicon.


Node.js

  • Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

https://github.com/asdf-vm/asdf-nodejs.git

asdf plugin add nodejs
asdf install nodejs latest
asdf global nodejs latest

Ruby

  • A dynamic, open source programming language with a focus on simplicity and productivity.
asdf plugin add ruby https://github.com/asdf-vm/asdf-ruby.git
asdf install ruby latest
asdf global ruby latest

Rust

  • Rust is a systems programming language created by Mozilla. It is similar to C++, but is designed for improved memory safety without sacrificing performance.

https://github.com/code-lever/asdf-rust

rust https://github.com/code-lever/asdf-rust.git
asdf install ruby latest
asdf global ruby latest

shellcheck

  • ShellCheck, a static analysis tool for shell scripts

https://github.com/luizm/asdf-shellcheck

asdf plugin add shellcheck https://github.com/luizm/asdf-shellcheck.git
asdf install shellcheck latest
asdf global shellcheck latest

shfmt

  • A shell parser, formatter, and interpreter.

https://github.com/luizm/asdf-shfmt.git

asdf plugin add shfmt https://github.com/luizm/asdf-shfmt.git
asdf install shfmt latest
asdf global shfmt latest

tart

  • macOS VMs on Apple Silicon to use in CI and other automations.

https://github.com/headmin/asdf-tart

asdf plugin-add tart https://github.com/headmin/asdf-tart
asdf install tart latest
asdf global tart latest

mkcert

  • A simple zero-config tool to make locally trusted development certificates with any names you’d like.

https://github.com/salasrod/asdf-mkcert

asdf plugin add mkcert https://github.com/salasrod/asdf-mkcert
asdf install mkcert latest
asdf global mkcert latest

awscli

  • The AWS Command Line Interface is a unified tool to manage your AWS services

https://github.com/MetricMike/asdf-awscli

asdf plugin add awscli https://github.com/MetricMike/asdf-awscli.git
asdf install awscli latest
asdf global awscli latest

gcloud

  • The Google Cloud CLI is a set of tools to create and manage Google Cloud resources.

https://github.com/jthegedus/asdf-gcloud.git

asdf plugin add gcloud https://github.com/jthegedus/asdf-gcloud
✅  All dependencies found on system!

asdf install gcloud latest
asdf global gcloud latest

azure-cli

  • The Azure Command-Line Interface (CLI) is a cross-platform command-line tool to connect to Azure and execute administrative commands on Azure resources.

https://github.com/itspngu/asdf-azure-cli

asdf plugin add azure-cli https://github.com/itspngu/asdf-azure-cli.git
asdf install azure-cli latest
asdf global azure-cli latest

cloudflared

  • Cloudflare Tunnel client (formerly Argo Tunnel)
asdf plugin add cloudflared https://github.com/threkk/asdf-cloudflared.git

# Show all installable versions
asdf list-all cloudflared

# Install specific version
asdf install cloudflared latest

# Set a version globally (on your ~/.tool-versions file)
asdf global cloudflared latest

asdf uninstall cloudflared 2022.5.3

hub

  • hub is an extension to command-line git that helps you do everyday GitHub tasks without ever leaving the terminal.

https://github.com/vixus0/asdf-hub

asdf plugin add hub https://github.com/vixus0/asdf-hub.git
asdf install hub latest
asdf global hub latest 

Concourse

  • Concourse is an open-source continuous thing-doer. Built on the simple mechanics of resources, tasks, and jobs, Concourse presents a general approach to automation that makes it great for CI/CD..

https://github.com/mattysweeps/asdf-concourse

asdf plugin add concourse https://github.com/mattysweeps/asdf-concourse.git
asdf install concourse latest
asdf global concourse latest

hugo

  • Create identical machine images for multiple platforms from a single source configuration.

https://github.com/NeoHsu/asdf-hugo

asdf plugin add hugo https://github.com/NeoHsu/asdf-hugo.git
asdf install hugo latest
asdf global hugo latest
 

Terraform

  • Terraform is an infrastructure as code (IaC) tool that allows you to build, change, and version infrastructure safely and efficiently.

https://github.com/Banno/asdf-hashicorp.git

asdf plugin add terraform https://github.com/Banno/asdf-hashicorp.git
asdf install terraform latest
asdf global terraform latest

Packer

  • Create identical machine images for multiple platforms from a single source configuration.

https://github.com/Banno/asdf-hashicorp.git

asdf plugin add packer https://github.com/asdf-community/asdf-hashicorp.git
asdf install packer latest
asdf global packer latest
 

Vault

  • Vault brokers and deeply integrates with trusted identities to automate access to secrets, data, and systems.
asdf plugin add vault  https://github.com/Banno/asdf-hashicorp.git
asdf install vault latest
asdf global vault latest

Elasticsearch

  • Elasticsearch is a distributed, RESTful search and analytics engine capable of addressing a growing number of use cases.

https://github.com/asdf-community/asdf-elasticsearch.git

asdf plugin add elasticsearch https://github.com/asdf-community/asdf-elasticsearch.git
asdf install elasticsearch latest
asdf global elasticsearch latest
 

minicube

  • minikube is local Kubernetes, focusing on making it easy to learn and develop for Kubernetes.
asdf plugin add minikube https://github.com/alvarobp/asdf-minikube.git
asdf install minikube latest
asdf global minikube latest

jmespath

  • JMESPath is a query language for JSON.
asdf plugin add jmespath https://github.com/skyzyx/asdf-jmespath.git
asdf install jmespath latest
asdf global jmespath latest

Osqueryi

  • Osquery uses basic SQL commands to leverage a relational data-model to describe a device.

https://github.com/davidecavestro/asdf-osqueryi.git

asdf plugin add osqueryi https://github.com/davidecavestro/asdf-osqueryi.git
asdf install osqueryi latest
asdf global osqueryi latest

Poetry

  • Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.

https://github.com/asdf-community/asdf-poetry.git

asdf plugin add poetry
asdf install poetry latest
asdf global poetry latest

Terragrunt

  • Terragrunt is a thin wrapper for Terraform that provides extra tools for working with multiple Terraform modules.

https://github.com/ohmer/asdf-terragrunt

asdf plugin add terragrunt https://github.com/ohmer/asdf-terragrunt
asdf install terragrunt latest
asdf global terragrunt latest

ripgrep

  • ripgrep recursively searches directories for a regex pattern while respecting your gitignore

https://gitlab.com/wt0f/asdf-ripgrep.git

asdf plugin add ripgrep
asdf install ripgrep latest
# Downloading rg from https://github.com/BurntSushi/ripgrep/releases/download/13.0.0/ripgrep-13.0.0-x86_64-apple-darwin.tar.gz
asdf global ripgrep latest

syft

  • CLI tool and library for generating a Software Bill of Materials from container images and filesystems

https://github.com/davidgp1701/asdf-syft.git

asdf plugin add syft https://github.com/davidgp1701/asdf-syft.git
asdf install syft latest
asdf global syft latest

CLI Reference

Updating asdf

After a while, the asdf tool also needs to be updated, which is very easy task with the command asdf update.

## example update
asdf update
remote: Enumerating objects: 812, done.
remote: Counting objects: 100% (676/676), done.
remote: Compressing objects: 100% (337/337), done.
remote: Total 812 (delta 401), reused 533 (delta 328), pack-reused 136
Receiving objects: 100% (812/812), 605.28 KiB | 1.54 MiB/s, done.
Resolving deltas: 100% (436/436), completed with 53 local objects.
From https://github.com/asdf-vm/asdf
 * [new branch]      dependabot/npm_and_yarn/docs/prismjs-1.27.0 -> origin/dependabot/npm_and_yarn/docs/prismjs-1.27.0
 + 92fa595...60b87c6 gh-pages                                    -> origin/gh-pages  (forced update)
   60d1863..950e417  master                                      -> origin/master
 * [new branch]      release-v0.9.1                              -> origin/release-v0.9.1
 + 8a6a0c9...1c8648d tb/no-unset-vars                            -> origin/tb/no-unset-vars  (forced update)
 * [new branch]      tb/remove-ls                                -> origin/tb/remove-ls
 * [new tag]         v0.10.0                                     -> v0.10.0
 * [new tag]         v0.10.1                                     -> v0.10.1
 * [new tag]         v0.10.2                                     -> v0.10.2
 * [new tag]         v0.9.0                                      -> v0.9.0
Previous HEAD position was a1ef92a Update version to 0.8.1
HEAD is now at 7e7a1fa chore: release 0.10.2 (#1233)
Updated asdf to release v0.10.2

asdf command reference

Find the fulll documentation here:

Manage Plugins

MANAGE PLUGINS
asdf plugin add <name> [<git-url>]      Add a plugin from the plugin repo OR,
                                        add a Git repo as a plugin by
                                        specifying the name and repo url
asdf plugin list [--urls] [--refs]      List installed plugins. Optionally show
                                        git urls and git-ref
asdf plugin list all                    List plugins registered on asdf-plugins
                                        repository with URLs
asdf plugin remove <name>               Remove plugin and package versions
asdf plugin update <name> [<git-ref>]   Update a plugin to latest commit on
                                        default branch or a particular git-ref
asdf plugin update --all                Update all plugins to latest commit on
                                        default branch

Manage Packages

MANAGE PACKAGES
asdf install                            Install all the package versions listed
                                        in the .tool-versions file
asdf install <name>                     Install one tool at the version
                                        specified in the .tool-versions file
asdf install <name> <version>           Install a specific version of a package
asdf install <name> latest[:<version>]  Install the latest stable version of a
                                        package, or with optional version,
                                        install the latest stable version that
                                        begins with the given string
asdf uninstall <name> <version>         Remove a specific version of a package
asdf current                            Display current version set or being
                                        used for all packages
asdf current <name>                     Display current version set or being
                                        used for package
asdf where <name> [<version>]           Display install path for an installed
                                        or current version
asdf which <command>                    Display the path to an executable
asdf local <name> <version>             Set the package local version
asdf local <name> latest[:<version>]    Set the package local version to the
                                        latest provided version
asdf global <name> <version>            Set the package global version
asdf global <name> latest[:<version>]   Set the package global version to the
                                        latest provided version
asdf shell <name> <version>             Set the package version to
                                        `ASDF_${LANG}_VERSION` in the current shell
asdf latest <name> [<version>]          Show latest stable version of a package
asdf latest --all                       Show latest stable version of all the
                                        packages and if they are installed
asdf list <name> [version]              List installed versions of a package and
                                        optionally filter the versions
asdf list all <name> [<version>]        List all versions of a package and
                                        optionally filter the returned versions
asdf help <name> [<version>]            Output documentation for plugin and tool

Manage Utilities

UTILS
asdf exec <command> [args...]           Executes the command shim for current version
asdf env <command> [util]               Runs util (default: `env`) inside the
                                        environment used for command shim execution.
asdf info                               Print OS, Shell and ASDF debug information.
asdf reshim <name> <version>            Recreate shims for version of a package
asdf shim-versions <command>            List the plugins and versions that
                                        provide a command
asdf update                             Update asdf to the latest stable release
asdf update --head                      Update asdf to the latest on the master branch