RVM 和 rbenv 实际上是如何工作的?

我感兴趣的是 RVM 和 rbenv 实际上是如何工作的。

显然,它们在不同版本的 Ruby 和 gemset 之间进行交换,但这是如何实现的呢?我原以为他们只是在更新符号链接,但在深入研究了代码之后(我必须承认,我对 Bash 的了解只是表面上的) ,他们似乎做的不止这些。

25766 次浏览
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

我写了一篇深度文章: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

基本区别在于 shell 环境在哪里发生了变化:

  • RVM: 当你改变 Ruby 的时候它就改变了。
  • Rbenv: 当您运行 Ruby/gem 可执行文件时,它发生了变化。

另外,关于 RVM 的事情是,它涵盖了很多不仅仅是管理 Ruby,它有很多比任何其他工具(除了 RVM 和 rbenv: https://twitter.com/#!/mpapis/status/171714447910502401之外还有其他工具)

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

简短的解释: rbenv 通过连接到环境的 PATH来工作。这个概念很简单,但是魔鬼在于细节; 完整的独家新闻如下。

首先,rbenv 为所有已安装的 Ruby 版本中的所有命令(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. 如果设置了环境变量,它的值将决定要使用的 Ruby 版本。
  2. 如果当前工作目录有一个 .rbenv-version文件,则其内容用于设置 RBENV_VERSION环境变量。
  3. 如果工作目录中没有 .rbenv-version文件,rbenv 会在每个父目录中搜索一个 .rbenv-version文件,直到它到达文件系统的根目录。如果找到一个,它的内容被用来设置 ABc2环境变量。
  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建立你的环境管理“宝石”甚至 自动化 bundle exec的所有任务。

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

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

因此,总结以上的优秀答案,RVM 和 rbenv 的主要实际区别在于选择 Ruby 版本的时间。

Rbenv:

Rbenv 在路径的开始部分添加了一个 shim,这是一个与 Ruby 同名的命令。当您在命令行中键入 ruby时,将运行垫片(因为它也被称为“ ruby”,并且在路径中排在第一位)。Shim 寻找一个环境变量或者 .rbenv_version文件来告诉它要委托给哪个版本的 Ruby。

RVM:

RVM 允许您通过调用 rvm use直接设置 Ruby 的一个版本。此外,它还覆盖了 cd系统命令。当您将 cd放入包含 .rvmrc文件的文件夹时,将执行 .rvmrc文件中的代码。这可以用来设置 Ruby 版本,或者任何你喜欢的东西。

其他差异:

当然还有其他不同之处。RVM 已经开箱即用,而 rbenv 只需要更多的黑客技术(但不是很多)。两者都是问题的功能性解决方案。

主要的区别似乎是 什么时候以及如何交换 Ruby。 Ruby 被切换了:

  • 为 RVM 手动(RVM 使用)或在目录更改期间自动
  • 对于 rbenv,每次执行 Ruby 命令时都会自动执行

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

因此,这两种方法都通过覆盖命令和使用包装器来“自动”选择正确的 Ruby 版本。Rvm 重写像 cd 这样的 shell 命令。Rbenv 覆盖所有基本的 Ruby 命令,如 ruby、 irb、 rake 和 gem。