Системная установка

Для запуска кода на любом языке, необходимо установить его интерпретатор (или компилятор). В разных операционных системах это делается по-разному: где-то используются пакетные менеджеры, например, apt или yum, где-то скачивается установщик. Некоторые языки бывают предустановленны сразу, например, Python. На него многое завязано в дистрибутивах линукса.

# Ubuntu
sudo apt install nodejs # установит не самую свежую версию

Стандартный способ установки работает хорошо только в самом начале, когда происходит первичная настройка. Затем, с течением времени, начинают всплывать разные проблемы. Например, в какой-то момент выходит новая версия языка, которую нужно подключить к проекту. Обычно, должно пройти какое-то время, перед тем, как язык станет доступным для установки через пакетные менеджеры. И здесь либо придется ждать, что не всегда желательно, либо искать другой способ установки. Последнее нередко превращается в серьёзное испытание, с часами гугления и установкой дополнительных библиотек. Все это в конце концов засоряет систему и иногда ломает её.

Другая серьёзная проблема – установка сразу нескольких версий одного языка. Такое бывает нужно, когда разработчик переключается между разными проектами, требующими разные версии. Насколько часто такое происходит? Крайне часто. Чем дальше в разработку, тем больше вариантов: разные проекты в компании, свои проекты, опенсорс.

Здесь нужно упомянуть, что всё это мало касается тех, кто целиком ушел в Docker и Docker Compose. Однако даже в этом случае, нужны языки для работы с опенсорсом.

Менеджеры версий

Для решения этих проблем разработчики придумали менеджеры версий. Менеджер версий – это специальная программа, предназначенная для управления версиями языка. С его помощью устанавливают нужные версии и производят переключение между ними. В отличие от пакетных менеджеров, входящих в операционные системы, менеджеры версий всегда позволяют ставить последние версии языков, как только они выходят (включая установку альфа- и бета-версий).

Например, для Node.js это NVM (Node Version Manager):

# Установка NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
# Установка не означает активацию. После установки активной останется та версия, что и была до установки
nvm install node # Установка последней доступной версии ноды
nvm install 6.14.4 # или 10.10.0, 8.9.1, и т.п.
nvm ls-remote # список доступных версий
nvm use node # Активация последней установленной версии ноды
nvm use node 17 # Активация нужной версии

Для упрощения работы менеджеры версий обычно позволяют создать специальный файл внутри проекта, который зафиксирует нужную версию языка. В некоторых случаях менеджеры версий сами отслеживают этот файл и переключают версию автоматически.

echo "17" > .nvmrc
# Эта команда увидела файл .nvmrc и использовала указанную там версию
$ nvm use
Found '/path/to/project/.nvmrc' with version <17>
Now using node v17

В современном мире сложно представить себе язык, у которого бы не было менеджера версий. Более того некоторые языки, такие как Ruby, имеют множество разных менеджеров версий, которые конкурируют между собой:

Менеджеры версий позволили решить ещё несколько важных задач. Как правило, когда программист взаимодействует с языком, установленным напрямую, то ему приходится использовать sudo при установке глобальных пакетов. Дело в том, что стандартная схема установки языка предназначена для всех пользователей сразу. Поэтому все нужные файлы, включая глобальные пакеты, попадают в общие директории для которых нужны права администратора. С точки зрения безопасности это довольно большая дыра, которой могут воспользоваться (и иногда пользуются) разработчики опенсорс библиотек. Менеджеры версий устанавливают всё в домашнюю директорию текущего пользователя, где у него и так полные права. С одной стороны это позволяет не запускать установку пакетов от имени администратора, а с другой — не засоряется система. Удалить язык и все его пакеты через менеджер версий невероятно просто. Достаточно стереть директорию (правда, лучше это делать средствами самого менеджера версий).

Универсальный менеджер

Решив одни проблемы, менеджеры версий добавили другие. Во-первых, их слишком много, и они иногда меняются, сначала популярен один, затем другой. Во-вторых, сам процесс установки менеджера версий может оказаться сложнее установки языка. Проблема в том, что им нужно быть универсальными и работать везде, что крайне проблематично, учитывая разнообразие современных экосистем. Достаточно посмотреть размер документации NVM, чтобы оценить масштаб катастрофы. В-третьих, все эти менеджеры работают по-разному и имеют разные команды. Из-за этого усложняется процесс переключения между ними при работе с разными языками.

Всё это привело к следующему логическому шагу. В конце концов появился универсальный менеджер asdf, который, благодаря плагинам, способен работать с любыми языками. Неполный список его преимуществ:

Сейчас asdf набрал достаточно большую популярность и постепенно заменяет собой все остальные менеджеры версий (технически под капотом там часто используются менеджеры, специфические для конкретных языков). У него чуть более сложная система команд из-за необходимости поддерживать множество языков, но в остальном он резко упрощает весь процесс.

# У asdf прекрасная документация, где наглядно показано, как его установить,
# и какие могут понадобится зависимости в разных системах

# Установка
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.9
# После этого нужно перезапустить терминал
echo '. $HOME/.asdf/asdf.sh' >> ~/.bashrc

# Для работы с конкретным языком, сначала нужно подключить соответствующий плагин
# Список доступных плагинов есть на сайте проекта
asdf plugin add nodejs

# Установка языка
# Вместо nodejs нужно подставить название того плагина, с которым работаем
asdf install nodejs latest # latest означает последнюю версию указанного языка

# Установка указанной версии
asdf install nodejs latest

# Установка нужной версии языка версией по умолчанию
asdf global nodejs latest

# Показывает текущие версии для языков, установленных через asdf
asdf current
elixir         1.10.1-otp-22 (set by /Users/user/.tool-versions)
erlang         22.2.7   (set by /Users/user/.tool-versions)
nodejs         17.0.0   (set by /Users/user/.tool-versions)
php            7.4.5    (set by /Users/user/.tool-versions)
python         3.8.2 2.7.16 (set by /Users/user/.tool-versions)
ruby           2.7.0    (set by /Users/user/.tool-versions)
yarn           1.22.4   (set by /Users/user/.tool-versions)

Вывод

Работа с разными версиями языков – непростая задача, которую решают менеджеры версий и докер (для продвинутых). Среди всех менеджеров выделяется asdf, который становится универсальным инструментом для управления любыми языками и даже обычными программами.