Come funzionano effettivamente RVM e rbenv?


141

Sono interessato a come funzionano RVM e rbenv.

Ovviamente si scambiano tra diverse versioni di Ruby e gemme, ma come si ottiene? Avevo supposto che stessero semplicemente aggiornando i symlink, ma avendo approfondito il codice (e devo ammettere che la mia conoscenza di Bash è superficiale) sembrano fare di più.

Risposte:


241

Breve spiegazione: rbenv funziona collegandosi al proprio ambiente PATH. Il concetto è semplice, ma il diavolo è nei dettagli; scoop completo di seguito.

In primo luogo, rbenv crea spessori per tutti i comandi ( ruby, irb, rake, geme così via) su tutti i tuoi versioni installate di Ruby. Questo processo si chiama rehashing . Ogni volta che installi una nuova versione di Ruby o installi una gemma che fornisce un comando, esegui rbenv rehashper assicurarti che tutti i nuovi comandi vengano sottoposti a shim.

Questi spessori vivono in una singola directory ( ~/.rbenv/shimsper impostazione predefinita). Per usare rbenv, devi solo aggiungere la directory shims nella parte anteriore del tuo PATH:

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

Quindi ogni volta che esegui rubydalla riga di comando o esegui uno script il cui shebang legge #!/usr/bin/env ruby, il tuo sistema operativo lo troverà per ~/.rbenv/shims/rubyprimo ed eseguirà invece di qualsiasi altro rubyeseguibile che potresti aver installato.

Ogni shim è un minuscolo script di Bash che a sua volta viene eseguito rbenv exec. Quindi, con rbenv nel tuo percorso, irbè equivalente a rbenv exec irbed ruby -e "puts 42"è equivalente a rbenv exec ruby -e "puts 42".

Il rbenv execcomando determina quale versione di Ruby si desidera utilizzare, quindi esegue il comando corrispondente per quella versione. Ecco come:

  1. Se la RBENV_VERSIONvariabile di ambiente è impostata, il suo valore determina la versione di Ruby da utilizzare.
  2. Se la directory di lavoro corrente ha un .rbenv-versionfile, il suo contenuto viene utilizzato per impostare la RBENV_VERSIONvariabile di ambiente.
  3. Se non ci sono .rbenv-versionfile nella directory corrente, rbenv cerca un .rbenv-versionfile in ciascuna directory principale fino a quando non raggiunge la radice del filesystem. Se ne viene trovato uno, il suo contenuto viene utilizzato per impostare la RBENV_VERSIONvariabile di ambiente.
  4. Se non RBENV_VERSIONè ancora impostato, rbenv tenta di impostarlo utilizzando il contenuto del ~/.rbenv/versionfile.
  5. Se nessuna versione viene specificata da nessuna parte, rbenv presume che tu voglia utilizzare il "sistema" Ruby, ovvero qualunque versione verrebbe eseguita se rbenv non fosse sul tuo percorso.

(È possibile impostare una versione di Ruby specifica del progetto con il rbenv localcomando, che crea un .rbenv-versionfile nella directory corrente. Allo stesso modo, il rbenv globalcomando modifica il ~/.rbenv/versionfile.)

Armato di una RBENV_VERSIONvariabile d'ambiente, rbenv si aggiunge ~/.rbenv/versions/$RBENV_VERSION/binalla parte anteriore del tuo PATH, quindi esegue il comando e gli argomenti passati a rbenv exec. Ecco!

Per uno sguardo approfondito esattamente cosa succede sotto il cofano, prova a impostare RBENV_DEBUG=1ed eseguire un comando Ruby. Ogni comando di Bash eseguito da rbenv verrà scritto sul tuo terminale.


Ora, rbenv si occupa solo di cambiare versione, ma un florido ecosistema di plug-in ti aiuterà a fare di tutto, dall'installazione di Ruby alla configurazione del tuo ambiente , alla gestione dei "gemset" e persino all'automazionebundle exec .

