Comment RVM et rbenv fonctionnent-ils réellement?

141

Je suis intéressé par la manière dont RVM et rbenv fonctionnent réellement.

De toute évidence, ils basculent entre différentes versions de Ruby et de gemsets, mais comment cela est-il possible? J'avais supposé qu'ils mettaient simplement à jour les liens symboliques, mais après avoir fouillé dans le code (et je dois admettre que ma connaissance de Bash est superficielle), ils semblent faire plus que cela.

superluminaire
la source

Réponses:

241

Brève explication: rbenv fonctionne en se connectant à votre environnement PATH. Le concept est simple, mais le diable est dans les détails; plein scoop ci-dessous.

Tout d' abord, rbenv crée des cales pour toutes les commandes ( ruby, irb, rake, gemetc.) à travers toutes vos versions installées de Ruby. Ce processus s'appelle rehashing . Chaque fois que vous installez une nouvelle version de Ruby ou installez une gemme qui fournit une commande, exécutez rbenv rehashpour vous assurer que toutes les nouvelles commandes sont shimmed.

Ces shims vivent dans un seul répertoire ( ~/.rbenv/shimspar défaut). Pour utiliser rbenv, il vous suffit d'ajouter le répertoire shims au début de votre PATH:

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

Ensuite, chaque fois que vous exécutez à rubypartir de la ligne de commande, ou exécutez un script dont shebang lit #!/usr/bin/env ruby, votre système d'exploitation le trouvera en ~/.rbenv/shims/rubypremier et l'exécutera à la place de tout autre rubyexécutable que vous avez peut-être installé.

Chaque shim est un petit script Bash qui s'exécute à son tour rbenv exec. Donc, avec rbenv dans votre chemin, irbéquivaut à rbenv exec irbet ruby -e "puts 42"équivaut à rbenv exec ruby -e "puts 42".

La rbenv execcommande détermine la version de Ruby que vous souhaitez utiliser, puis exécute la commande correspondante pour cette version. Voici comment:

  1. Si la RBENV_VERSIONvariable d'environnement est définie, sa valeur détermine la version de Ruby à utiliser.
  2. Si le répertoire de travail actuel contient un .rbenv-versionfichier, son contenu est utilisé pour définir la RBENV_VERSIONvariable d'environnement.
  3. S'il n'y a pas de .rbenv-versionfichier dans le répertoire courant, rbenv recherche un .rbenv-versionfichier dans chaque répertoire parent jusqu'à ce qu'il atteigne la racine de votre système de fichiers. S'il en trouve un, son contenu est utilisé pour définir la RBENV_VERSIONvariable d'environnement.
  4. Si RBENV_VERSIONn'est toujours pas défini, rbenv essaie de le définir en utilisant le contenu du ~/.rbenv/versionfichier.
  5. Si aucune version n'est spécifiée nulle part, rbenv suppose que vous voulez utiliser le Ruby "système" - c'est-à-dire quelle que soit la version exécutée si rbenv n'était pas dans votre chemin.

(Vous pouvez définir une version Ruby spécifique au projet avec la rbenv localcommande, qui crée un .rbenv-versionfichier dans le répertoire actuel. De même, la rbenv globalcommande modifie le ~/.rbenv/versionfichier.)

Armé d'une RBENV_VERSIONvariable d'environnement, rbenv ajoute ~/.rbenv/versions/$RBENV_VERSION/binà l'avant de votre PATH, puis exécute la commande et les arguments passés à rbenv exec. Voila!

Pour un aperçu détaillé de ce qui se passe sous le capot, essayez de définir RBENV_DEBUG=1et d'exécuter une commande Ruby. Chaque commande Bash exécutée par rbenv sera écrite sur votre terminal.


Maintenant, rbenv se préoccupe uniquement de changer de version, mais un écosystème prospère de plugins vous aidera à tout faire, de l' installation de Ruby à la configuration de votre environnement , en passant par la gestion des «gemsets» et même l' automatisationbundle exec .

