Managing Elixir runtime version with asdf

An uncomfortably common problem when developing for a particular programming language is needing to deal with compatibility issues across different versions of the language runtime. Most often this means keeping individual projects tied to their then-current version of the language until such time that the project can address any compatibility issues with later language releases. To that end, Ruby developers are probably familiar with one of rbenv, chruby or rvm, for example. Elixir isn’t much different in this regard.

One available project that I find pretty promising is asdf, which is self-described as:

[An] extendable version manager with support for Ruby, Node.js, Elixir, Erlang & more

It fulfills some of the same roles that rbenv and friends do, while supporting multiple languages and even other software tools in a fairly standardized way.

Installation

Homebrew

brew install asdf

Follow the instructions in the output, which you can read again with brew info asdf if you missed them. As of this writing, those instructions are:

Add the following line to your bash profile (e.g. ~/.bashrc, ~/.profile, or ~/.bash_profile)

source /usr/local/opt/asdf/asdf.sh

If you use Fish shell, add the following line to your fish config (e.g. ~/.config/fish/config.fish)

source /usr/local/opt/asdf/asdf.fish

Git

You can follow the latest manual installation instructions from the project’s README, but today it includes:

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.4.0

# install shell hooks
# I personally prefer `source` to `.`

# bash users
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bash_profile
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.bash_profile

# zsh users
echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.zshrc
echo -e '\n. $HOME/.asdf/completions/asdf.bash' >> ~/.zshrc

# fish users
echo 'source ~/.asdf/asdf.fish' >> ~/.config/fish/config.fish
mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions

Prerequisites

At the time of writing, here are the prerequisites recommended to use asdf, which can be installed with Homebrew:

brew install autoconf automake coreutils \
     libtool libxslt libyaml openssl \
     readline unixodbc

Install required asdf plugins

You can check the available plugins, based on the open-source plugin index here:

asdf plugin-list-all

After identifying desirable plugins:

asdf plugin-install erlang
asdf plugin-install elixir
# phoenix users will likely also want:
asdf plugin-install nodejs

Usage

To install the latest Erlang and Elixir versions at the time of writing:

asdf install erlang 20.2
asdf install elixir 1.5.3

Phoenix users will also want:

asdf list-all nodejs
asdf install nodejs 9.3.0

Checking available tool versions

You can see what versions asdf currently supports for installation with this command:

# asdf list-all [plugin]
asdf list-all erlang
asdf list-all elixir
asdf list-all nodejs

Each plugin is able to implement this behavior in its own way, so their behavior may vary. Some are able to directly examine the releases of the upstream language project, others require manual support within the asdf plugin in question, and so may lag behind new releases.

Installing a specific Erlang patch version

The author of asdf, @HashNuke on GitHub, cleared up in this GitHub issue that any tagged release of Erlang can be installed with asdf-erlang:

We already support it. You can do the following:

asdf install erlang ref:OTP-20.1.2

Where OTP-20.1.2 is a valid tag that you can find on https://github.com/erlang/otp/releases. You can also specify a commit sha or branch name if you insist on the latest super-powers.

As of this writing the latest release is 20.2.2, so that can be installed like so:

asdf install erlang ref:OTP-20.2.2
# set global default
asdf global erlang ref:OTP-20.2.2

Installing Elixir from master

If you’d like to use the latest and greatest features, such as the upcoming mix format command slated for inclusion in Elixir 1.6, you can install the current version of the elixir-lang/elixir repository’s master branch:

asdf install elixir master

You can use this version all the time via asdf global or asdf local, or on one-off commands by setting the ASDF_ELIXIR_VERSION environment variable to master.

Per-project tool versions

By using asdf local, you can configure pre-project tool versions, which are persisted in a project-local .tool-versions file you may wish to include in your global .gitignore. When revisiting a project later, you can run asdf install with no additional arguments to ensure that the project’s desired software versions are available.

Keeping up to date

To update asdf itself:

asdf update

To update asdf plugins:

# update all plugins
asdf plugin-update --all
# update individual plugin
asdf plugin-update erlang

Troubleshooting

You can inspect where a particular version of a particular language is installed with asdf where:

asdf where erlang 20.2
# /Users/shane/.asdf/installs/erlang/20.2

You can make sure that newly-installed binaries (such as those installed by npm) are detected by using asdf reshim:

asdf reshim nodejs 9.3.0
# no output

You can inspect which specific binary will be used in your current context, accounting for both global and local tool versions, with asdf which:

asdf which erlang
# /Users/shane/.asdf/installs/erlang/20.1/bin/erlang

Other notable plugins

Here are a few other asdf plugins I’m prone to using in the course of my infrastructure-focused work:

Alternatives

There are many alternative options for installing Elixir. Here are a few in no particular order and with no specific endorsement:

Software/Tool Versions

Software Version
OSX 10.12.6
asdf 0.4.0
Elixir 1.5.3
Erlang 20.2.2
Node.js 9.3.0
Tags// , , ,
comments powered by Disqus