¿Cómo funcionan realmente RVM y rbenv?

140

Estoy interesado en cómo funcionan realmente RVM y rbenv.

Obviamente intercambian entre diferentes versiones de Ruby y gemas, pero ¿cómo se logra esto? Supuse que simplemente estaban actualizando enlaces simbólicos, pero habiendo profundizado en el código (y debo admitir que mi conocimiento de Bash es superficial) parecen estar haciendo más que esto.

superluminario
fuente

Respuestas:

241

Breve explicación: rbenv funciona conectándose a su entorno PATH. El concepto es simple, pero el diablo está en los detalles; cucharada completa a continuación.

En primer lugar, crea rbenv cuñas para todos los comandos ( ruby, irb, rake, gemetc.) a través de todas sus versiones instaladas de Ruby. Este proceso se llama rehashing . Cada vez que instale una nueva versión de Ruby o instale una gema que proporcione un comando, ejecute rbenv rehashpara asegurarse de que los comandos nuevos se bloqueen.

Estas cuñas viven en un solo directorio ( ~/.rbenv/shimspor defecto). Para usar rbenv, solo necesita agregar el directorio de cuñas al frente de su PATH:

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

Luego, cada vez que ejecute rubydesde la línea de comandos, o ejecute un script cuyo shebang lea #!/usr/bin/env ruby, su sistema operativo lo encontrará ~/.rbenv/shims/rubyprimero y lo ejecutará en lugar de cualquier otro rubyejecutable que haya instalado.

Cada cuña es un pequeño script Bash que a su vez se ejecuta rbenv exec. Entonces, con rbenv en su camino, irbes equivalente a rbenv exec irb, y ruby -e "puts 42"es equivalente a rbenv exec ruby -e "puts 42".

El rbenv execcomando determina qué versión de Ruby desea usar, luego ejecuta el comando correspondiente para esa versión. Así es cómo:

  1. Si se establece la RBENV_VERSIONvariable de entorno, su valor determina la versión de Ruby que se utilizará.
  2. Si el directorio de trabajo actual tiene un .rbenv-versionarchivo, su contenido se usa para establecer la RBENV_VERSIONvariable de entorno.
  3. Si no hay ningún .rbenv-versionarchivo en el directorio actual, rbenv busca en cada directorio padre un .rbenv-versionarchivo hasta que llegue a la raíz de su sistema de archivos. Si se encuentra uno, su contenido se utiliza para establecer la RBENV_VERSIONvariable de entorno.
  4. Si RBENV_VERSIONaún no está configurado, rbenv intenta configurarlo utilizando el contenido del ~/.rbenv/versionarchivo.
  5. Si no se especifica ninguna versión en ninguna parte, rbenv supone que desea utilizar el "sistema" de Ruby, es decir, cualquier versión que se ejecute si rbenv no estuviera en su camino.

(Puede establecer una versión de Ruby específica del proyecto con el rbenv localcomando, que crea un .rbenv-versionarchivo en el directorio actual. Del mismo modo, el rbenv globalcomando modifica el ~/.rbenv/versionarchivo).

Armado con una RBENV_VERSIONvariable de entorno, rbenv se agrega ~/.rbenv/versions/$RBENV_VERSION/binal frente de su PATH, luego ejecuta el comando y los argumentos pasados rbenv exec. Voila!

Para una mirada completa a lo que sucede exactamente debajo del capó, intente configurar RBENV_DEBUG=1y ejecutar un comando Ruby. Cada comando Bash que rbenv ejecuta se escribirá en su terminal.


Ahora, rbenv solo se preocupa por cambiar las versiones, pero un próspero ecosistema de complementos lo ayudará a hacer todo, desde instalar Ruby hasta configurar su entorno , administrar "gemas" e incluso automatizarbundle exec .

