Switching from pyenv, rbenv, goenv and nvm to asdf
Table of Contents
So, there was a time when I was only developing applications using Python
. And so I found out about virtual environments.
And then after a couple of months, I discovered pyenv
.
It also came to a time I had to work on multiple projects that uses different versions of nodejs
and searched something similar
so I installed nvm
.
Then, I was required to work on a Ruby
project so I installed rbenv
.
And since golang
was one of the new shiny objects that kinda got my interest, I went on and installed goenv
.
Everything was fine until I kinda felt my config.fish
file got bloated and somehow nvm
was kinda slowing down my shell startup.
I did do some optimizations such as lazy loading nvm
and used a fish
plugin called fish-nvm.
And then one day, I found out about asdf-vm.
At first, I was quite hesitant to install it since it would kinda disrupt my work flow with python projects since I heavily use pyenv virtualenv <version> <name>
.
But I did feel that the benefits of using asdf-vm
outweighs the cons so I went ahead and proceeded.
Installation #
$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.8
asdf
has a pretty good documentation to be honest. Despite brew
being my go to package manager, I chose git
as my installation method.
My reason is that asdf
requires me to add this line in my config.fish
source (brew --prefix asdf)/asdf.fish
and the brew --prefix adsf
is just too slow compared to just having this
source $HOME/.asdf/asdf.fish
Next, for the auto completions just run this command in your terminal:
$ mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions
Restart your shell so that PATH changes take effect!
You can checkout a more detailed documentation here: https://asdf-vm.com/#/core-manage-asdf-vm?id=install
Before, my config.fish
looked something like this:
# pyenv
set -gx PYENV_ROOT $HOME/.pyenv
set -gx PYTHON_BUILD_ARIA2_OPTS "-x 10 -k 1M" # Use aria2c when downloading
contains $PYENV_ROOT/bin $fish_user_paths; or set -Ua fish_user_paths $PYENV_ROOT/bin
status --is-interactive; and pyenv init - | source
status --is-interactive; and pyenv virtualenv-init - | source
# goenv
set -gx GOENV_GOPATH_PREFIX $HOME/.go
status --is-interactive; and goenv init - | source
# rbenv
status --is-interactive; and rbenv init - | source
# Set nvm aliases and add to path
set -gx nvm_alias_output $HOME/.node_aliases
contains $nvm_alias_output $fish_user_paths; or set -Ua fish_user_paths $nvm_alias_output
After
# pyenv (asdf still uses pyenv under the hood)
set -gx PYTHON_BUILD_ARIA2_OPTS "-x 10 -k 1M" # Use aria2c when downloading
# asdf
source $HOME/.asdf/asdf.fish
Installing pyenv, rbenv, goenv, and nvm replacements #
Again, most of the things I put here just came from the documentation: https://asdf-vm.com/#/core-manage-plugins?id=add
pyenv replacement #
$ asdf plugin add python
$ asdf install python latest:3 # At the moment of writing this, it installed 3.8.4
$ asdf global python 3.8.4 # This sets python 3.8.4 as our default python version
rbenv replacement #
$ asdf plugin add ruby
$ asdf install ruby latest # We can omit the version number. Currently installs 2.7.1
$ asdf global ruby 2.7.1
goenv replacement #
$ asdf plugin add golang
$ asdf install golang latest # 1.14.6
$ asdf global golang 1.14.6
nvm replacement #
$ asdf plugin add nodejs
$ asdf install nodejs 12.18.2
$ asdf global nodejs 12.18.2
Using asdf global
creates a file under your HOME directory called .tool-versions
$ cat ~/.tool-versions
python 3.8.4
ruby 2.7.1
golang 1.14.6
nodejs 12.18.2
This lets asdf
know which versions to use. And of course, in contrast to global
,
there is also the local
keyword that creates another .tool-versions
.
This is useful when projects require different version.
$ cd ~/project1
$ asdf local python 3.7.5
$ python --version # Uses the python version specified in .tool-versions
3.7.5
$ cd ~/project2
$ python --version # Uses the python version specified in ~/.tool-versions
3.8.4
asdf
has a lot of plugins available. You can check them out here: https://github.com/asdf-vm/asdf-plugins
Extras #
In order to accommodate my work flow when I was still using pyenv virtualenv
,
I created a function that behaves quite similar to pyenv virtualenv
.
$ touch ~/.config/fish/functions/venv.fish
And paste the following:
function venv --argument-names 'python_version' --description 'Create virtualenv named the same as current directory'
set -l python_bin
if not test -n "$python_version"
# Use default python version set by asdf
set python_bin ($HOME/.asdf/bin/asdf which python)
else
set python_bin $ASDF_DIR/installs/python/$python_version/bin/python
end
set -l venv_name (basename $PWD | tr . -)
echo
if not test -e $python_bin
echo "Python version `$python_version` is not installed."
return 1
end
echo Creating virtualenv `$venv_name`
$python_bin -m venv $HOME/.virtualenvs/$venv_name
source $HOME/.virtualenvs/$venv_name/bin/activate.fish
end
Whenever I’m inside a python project, I just need to type venv
or venv <python_version>
and it will automatically create a virtualenv under ~/.virtualenvs
using the current directory name.
In order to automatically activate the virtualenv when cd
ing to a project, do the following:
$ touch ~/.config/fish/conf.d/__auto_venv.fish
And paste the following:
function __auto_venv --on-variable PWD --description "Automatically activate python venv"
set -l venv_name (basename $PWD | tr . -)
if test -d $HOME/.virtualenvs/$venv_name
source $HOME/.virtualenvs/$venv_name/bin/activate.fish
end
end
Cool! Not only did I reduce the lines in my config.fish
, I could also notice a decreased startup time which is a good thing!
You can also check out my dotfiles in my GitHub repository: https://github.com/yujinyuz/dotfiles
I hope this article helped you! You can leave a comment below and I’ll try to answer them as fast as I can.
Thanks for reading! 🎉