Non sono sicuro di cosa abbia a che fare il supporto IRC con la commutazione delle versioni di Ruby e rbenv è progettato per essere abbastanza semplice e comprensibile da non richiedere supporto. Ma se hai mai bisogno di aiuto, il tracker dei problemi e Twitter sono solo un paio di clic di distanza.

Divulgazione: sono l'autore di rbenv, ruby-build e rbenv-vars.


14
Grazie per aver dedicato del tempo a dare una risposta così eccellente.
superluminario,

2
Wow, grazie per una spiegazione così comprensibile e comprensibile. Un insegnante nato naturale.
racl101,

Ehi, Sam, dato che questa risposta ha due anni, vorresti fare degli aggiornamenti? Sicuramente qualcosa è cambiato in rbenv da quel momento.
Nakilon,

No. Descrizione del miglior hacker che abbia mai visto. Penso che l'unico aggiornamento che debba cambiare sia il link a rbenv-gemset (il link ti porterà ancora lì. È solo un altro passo in più da un reindirizzamento).
Jeffrey 'jf' Lim,

18

Ho scritto un articolo approfondito: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

La differenza di base è dove l'ambiente della shell è cambiato:

  • RVM: è cambiato quando cambi Ruby.
  • rbenv: viene modificato quando si esegue un eseguibile Ruby / gem.

Inoltre, la cosa su RVM è che copre molto di più della semplice gestione dei rubini, ha molto più di qualsiasi altro strumento (ce ne sono altri oltre a RVM e rbenv: https://twitter.com/#!/mpapis/ status / 171714447910502401 )

Non dimenticare il supporto istantaneo che ricevi su IRC nel canale "#rvm" sui server Freenode.


1
Grazie, è davvero bello che vengano coinvolte persone di entrambe le comunità.
superluminario

15

Quindi, per riassumere le eccellenti risposte sopra, la principale differenza pratica tra RVM e rbenv è quando viene selezionata la versione di Ruby.

rbenv:

rbenv aggiunge uno spessore all'inizio del percorso, un comando con lo stesso nome di Ruby. Quando si digita rubyda una riga di comando, viene invece eseguito lo shim (perché è anche chiamato "ruby" e arriva per primo nel percorso). Lo shim cerca una variabile d'ambiente o un .rbenv_versionfile per dirgli a quale versione di Ruby delegare.

RVM:

RVM ti consente di impostare direttamente una versione di Ruby chiamando rvm use. Inoltre, ignora anche il cdcomando di sistema. Quando ti trovi cdin una cartella che contiene un .rvmrcfile, .rvmrcviene eseguito il codice all'interno del file. Questo può essere usato per impostare una versione di Ruby o qualsiasi altra cosa tu voglia.

Altre differenze:

Ci sono ovviamente altre differenze. RVM ha gemme fuori dalla scatola, mentre rbenv richiede solo un po 'più di hacking (ma non molto). Entrambe sono soluzioni funzionali al problema.


6

La differenza principale sembra essere quando e come si cambia il rubino . Ruby è cambiato:

  • per RVM manualmente (uso rvm) o automaticamente durante il cambio di directory
  • per rbenv automaticamente ogni volta che viene eseguito un comando ruby

RVM si basa sul cdcomando modificato e sulla selezione manuale di Ruby di rvm use. rbenv utilizza wrapper o "shim" per tutti i comandi ruby ​​di base come meccanismo predefinito per selezionare ruby. RVM crea wrapper per gli strumenti di base della riga di comando come gem, rake, ruby. Sono usati ad esempio in CronJobs (vedi http://rvm.io/integration/cron/ ), ma non sono il meccanismo predefinito per cambiare la versione di Ruby.

Pertanto, entrambi i metodi selezionano "automaticamente" la versione corretta di Ruby sovrascrivendo i comandi e utilizzando i wrapper. rvm sovrascrive i comandi della shell come cd. rbenv ha la precedenza su tutti i comandi ruby ​​di base come ruby, irb, rake e gem.


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

Ti dà circa:

< 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

E antepone:

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

per $PATH

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.