No estoy muy seguro de qué tiene que ver el soporte de IRC con el cambio de versiones de Ruby, y rbenv está diseñado para ser simple y lo suficientemente comprensible como para no requerir soporte. Pero si alguna vez necesita ayuda, el rastreador de problemas y Twitter están a solo un par de clics de distancia.

Divulgación: soy el autor de rbenv, ruby-build y rbenv-vars.

Sam Stephenson
fuente
14
Gracias por tomarse el tiempo para dar una respuesta tan excelente.
superluminario
2
Wow, gracias por una explicación tan comprensible y comprensible. Un maestro nato.
racl101
Hola, Sam, ya que esta respuesta tiene dos años, ¿te gustaría hacer alguna actualización? Seguramente algo ha cambiado en rbenv desde entonces.
Nakilon
No La mejor descripción de hackers que he visto. Creo que la única actualización que debe cambiar allí es el enlace a rbenv-gemset (el enlace aún lo llevará allí. Es solo otro paso adicional de una redirección).
Jeffrey 'jf' Lim
18

Escribí un artículo en profundidad: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

La diferencia básica es dónde se cambia el entorno de shell:

  • RVM: cambia cuando cambias a Ruby.
  • rbenv: cambia cuando ejecutas un ejecutable Ruby / gem.

Además, lo que pasa con RVM es que cubre mucho más que solo administrar Rubies, tiene mucho más que cualquier otra herramienta (hay otros aparte de RVM y rbenv: https://twitter.com/#!/mpapis/ estado / 171714447910502401 )

No olvide el soporte instantáneo que obtiene en IRC en el canal "#rvm" en los servidores Freenode.

mpapis
fuente
1
Gracias, es realmente genial que personas de ambas comunidades se estén involucrando.
superluminario
15

Entonces, para resumir las excelentes respuestas anteriores, la principal diferencia práctica entre RVM y rbenv es cuando se selecciona la versión de Ruby.

rbenv:

rbenv agrega una cuña al inicio de su ruta, un comando con el mismo nombre que Ruby. Cuando escribe rubyen una línea de comando, la cuña se ejecuta en su lugar (porque también se llama "ruby" y aparece primero en la ruta). La cuña busca una variable de entorno o .rbenv_versionarchivo para indicarle a qué versión de Ruby delegar.

RVM:

RVM le permite configurar una versión de Ruby directamente llamando rvm use. Además, también anula el cdcomando del sistema. Cuando ingresa cda una carpeta que contiene un .rvmrcarchivo, .rvmrcse ejecuta el código dentro del archivo. Esto se puede usar para configurar una versión de Ruby, o cualquier otra cosa que desee.

Otras diferencias

Por supuesto, hay otras diferencias. RVM tiene conjuntos de gemas listos para usar, mientras que rbenv requiere solo un poco más de pirateo (pero no mucho). Ambas son soluciones funcionales al problema.

superluminario
fuente
6

La principal diferencia parece ser cuándo y cómo se cambia el rubí . Ruby se cambia:

  • para RVM manualmente (uso de rvm) o automáticamente durante el cambio de directorios
  • para rbenv automáticamente cada vez que se ejecuta un comando ruby

RVM se basa en el cdcomando modificado y la selección manual de Ruby por rvm use. rbenv usa envoltorios o "cuñas" para todos los comandos básicos de ruby ​​como el mecanismo predeterminado para seleccionar ruby. RVM crea envoltorios para herramientas básicas de línea de comandos como gema, rastrillo, rubí, también. Se utilizan, por ejemplo, en CronJobs (consulte http://rvm.io/integration/cron/ ), pero no son el mecanismo predeterminado para cambiar la versión de Ruby.

Por lo tanto, ambos métodos seleccionan "automáticamente" la versión correcta de Ruby sobrescribiendo los comandos y utilizando envoltorios. rvm anula los comandos de shell como cd. rbenv anula todos los comandos básicos de ruby ​​como ruby, irb, rake y gem.

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

Te da aproximadamente:

< 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

Y antecede:

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

a $PATH

Reactormonk
fuente