Je ne suis pas tout à fait sûr de ce que le support IRC a à voir avec le changement de version de Ruby, et rbenv est conçu pour être suffisamment simple et compréhensible pour ne pas nécessiter de support. Mais si jamais vous avez besoin d'aide, le suivi des problèmes et Twitter ne sont qu'à quelques clics.

Divulgation: Je suis l'auteur de rbenv, ruby-build et rbenv-vars.

Sam Stephenson
la source
14
Merci d'avoir pris le temps de donner une si excellente réponse.
superluminaire
2
Wow, merci pour une explication aussi compréhensible et compréhensible. Un enseignant né naturellement.
racl101
Hé, Sam, puisque cette réponse a deux ans, voudriez-vous faire des mises à jour? Quelque chose a sûrement changé dans rbenv depuis ce temps.
Nakilon
Nan. La meilleure description de hacker que j'ai jamais vue. Je pense que la seule mise à jour qui doit changer ici est le lien vers rbenv-gemset (le lien vous y mènera toujours. C'est juste une autre étape supplémentaire à partir d'une redirection).
Jeffrey 'jf' Lim
18

J'ai écrit un article approfondi: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

La différence fondamentale réside dans l'endroit où l'environnement du shell est modifié:

  • RVM: il a changé lorsque vous changez Ruby.
  • rbenv: il est modifié lorsque vous exécutez un exécutable Ruby / gem.

En outre, le problème avec RVM est qu'il couvre beaucoup plus que la gestion de Rubies, il a beaucoup plus que tout autre outil (il y en a d'autres en dehors de RVM et de rbenv: https://twitter.com/#!/mpapis/ état / 171714447910502401 )

N'oubliez pas le support instantané que vous obtenez sur IRC dans le canal "#rvm" sur les serveurs Freenode.

mpapis
la source
1
Merci, c'est vraiment génial que les gens des deux communautés s'impliquent.
Superluminary
15

Donc, pour résumer les excellentes réponses ci-dessus, la principale différence pratique entre RVM et rbenv réside dans la sélection de la version de Ruby.

rbenv:

rbenv ajoute un shim au début de votre chemin, une commande du même nom que Ruby. Lorsque vous tapez rubysur une ligne de commande, le shim est exécuté à la place (car il est également appelé "ruby" et vient en premier dans le chemin). Le shim recherche une variable d'environnement ou un .rbenv_versionfichier pour lui dire à quelle version de Ruby déléguer.

RVM:

RVM vous permet de définir une version de Ruby directement en appelant rvm use. En outre, il remplace également la cdcommande système. Lorsque vous êtes cddans un dossier contenant un .rvmrcfichier, le code à l'intérieur du .rvmrcfichier est exécuté. Cela peut être utilisé pour définir une version Ruby, ou tout autre élément de votre choix.

Autres différences:

Il y a bien sûr d'autres différences. RVM a des gemsets prêts à l'emploi, tandis que rbenv nécessite juste un peu plus de piratage (mais pas beaucoup). Les deux sont des solutions fonctionnelles au problème.

superluminaire
la source
6

La principale différence semble être quand et comment le rubis est changé . Ruby est commuté:

  • pour RVM manuellement (utilisation rvm) ou automatiquement lors du changement de répertoire
  • pour rbenv automatiquement à chaque fois qu'une commande ruby ​​est exécutée

RVM repose sur la cdcommande modifiée et la sélection manuelle de Ruby par rvm use. rbenv utilise des wrappers ou "shims" pour toutes les commandes ruby ​​de base comme mécanisme par défaut pour sélectionner ruby. RVM crée également des wrappers pour les outils de ligne de commande de base tels que gem, rake, ruby. Ils sont utilisés par exemple dans CronJobs (voir http://rvm.io/integration/cron/ ), mais ils ne sont pas le mécanisme par défaut pour changer de version de Ruby.

Ainsi, les deux méthodes sélectionnent "automatiquement" la bonne version de Ruby en écrasant les commandes et en utilisant des wrappers. rvm remplace les commandes shell comme cd. rbenv remplace toutes les commandes ruby ​​de base telles que ruby, irb, rake et gem.

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

Vous donne environ:

< 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

Et il ajoute:

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

à $PATH

Reactormonk
la source