RVM和rbenv实际如何工作?


140

我对RVM和rbenv的实际工作方式很感兴趣。

显然,它们在不同版本的Ruby和gemset之间交换,但是如何实现呢?我以为它们只是在更新符号链接,但是深入研究代码(我必须承认我对Bash的了解是肤浅的),它们似乎在做更多的事情。

Answers:


241

简短说明:rbenv通过与您环境的挂钩而起作用PATH。这个概念很简单,但是细节决定成败。下面有完整的独家新闻。

首先,rbenv创建垫片的所有命令(rubyirbrakegem等)跨红宝石的所有已安装的版本。此过程称为重新哈希处理。每次您安装新版本的Ruby或安装提供命令的gem时,请运行rbenv rehash以确保对所有新命令进行填充。

这些垫片位于单个目录中(~/.rbenv/shims默认情况下)。要使用rbenv,只需将shims目录添加到您的前端PATH

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

然后,无论何时ruby从命令行运行,或者运行shebang读为的脚本#!/usr/bin/env ruby,您的操作系统都会~/.rbenv/shims/ruby首先找到并运行它,而不是ruby您可能已安装的任何其他可执行文件。

每个填充程序都是一个很小的Bash脚本,该脚本随后运行rbenv exec。因此,在您的路径中使用rbenv irb等效于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不在您的路径中,则将运行任何版本。

(您可以使用rbenv local命令设置特定于项目的Ruby版本,该命令将.rbenv-version在当前目录中创建一个文件。类似地,该rbenv global命令将修改该~/.rbenv/version文件。)

配备RBENV_VERSION环境变量后,rbenv添加~/.rbenv/versions/$RBENV_VERSION/bin到您的前端PATH,然后执行传递给的命令和参数rbenv exec。瞧!

要彻底了解幕后情况,请尝试设置RBENV_DEBUG=1和运行Ruby命令。rbenv运行的每个Bash命令将被写入您的终端。


现在,rbenv只关心切换版本,但是蓬勃发展的插件生态系统将帮助您完成从安装Ruby设置您的环境管理“ gemsets”甚至自动化的所有工作bundle exec

我不太确定IRC支持与切换Ruby版本有什么关系,而rbenv的设计简单易懂,不需要支持。但是,如果您需要帮助,只需单击几下即可找到问题跟踪器和Twitter。

披露:我是rbenv,ruby-build和rbenv-vars的作者。


14
感谢您抽出宝贵的时间来回答这个问题。
superluminary'2

2
哇,谢谢您这么容易理解的解释。天生的老师。
racl101 2012年

嘿,Sam,因为这个答案已有两年了,您是否想进行任何更新?自那时以来,rbenv肯定已经发生了一些变化。
Nakilon

不。我见过的最好的黑客描述。我认为唯一需要更改的更新是指向rbenv-gemset的链接(该链接仍将带您到那里。这只是重定向的又一额外步骤)。
Jeffrey'jf'Lim 2015年

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

不要忘记Freenode服务器上“ #rvm”通道中的IRC上的即时支持。


1
谢谢,来自两个社区的人们参与其中真的很棒。
superluminary 2012年

15

因此,总结上面的出色答案,RVM和rbenv之间的主要实际区别是选择Ruby版本时。

rbenv:

rbenv在路径的开头添加了一个垫片,该垫片的名称与Ruby相同。ruby在命令行上键入时,将运行垫片(因为它也被称为“红宝石”,并且在路径中排在第一位)。填充程序会寻找一个环境变量或.rbenv_version文件来告诉它要委托给哪个版本的Ruby。

RVM:

RVM允许您通过调用直接设置Ruby版本rvm use。此外,它还会覆盖cd系统命令。当您cd进入包含.rvmrc文件的文件夹时,将.rvmrc执行文件内的代码。这可用于设置Ruby版本或您喜欢的其他任何版本。

其他差异:

当然还有其他差异。RVM开箱即用,而rbenv只需要更多的黑客操作(但不多)。两者都是该问题的功能性解决方案。


6

主要的区别似乎在于何时以及如何切换红宝石。Ruby已切换:

  • 手动(用于rvm)或在目录更改期间自动为RVM
  • 每次执行ruby命令时,将自动为rbenv

RVM依赖于修改后的cd命令和Ruby对Ruby的手动选择rvm use。rbenv对所有基本的ruby命令使用包装器或“垫片”作为选择ruby的默认机制。RVM也为基本命令行工具(如gem,rake,ruby)创建包装器。例如,它们在CronJobs中使用(请参阅http://rvm.io/integration/cron/),但它们不是切换Ruby版本的默认机制。

因此,这两种方法都将通过覆盖命令并使用包装器来“自动”选择正确的Ruby版本。rvm会覆盖诸如cd之类的shell命令。rbenv会覆盖所有基本的ruby命令,例如ruby,irb,rake和gem。


5
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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.