Wie funktionieren RVM und rbenv tatsächlich?

140

Ich interessiere mich dafür, wie RVM und rbenv tatsächlich funktionieren.

Natürlich wechseln sie zwischen verschiedenen Versionen von Ruby und Gemsets, aber wie wird dies erreicht? Ich hatte angenommen, dass sie lediglich Symlinks aktualisieren, aber nachdem sie sich mit dem Code befasst haben (und ich muss zugeben, dass mein Wissen über Bash oberflächlich ist), scheinen sie mehr zu tun.

überleuchtet
quelle

Antworten:

241

Kurze Erklärung: rbenv funktioniert, indem es sich in die Umgebung einfügt PATH. Das Konzept ist einfach, aber der Teufel steckt im Detail; volle Schaufel unten.

Zuerst rbenv schafft Beilagen für alle Befehle ( ruby, irb, rake, gemusw.) über alle installierten Versionen von Ruby. Dieser Vorgang wird als Aufwärmen bezeichnet . Führen Sie jedes Mal, wenn Sie eine neue Version von Ruby installieren oder ein Juwel installieren, das einen Befehl bereitstellt, aus rbenv rehash, um sicherzustellen, dass alle neuen Befehle abgeglichen werden.

Diese Shims befinden sich ( ~/.rbenv/shimsstandardmäßig) in einem einzigen Verzeichnis . Um rbenv zu verwenden, müssen Sie nur das Shims-Verzeichnis an der Vorderseite Ihres PATH:

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

Jedes Mal, wenn Sie rubyüber die Befehlszeile ausführen oder ein Skript ausführen, dessen Shebang lautet #!/usr/bin/env ruby, wird Ihr Betriebssystem es ~/.rbenv/shims/rubyzuerst finden und anstelle einer anderen rubyausführbaren Datei ausführen, die Sie möglicherweise installiert haben.

Jeder Shim ist ein winziges Bash-Skript, das wiederum ausgeführt wird rbenv exec. Also mit rbenv auf Ihrem Weg irbist äquivalent zu rbenv exec irbund ruby -e "puts 42"äquivalent zu rbenv exec ruby -e "puts 42".

Der rbenv execBefehl ermittelt, welche Version von Ruby Sie verwenden möchten, und führt dann den entsprechenden Befehl für diese Version aus. Hier ist wie:

  1. Wenn die RBENV_VERSIONUmgebungsvariable festgelegt ist, bestimmt ihr Wert die zu verwendende Ruby-Version.
  2. Wenn das aktuelle Arbeitsverzeichnis eine .rbenv-versionDatei enthält, wird deren Inhalt zum Festlegen der RBENV_VERSIONUmgebungsvariablen verwendet.
  3. Wenn sich .rbenv-versionim aktuellen Verzeichnis keine Datei befindet, durchsucht rbenv jedes übergeordnete Verzeichnis nach einer .rbenv-versionDatei, bis es das Stammverzeichnis Ihres Dateisystems erreicht. Wenn einer gefunden wird, wird sein Inhalt verwendet, um die RBENV_VERSIONUmgebungsvariable festzulegen.
  4. Wenn dies RBENV_VERSIONimmer noch nicht festgelegt ist, versucht rbenv, es anhand des Inhalts der ~/.rbenv/versionDatei festzulegen .
  5. Wenn nirgendwo eine Version angegeben ist, geht rbenv davon aus, dass Sie den Ruby "System" verwenden möchten - dh welche Version auch immer ausgeführt wird, wenn sich rbenv nicht in Ihrem Pfad befindet.

(Mit dem rbenv localBefehl können Sie eine projektspezifische Ruby-Version festlegen, mit der eine .rbenv-versionDatei im aktuellen Verzeichnis erstellt wird. Ebenso rbenv globaländert der Befehl die ~/.rbenv/versionDatei.)

Mit einer RBENV_VERSIONUmgebungsvariablen bewaffnet, fügt rbenv ~/.rbenv/versions/$RBENV_VERSION/bindie Vorderseite Ihres hinzu PATHund führt dann den Befehl und die Argumente aus, an die übergeben wird rbenv exec. Voila!

Versuchen Sie RBENV_DEBUG=1, einen Ruby-Befehl festzulegen und auszuführen, um genau zu sehen, was unter der Haube passiert . Jeder Bash-Befehl, den rbenv ausführt, wird in Ihr Terminal geschrieben.


Jetzt befasst sich rbenv nur noch mit dem Wechseln von Versionen, aber ein florierendes Ökosystem von Plugins hilft Ihnen dabei, alles zu tun, von der Installation von Ruby über die Einrichtung Ihrer Umgebung , die Verwaltung von "Gemsets" bis hin zur Automatisierungbundle exec .

