Managing Elixir versions with Kiex

When you're doing development work, it's often useful to have several versions of your environment around, both for testing compatibility and for working with code that was initially written for an older version of eg. Elixir, and may not work at all with newer versions.

Kiex seems to be a promising approach to this issue for Elixir, as there's both recent activity and a fair amount of commits. But nothing is certain until you try it, so let's go ahead with that!

Installation is simple as pie, according to the README.. but please read the scripts before piping them to bash on your machine!

Since I already did that, I'll just install:

$ \curl -sSL https://raw.githubusercontent.com/taylor/kiex/master/install | bash -s
Running initial environment setup
    Kiex sourcing line not found in ~/.bashrc, ~/.bash_profile, ~/.profile, ~/.zshrc, or ~/.zsh_profile
    Add the following to your shell's config file (.bashrc/.zshrc/.cshrc):
        test -s "$HOME/.kiex/scripts/kiex" && source "$HOME/.kiex/scripts/kiex"
kiex has been installed in /home/johwar/.kiex ☺ 

Let's also add the environment config accoring to instructions; I'm using a machine-local rc script for zsh that's loaded by my generic version-controlled config, so I'll put it there:

$ cat >> ~/.zshrc.include
test -s "$HOME/.kiex/scripts/kiex" && source "$HOME/.kiex/scripts/kiex"

Usage is fairly straightforward:

$ kiex
kiex commands:
    list                      - shows currently installed Elixirs
    list known                - shows available Elixir releases
    list branches             - shows available Elixir branches
    install <version>         - installs the given release version
    use <version> [--default] - uses the given version for this shell
    shell <version>           - uses the given version for this shell
    default <version>         - sets the default version to be used
    selfupdate                - updates kiex itself
    implode                   - removes kiex and all installed Elixirs
    reset                     - resets default Elixir version to null

What do we have currently, then?

$ kiex list

kiex elixirs


# No kiex elixirs installed yet. Try 'kiex install <version>'.

Fair enough, we haven't actually installed any Elixir versions yet. Let's try to get 1.0.4 installed.

kiex install 1.0.4
Already on 'master'
Your branch is up-to-date with 'origin/master'.
Switched to a new branch 'v1.0.4'
From https://github.com/elixir-lang/elixir
 * tag               v1.0.4     -> FETCH_HEAD
Already up-to-date.
cd lib/elixir && ../../rebar clean
...
Installed Elixir version 1.0.4
Load with:
           kiex use 1.0.4 
or load the elixir environment file with: 
   source $HOME/.kiex/elixirs/elixir-1.0.4.env

Looking good so far. Does it work, though?

$ which elixir
/usr/local/bin/elixir  # This is from my existing Erlang Solutions install
$ kiex use 1.0.4
Using 1.0.4
$ which elixir
/home/johwar/.kiex/elixirs/elixir-1.0.4/bin/elixir  # There we go!
$ iex
Erlang/OTP 17 [erts-6.4.1] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 

Cool, that works. But I already had Elixir 1.0.4, so no news.. Going by the availability of the list branches command, however, you should be able to install branches as well, so how about a master build?

$ kiex install master
That Elixir requires Erlang R16B or later but before R17
Erlang installation choices:
   * Download - https://www.erlang-solutions.com/downloads/download-erlang-otp
                http://www.erlang.org/download.html
   * Kerl - https://github.com/spawngrid/kerl
   * Package manager -
           Arch: See AUR package,
           FreeBSD: pkg install erlang
           OS X: brew install erlang
           Ubuntu/Debian/CentOS see erlang-solutions.com

WUT?!

Ok, let's calm down a bit.. Looking at ~/.kiex/bin/kiex, it becomes obvious that the install_elixir() function is checking the Elixir version we're installing, and trying to figure out what Erlang version that goes with it.. except only numeric versions are considered.

When we install 'master', we can safely assume that we need Erlang 17+, so let's amend that if statement (the old one is commented out below):

function install_elixir() {
  ver="$1"
  ver=${ver//v/}
  major=${ver%%.[0-9]*}
  mp=${ver#[0-9]*.}
  minor=${mp%.*[0-9]}
  patch=${ver##*[0-9].}
  # if (( $major >= 1 )) || (( $minor > 12 )); then
  if (( $major >= 1 )) || (( $minor > 12 )) || (( $ver == "master" )); then
    need_erl_17=1
  fi
  # ...
}

If we try that again now, it looks like it's working:

kiex install master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
fatal: A branch named 'master' already exists.
Already on 'master'
Your branch is up-to-date with 'origin/master'.
From https://github.com/elixir-lang/elixir
 * branch            master     -> FETCH_HEAD
Already up-to-date.
cd lib/elixir && /home/johwar/.kiex/builds/elixir-git/rebar clean
...
Installed Elixir version master
Load with:
           kiex use master 
or load the elixir environment file with: 
   source $HOME/.kiex/elixirs/elixir-master.env

If we verify by trying to use the new version, it is indeed starting up Elixir 1.1.0-dev:

$ kiex use master
Using master
$ iex
Erlang/OTP 17 [erts-6.4.1] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.1.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 

Nice, so now we've got Elixir 1.0.4 and 1.1.0-dev configured.. Go do something fun with it!

Meanwhile, I have an issue to register and a pull request to write..