Что такое "Менеджер версий"

Как управлять версиями языков

Содержание
  1. Системная установка
  2. Менеджеры версий
  3. Универсальный менеджер
  4. Вывод

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

Для запуска кода на любом языке, необходимо установить его интерпретатор (или компилятор). В разных операционных системах это делается по-разному: где-то используются пакетные менеджеры, например, 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 14.1 # Активация нужной версии

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

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

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

  • go: gvm, g
  • java: jabba
  • ruby: rbenv, rvm, chruby
  • php: phpenv, phpbrew
  • python: pyenv

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

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

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

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

  • Одна единственная утилита командной строки для работы со всеми языками
  • Единый интерфейс взаимодействия для всех языков
  • Автоматическое переключение на нужную версию языка внутри каждого проекта
  • Простая система плагинов, позволяющая добавить любые языки

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

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

# Установка
$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.7.8

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

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

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

# Установка нужной версии языка версией по умолчанию
# Здесь нужно всегда указывать конкретную версию
$ asdf global nodejs 14.1

# Показывает текущие версии для языков, установленных через 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         14.2.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, который становится универсальным инструментом для управления любыми языками и даже обычными программами.