Как на самом деле работают RVM и rbenv?

142

Мне интересно, как на самом деле работают RVM и rbenv.

Очевидно, они переключаются между разными версиями Ruby и гемсетами, но как это достигается? Я предполагал, что они просто обновляют символические ссылки, но, вникнув в код (и я должен признать, что мои знания о Bash поверхностны), похоже, они делают больше, чем это.

сверхсветовой
источник

Ответы:

242

Краткое объяснение: rbenv работает путем подключения к вашей среде PATH. Концепция проста, но дьявол кроется в деталях; полный совок ниже.

Во- первых, rbenv создает регулировочные шайбы для всех команд ( ruby, irb, rake, gemи т.д.) во всех установленных версий Ruby. Этот процесс называется перефразированием . Каждый раз, когда вы устанавливаете новую версию Ruby или гем, который предоставляет команду, запускайте, rbenv rehashчтобы убедиться, что все новые команды объединены оболочкой.

Эти прокладки находятся в одном каталоге ( ~/.rbenv/shimsпо умолчанию). Чтобы использовать rbenv, вам нужно только добавить каталог прокладок в начало PATH:

export PATH="$HOME/.rbenv/shims:$PATH"

Затем всякий раз, когда вы запускаете rubyиз командной строки или запускаете сценарий, который читает shebang #!/usr/bin/env ruby, ваша операционная система ~/.rbenv/shims/rubyсначала найдет и запустит его вместо любого другого rubyисполняемого файла, который вы могли установить.

Каждая прокладка - это крошечный сценарий Bash, который, в свою очередь, выполняется rbenv exec. Таким образом, если на вашем пути irbесть rbenv, это эквивалентно rbenv exec irbи ruby -e "puts 42"эквивалентно rbenv exec ruby -e "puts 42".

Команда rbenv execопределяет, какую версию Ruby вы хотите использовать, а затем запускает соответствующую команду для этой версии. Вот как:

  1. Если RBENV_VERSIONпеременная среды установлена, ее значение определяет версию Ruby для использования.
  2. Если в текущем рабочем каталоге есть .rbenv-versionфайл, его содержимое используется для установки RBENV_VERSIONпеременной среды.
  3. Если .rbenv-versionв текущем каталоге нет файла, rbenv ищет файл в каждом родительском каталоге, .rbenv-versionпока не попадет в корень вашей файловой системы. Если он найден, его содержимое используется для установки RBENV_VERSIONпеременной среды.
  4. Если RBENV_VERSIONпо-прежнему не установлен, rbenv пытается установить его, используя содержимое ~/.rbenv/versionфайла.
  5. Если версия нигде не указана, rbenv предполагает, что вы хотите использовать «системный» Ruby, т.е. какую бы версию ни запустили, если бы rbenv не было на вашем пути.

(Вы можете установить версию Ruby для конкретного проекта с помощью rbenv localкоманды, которая создает .rbenv-versionфайл в текущем каталоге. Точно так же rbenv globalкоманда изменяет ~/.rbenv/versionфайл.)

Вооружившись RBENV_VERSIONпеременной окружения, rbenv добавляет ~/.rbenv/versions/$RBENV_VERSION/binв начало вашего файла PATH, затем выполняет команду и переданные аргументы rbenv exec. Вуаля!

Чтобы полностью понять, что именно происходит под капотом, попробуйте установить RBENV_DEBUG=1и запустить команду Ruby. Каждая команда Bash, запускаемая rbenv, будет записана в ваш терминал.


Сейчас rbenv занимается только переключением версий, но процветающая экосистема плагинов поможет вам сделать все, от установки Ruby до настройки вашей среды , управления «гемсетами» и даже автоматизацииbundle exec .

Я не совсем уверен, какое отношение имеет поддержка IRC к переключению версий Ruby, а rbenv разработан, чтобы быть достаточно простым и понятным, чтобы не требовать поддержки. Но если вам когда-нибудь понадобится помощь, средство отслеживания проблем и Twitter находятся всего в паре кликов.

Раскрытие информации: я являюсь автором rbenv, ruby-build и rbenv-vars.

