Управление версиями чего угодно при помощи asdf

Опубликовано: 13 мая 2020, Ср, автор: Андрей Семакин Обновлено: 13 мая 2020, Ср 6 минут

asdf

Нет, это не просто кто-то уронил четыре пальца на клавиатуру!

В предыдущей статье я писал про pyenv — отличный инструмент для установки различных версий интерпретатора. Для питонистов pyenv вполне достаточно, но люди, пишущие на нескольких языках, могут обнаружить себя в ситуации, когда им приходится держать установленными pyenv, rvm / rbenv, nvm, rustup, gvm или ещё какие-нибудь менеджеры версий для разных языков программирования. При этом, конечно же, у каждого инструмента свой синтаксис команд, свои тонкости по работе с ним, свои зависимости. Если установить это всё сразу в свой шелл, то боюсь представить, что будет с переменной $PATH (она будет очень толстой). Потенциально это может замедлить работу шелла вообще. Но все эти проблемы остались в прошлом — встречайте asdf, универсальный менеджер версий!

asdf meme

asdf, так же как и pyenv, написан на чистом bash. Это означает, что инструмент отлично работает под Linux и MacOS, но, к сожалению, никак не работает на Windows (ну, разве что в WSL). asdf сам по себе не требует никаких внешних зависимостей, кроме некоторых базовых утилит, типа git и curl, которые и так наверняка у вас есть. Эти утилиты нужны для установки плагинов.

Вокруг asdf выстроилась огромная экосистема плагинов. Именно благодаря плагинам asdf и именует себя универсальным менеджером версий.

Преимущества:

  • не нужно учить диалекты команд для каждой отдельной утилиты, чтобы делать типовые действия;
  • умеет управлять версиями всех мыслимых и немыслимых инструментов и языков программирования через плагины;
  • можно настроить версии локально для определённой директории и asdf автоматически переключит версии инструментов при входе в неё;
  • классное название — удобно печатать.

Недостатки:

  • у каждого плагина могут быть свои тонкости в плане настройки и свои зависимости, так что придётся читать инструкции, но, как правило, это единоразовые действия.

Установка

Установка во всех подробностях описана на официальном сайте. Глупо было бы пытаться описать установку лучше, чем на оф.сайте — лучше и не напишешь. Документация у asdf просто бомбическая. Есть варианты установки на Linux или MacOS (через brew), описана настройка для всех популярных шеллов — bash, zsh и fish. Всё просто — выбираете вашу систему и шелл, и получаете команды по установке и настройке.

Обратите внимание, что для корректной работы asdf требует наличия git и curl. Если вдруг у вас в системе нет таких утилит, то инструкции по установке опять-таки можно найти на сайте asdf.

После установки перезапустите ваш шелл и проверьте установку:

$ asdf
...
"Late but latest"
-- Rajinikanth

Если вы видите этот девиз asdf после справки по командам, то установка удалась, можно продолжать. Девиз в моём вольном переводе означает что-то типа "да, поздновато, но после нас подобных утилит уже не будет". Амбициозно, но я думаю, что asdf и правда в силах вытеснить с рынка все другие подобные утилиты, которые специфичны для одного языка.

Плагины

По умолчанию asdf поставляется без плагинов и содержит только базовую функциональность, такую как управление плагинами. asdf без плагинов по сути не делает ничего полезного. Чтобы управлять версиями чего-либо, нужно установить соответствующий плагин. Давайте запросим список доступных к установке плагинов:

$ asdf plugin list all

У меня вывелось аж 194 штуки. Список плагинов можно посмотреть и на сайте, вот здесь.

Есть плагины для всех популярных языков программирования:

  • python;
  • nodejs;
  • rust;
  • java;
  • kotlin;
  • golang;
  • php;
  • ruby;
  • и, конечно же, для вашего любимого языка плагин тоже наверняка есть.

Кроме того, через asdf можно управлять версиями различных утилит, например:

  • github-cli;
  • jq;
  • kubectl;
  • poetry.

И сервисов, например:

  • postgres;
  • mysql;
  • mongodb;
  • redis.

Установка интересующего плагина выполняется следующим образом:

$ asdf plugin add <имя плагина>

Рассмотрим работу с теми плагинами, с которыми мне доводилось работать.

Плагин для Python

Установим плагин для Python:

$ asdf plugin add python

asdf имеет очень логично организованный интерфейс командной строки. Запомните одно правило: если хотите просмотреть только установленные плагины или версии плагина, то делайте list, а если вообще все, то list all.

плагин версия
все
asdf plugin list all
asdf list all python
установленные
asdf plugin list
asdf list python

Выше мы уже смотрели список всех плагинов (через list all), а теперь давайте просмотрим список установленных плагинов. Там должен быть python, мы ведь его только что установили:

$ asdf plugin list
python

Отлично, плагин установлен! Давайте попросим asdf показать список доступных версий (хотим вообще все, поэтому list all) для плагина python:

$ asdf list all python
…
3.6-dev
3.6.1
3.6.2
3.6.3
3.6.4
3.6.5
3.6.6
3.6.7
3.6.8
3.6.9
3.6.10
3.7.0
3.7-dev
3.7.1
3.7.2
3.7.3
3.7.4
3.7.5
3.7.6
3.7.7
3.8.0
3.8-dev
3.8.1
3.8.2
3.9.0a6
3.9-dev
…

Список я подсократил, но поверьте — он длинный. Там есть как все версии эталонного интерпретатора CPython, начиная с 2.1.3, так и альтернативные реализации Python — PyPy, IronPython, Jython, MicroPython и другие. Этот список очень напоминает подобный список из pyenv, и это не просто совпадение. Плагин asdf-python действительно под капотом использует pyenv.