Ich bin mir nicht ganz sicher, was die IRC-Unterstützung mit dem Wechsel von Ruby-Versionen zu tun hat, und rbenv ist so konzipiert, dass es einfach und verständlich genug ist, um keine Unterstützung zu benötigen. Sollten Sie jemals Hilfe benötigen, sind der Issue-Tracker und Twitter nur ein paar Klicks entfernt.

Offenlegung: Ich bin der Autor von rbenv, ruby-build und rbenv-vars.

Sam Stephenson
quelle
14
Vielen Dank, dass Sie sich die Zeit genommen haben, eine so hervorragende Antwort zu geben.
Superluminary
2
Wow, danke für eine so verständliche und verständliche Erklärung. Ein natürlich geborener Lehrer.
racl101
Hey, Sam, da diese Antwort zwei Jahre alt ist, möchtest du irgendwelche Updates machen? Sicherlich hat sich seitdem etwas in rbenv geändert.
Nakilon
Nee. Beste Hacker-Beschreibung, die ich je gesehen habe. Ich denke, das einzige Update, das dort geändert werden muss, ist der Link zu rbenv-gemset (der Link bringt Sie immer noch dorthin. Es ist nur ein weiterer zusätzlicher Schritt von einer Weiterleitung).
Jeffrey 'jf' Lim
18

Ich habe einen ausführlichen Artikel geschrieben: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

Der grundlegende Unterschied besteht darin, wo die Shell-Umgebung geändert wird:

  • RVM: Es wird geändert, wenn Sie Ruby ändern.
  • rbenv: Es wird geändert, wenn Sie eine ausführbare Ruby / Gem-Datei ausführen.

Die Sache mit RVM ist außerdem, dass es viel mehr als nur das Verwalten von Rubinen abdeckt. Es hat viel mehr als jedes andere Tool (außer RVM und rbenv gibt es noch andere: https://twitter.com/#!/mpapis/ Status / 171714447910502401 )

Vergessen Sie nicht die sofortige Unterstützung, die Sie im IRC im Kanal "#rvm" auf den Freenode-Servern erhalten.

mpapis
quelle
1
Danke, es ist wirklich toll, dass sich Menschen aus beiden Communities engagieren.
Superluminary
15

Um die hervorragenden Antworten oben zusammenzufassen, besteht der praktische Hauptunterschied zwischen RVM und rbenv darin, dass die Version von Ruby ausgewählt wird.

rbenv:

rbenv fügt am Anfang Ihres Pfades eine Unterlegscheibe hinzu, einen Befehl mit demselben Namen wie Ruby. Wenn Sie rubyan einer Befehlszeile eingeben, wird stattdessen der Shim ausgeführt (da er auch als "Ruby" bezeichnet wird und im Pfad an erster Stelle steht). Der Shim sucht nach einer Umgebungsvariablen oder .rbenv_version-datei, um anzugeben, an welche Ruby-Version delegiert werden soll.

RVM:

Mit RVM können Sie eine Version von Ruby direkt durch Aufrufen festlegen rvm use. Darüber hinaus wird der cdSystembefehl überschrieben . Wenn Sie sich cdin einem Ordner befinden, der eine .rvmrcDatei enthält , wird der Code in der .rvmrcDatei ausgeführt. Dies kann verwendet werden, um eine Ruby-Version oder alles andere festzulegen, was Sie möchten.

Andere Unterschiede:

Es gibt natürlich noch andere Unterschiede. RVM hat Edelsteine ​​sofort einsatzbereit, während rbenv nur ein wenig mehr Hacking erfordert (aber nicht viel). Beides sind funktionale Lösungen für das Problem.

überleuchtet
quelle
6

Der Hauptunterschied scheint zu sein, wann und wie Rubin gewechselt wird . Ruby ist geschaltet:

  • für RVM manuell (rvm use) oder automatisch beim Verzeichniswechsel
  • für rbenv automatisch jedes Mal, wenn ein Ruby-Befehl ausgeführt wird

RVM stützt sich auf den geänderten cdBefehl und die manuelle Auswahl von Ruby durch rvm use. rbenv verwendet Wrapper oder "Shims" für alle grundlegenden Ruby-Befehle als Standardmechanismus für die Auswahl von Ruby. RVM erstellt Wrapper für grundlegende Befehlszeilen-Tools wie Edelstein, Rechen und Rubin. Sie werden beispielsweise in CronJobs verwendet (siehe http://rvm.io/integration/cron/ ), sind jedoch nicht der Standardmechanismus zum Wechseln der Ruby-Version.

Somit wählen beide Methoden "automatisch" die richtige Ruby-Version aus, indem sie Befehle überschreiben und Wrapper verwenden. rvm überschreibt Shell-Befehle wie cd. rbenv überschreibt alle grundlegenden Ruby-Befehle wie Ruby, Irb, Rake und Gem.

0x4a6f4672
quelle
5
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before

Gibt Ihnen ungefähr:

< 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

Und es geht voran:

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

zu $PATH

Reactormonk
quelle