Сэм Стивенсон
источник
14
Спасибо, что нашли время дать такой отличный ответ.
superluminary
2
Ого, спасибо за такое внятное и понятное объяснение. Прирожденный учитель.
racl101
Привет, Сэм, так как этому ответу два года, не хотите ли вы что-нибудь обновить? Наверняка с тех пор в rbenv что-то изменилось.
Nakilon
Неа. Лучшее описание хакера, которое я когда-либо видел. Я думаю, что единственное обновление, которое нужно изменить, - это ссылка на rbenv-gemset (ссылка все равно приведет вас туда. Это просто еще один дополнительный шаг от перенаправления).
Джеффри Лим,
18

Я написал подробную статью: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

Основное отличие заключается в том, где изменяется среда оболочки:

  • RVM: он меняется, когда вы меняете Ruby.
  • rbenv: изменяется при запуске исполняемого файла Ruby / gem.

Кроме того, особенность RVM заключается в том, что он охватывает гораздо больше, чем просто управление Rubies, он имеет гораздо больше, чем любой другой инструмент (есть и другие, кроме RVM и rbenv: https://twitter.com/#!/mpapis/ статус / 171714447910502401 )

Не забывайте о мгновенной поддержке, которую вы получаете в IRC в канале "#rvm" на серверах Freenode.

mpapis
источник
1
Спасибо, это действительно здорово, что люди из обоих сообществ принимают участие.
superluminary
15

Итак, чтобы обобщить отличные ответы выше, основное практическое различие между RVM и rbenv заключается в том, когда выбрана версия Ruby.

rbenv:

rbenv добавляет прокладку в начало вашего пути, команду с тем же именем, что и Ruby. Когда вы вводите rubyтекст в командной строке, вместо этого запускается прокладка (потому что она также называется «рубин» и идет первой в пути). Оболочка ищет переменную среды или .rbenv_versionфайл, чтобы сообщить ей, какой версии Ruby делегировать.

RVM:

RVM позволяет вам установить версию Ruby напрямую, вызвав rvm use. Кроме того, он также переопределяет cdсистемную команду. Когда вы cdпопадаете в папку, содержащую .rvmrcфайл, выполняется код внутри .rvmrcфайла. Это можно использовать для установки версии Ruby или чего-нибудь еще, что вам нравится.

Прочие отличия:

Конечно, есть и другие отличия. У RVM есть гемсеты из коробки, в то время как для rbenv требуется немного больше взлома (но не намного). Оба являются функциональным решением проблемы.

сверхсветовой
источник
6
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before

Дает вам примерно:

< GEM_HOME=$HOME/.gem/ruby/1.9.1
---
> GEM_HOME=$HOME/.rvm/gems/jruby-1.6.6
< GEM_PATH=$HOME/.gem/ruby/1.9.1
---
> GEM_PATH=$HOME/.rvm/gems/jruby-1.6.6:$HOME/.rvm/gems/jruby-1.6.6@global
*bunch of rvm_*
> MY_RUBY_HOME=$HOME/.rvm/rubies/jruby-1.6.6
> RUBY_VERSION=jruby-1.6.6
> IRBRC=$HOME/.rvm/rubies/jruby-1.6.6/.irbrc

И это предшествует:

$HOME/.rvm/gems/jruby-1.6.6/bin:$HOME/.rvm/gems/jruby-1.6.6@global/bin

к $PATH

Reactormonk
источник
6

Основная разница, по-видимому, заключается в том, когда и как рубин переключается . Ruby переключается:

  • для RVM вручную (использование rvm) или автоматически при смене директорий
  • для rbenv автоматически каждый раз, когда выполняется команда ruby

RVM полагается на измененную cdкоманду и ручной выбор Ruby by rvm use. rbenv использует оболочки или «прокладки» для всех основных команд ruby ​​в качестве механизма по умолчанию для выбора ruby. RVM создает оболочки для основных инструментов командной строки, таких как gem, rake, ruby. Они используются, например , в CronJobs (см http://rvm.io/integration/cron/ ), но они не являются механизмом по умолчанию для переключения версии Ruby.

Таким образом, оба метода «автоматически» выбирают нужную версию Ruby путем перезаписи команд и использования оболочек. rvm переопределяет команды оболочки, такие как cd. rbenv отменяет все основные команды Ruby, такие как ruby, irb, rake и gem.

0x4a6f4672
источник