В процессе установки asdf скачивает исходники Python и собирает интерпретатор из них. Это значит, что на машине придётся иметь установленные инструменты для сборки кода на C/C++ и все нужные библиотеки-зависимости. Список зависимостей для всех ОС и дистрибутивов можно посмотреть здесь. Обязательно установите эти зависимости прежде чем пытаться устанавливать какой-либо интерпретатор.

Установка конкретной версии интерпретатора происходит вот так:

$ asdf install python 3.7.7
$ asdf install python 3.8.2

Давайте запросим список установленных версий (list):

$ asdf list python
  3.7.7
  3.8.2

Давайте назначим глобальной ту версию Python, которую собираемся использовать чаще всего. Она будет использоваться по умолчанию, когда не найдена никакая локальная версия. Здесь всё работает так же, как и в pyenv, но даже если вы никогда им не пользовались, то я надеюсь, что дальше по примеру станет понятно как работают глобальные и локальные версии:

$ asdf global python 3.8.2
$ python -V
Python 3.8.2

Если вам интересно, как работает asdf, то:

$ which python
/home/br0ke/.asdf/shims/python

Опять же, он использует тот же принцип, что и pyenv — создает небольшие исполняемые файлы (shims) для всех команд, которыми собирается управлять. Эти шимы вызывают asdf и он принимает решение о том, какую версию программы нужно вызвать.

Давайте для демонстрации работы локальных версий создадим директорию, и представим, что в ней мы собираемся разрабатывать проект под определенной версией Python, отличной от глобальной:

$ mkdir my_project
$ cd my_project

Установим локальную версию:

$ asdf local python 3.7.7
$ python -V
Python 3.7.7

В этой директории asdf создал специальный файл .tool-versions (аналог .python-version из pyenv):

$ cat .tool-versions
python 3.7.7

Этот файл содержит версии всех утилит, которые мы настроили для директории, т.е. потенциально тут может быть не только Python. Как правило, этот файл не нужно добавлять в систему контроля версий (git), особенно если asdf в рамках проекта пользуетесь только вы.

asdf также вместо универсального .tool-versions умеет использовать файлы, специфичные для отдельных языков или инструментов, такие как .python-version (pyenv), .ruby-version (rbenv), .nvmrc и .node-version (nodejs) и другие. Это сделано для того, чтобы облегчить миграцию на asdf с других менеджеров версий. По умолчанию эта функциональность выключена, а включатся созданием файла ~/.asdfrc со следующим содержимым:

legacy_version_file = yes

При выходе из директории локально настроенная версия перестанет действовать и версия вернётся на глобальную:

$ cd ..
$ python -V
Python 3.8.2

По-моему, это очень удобно. В целом asdf работает так же как pyenv и многие другие менеджеры версий — в конце концов, они вдохновлены одной идеей. Только asdf вдохновился сильнее.

Допустим, что нужда прижала вас установить IPython:

$ pip install ipython

Чтобы IPython можно было запускать, нужно попросить asdf пересоздать шимы:

$ asdf reshim
$ ipython
Python 3.8.2 (default, May 10 2020, 22:17:35) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.14.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: print("asdf is awesome!")

Плагин для Node.js

Установим плагин для Node.js:

$ asdf plugin add nodejs

Запросим список доступных версий:

$ asdf list all nodejs
…
12.16.3
13.0.0
13.0.1
13.1.0
13.2.0
13.3.0
13.4.0
13.5.0
13.6.0
13.7.0
13.8.0
13.9.0
13.10.0
13.10.1
13.11.0
13.12.0
13.13.0
13.14.0
14.0.0
14.1.0
14.2.0

Все инструменты устанавливаются по-разному, и плагины это учитывают. Например, Python собирался из исходников, а Node.js устанавливается простым скачиванием бинарника, так что никакие зависимости для сборки не нужны.

Но у плагина Node.js тоже есть свои тонкости. Чтобы установить версию интерпретатора Node.js, нужно добавить ключи мейнтейнеров проекта Node.js в систему. Это нужно, чтобы при установке плагин asdf-nodejs проверил цифровую подпись бинарника (в системе должна быть установлена утилита установлена gpg):

$ bash ~/.asdf/plugins/nodejs/bin/import-release-team-keyring

Теперь установим последнюю на данный момент версию Node.js:

$ asdf install nodejs 14.2.0

Назначим её глобальной и проверим работу:

$ asdf global nodejs 14.2.0
$ node
Welcome to Node.js v14.2.0.
Type ".help" for more information.
> console.log("asdf is super awesome!")
asdf is super awesome!
undefined

Давайте вернемся в директорию из предыдущего примера и добавим там ещё и локальную версию Node.js:

$ cd my_project
$ asdf local nodejs 14.2.0

Теперь в .tool-versions лежит следующее содержимое:

$ cat .tool-versions 
python 3.7.7
nodejs 14.2.0

Заключение

asdf незаменим, если вы программируете более чем на одном языке. Крайне рекомендую присмотреться к нему, даже если сейчас вы программируете только на одном языке. Лучше выбирать инструменты на вырост.

Не бойтесь пробовать устанавливать разные плагины, только обязательно читайте инструкции к ним.

Обязательно подпишитесь на уведомления о новых постах в блоге, чтобы ничего не пропустить!

Дополнительное чтение

Обложка: idreamlikecrazy, One Ring to rule them all

тэги: python, node.js, pyenv, asdf