Como o RVM e o rbenv realmente funcionam?

140

Estou interessado em saber como o RVM e o rbenv realmente funcionam.

Obviamente eles trocam entre diferentes versões do Ruby e gemsets, mas como isso é alcançado? Eu tinha assumido que eles estavam simplesmente atualizando links simbólicos, mas, tendo investigado o código (e devo admitir que meu conhecimento sobre o Bash é superficial), eles parecem estar fazendo mais do que isso.

superluminário
fonte

Respostas:

241

Breve explicação: o rbenv funciona conectando-se ao seu ambiente PATH . O conceito é simples, mas o diabo está nos detalhes; colher completa abaixo.

Primeiro, rbenv cria calços para todos os comandos ( ruby, irb, rake, geme assim por diante) em todas as suas versões instaladas do Ruby. Esse processo é chamado de rehashing . Toda vez que você instalar uma nova versão do Ruby ou instalar uma jóia que fornece um comando, execute rbenv rehashpara garantir que quaisquer novos comandos sejam shimmed.

Esses shims residem em um único diretório ( ~/.rbenv/shimspor padrão). Para usar o rbenv, você só precisa adicionar o diretório shims na frente do seu PATH:

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

Então, sempre que você executar a rubypartir da linha de comando ou executar um script cujo shebang lê #!/usr/bin/env ruby, seu sistema operacional o localizará ~/.rbenv/shims/rubyprimeiro e o executará em vez de qualquer outro rubyexecutável que você possa ter instalado.

Cada shim é um pequeno script do Bash que, por sua vez, é executado rbenv exec. Assim, com rbenv em seu caminho, irbé equivalente a rbenv exec irb, e ruby -e "puts 42"é equivalente a rbenv exec ruby -e "puts 42".

O rbenv execcomando descobre qual versão do Ruby você deseja usar e, em seguida, executa o comando correspondente para essa versão. Aqui está como:

  1. Se o RBENV_VERSION variável de ambiente estiver definida, seu valor determinará a versão do Ruby a ser usada.
  2. Se o diretório de trabalho atual tiver um .rbenv-versionarquivo, seu conteúdo será usado para definir oRBENV_VERSION variável de ambiente.
  3. Se não houver .rbenv-versionarquivo no diretório atual, o rbenv procurará em cada diretório pai por um .rbenv-versionarquivo até atingir a raiz do seu sistema de arquivos. Se for encontrado, seu conteúdo é usado para definir oRBENV_VERSION variável de ambiente.
  4. Se RBENV_VERSIONainda não estiver definido, o rbenv tenta defini-lo usando o conteúdo do ~/.rbenv/versionarquivo.
  5. Se nenhuma versão for especificada em nenhum lugar, o rbenv assume que você deseja usar o Ruby "system" - ou seja, qualquer versão seria executada se o rbenv não estivesse no seu caminho.

(Você pode definir uma versão Ruby específica do projeto com o rbenv localcomando, que cria um .rbenv-versionarquivo no diretório atual. Da mesma forma, o rbenv globalcomando modifica o~/.rbenv/version arquivo.)

Armado com uma RBENV_VERSIONvariável de ambiente, o rbenv adiciona ~/.rbenv/versions/$RBENV_VERSION/binà sua frente PATHe depois executa o comando e os argumentos passados ​​para rbenv exec. Voila!

Para uma visão completa do que exatamente acontece sob o capô, tente configurar RBENV_DEBUG=1e executar um comando Ruby. Todo comando Bash executado pelo rbenv será gravado no seu terminal.


Agora, o rbenv se preocupa apenas com a alternância de versões, mas um ecossistema próspero de plugins o ajudará a fazer tudo, desde a instalação do Ruby até a configuração do seu ambiente , o gerenciamento de "gemsets" e até a automaçãobundle exec .

Não tenho muita certeza do que o suporte ao IRC tem a ver com a troca de versões do Ruby, e o rbenv foi projetado para ser simples e compreensível o suficiente para não exigir suporte. Mas se você precisar de ajuda, o rastreador de problemas e o Twitter estão a apenas alguns cliques de distância.

Divulgação: Eu sou o autor de rbenv, ruby-build e rbenv-vars.

Sam Stephenson
fonte
14
Obrigado por dar um tempo para dar uma resposta tão excelente.
superluminary
2
Uau, obrigado por uma explicação tão compreensível e compreensível. Um professor nato.
racl101
Ei, Sam, como essa resposta tem dois anos, você gostaria de fazer alguma atualização? Certamente algo mudou em rbenv desde aquela época.
Nakilon 19/04
Não. A melhor descrição de hacker que eu já vi. Eu acho que a única atualização que precisa ser alterada é no link para rbenv-gemset (o link ainda o levará até lá. É apenas mais uma etapa extra de um redirecionamento).
Jeffrey 'jf' Lim
18

Eu escrevi um artigo detalhado: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

A diferença básica é onde o ambiente do shell é alterado:

  • RVM: é alterado quando você muda o Ruby.
  • rbenv: é alterado quando você executa um executável Ruby / gem.

Além disso, o RVM abrange muito mais do que apenas gerenciar Rubies, possui muito mais do que qualquer outra ferramenta (existem outras além do RVM e do rbenv: https://twitter.com/#!/mpapis/ status / 171714447910502401 )

Não se esqueça do suporte instantâneo obtido no IRC no canal "#rvm" nos servidores Freenode.

mpapis
fonte
1
Obrigado, é realmente ótimo que pessoas de ambas as comunidades estejam se envolvendo.
superluminar
15

Então, para resumir as excelentes respostas acima, a principal diferença prática entre RVM e rbenv é quando a versão do Ruby é selecionada.

rbenv:

O rbenv adiciona um calço ao início do seu caminho, um comando com o mesmo nome que Ruby. Quando você digita rubyem uma linha de comando, o shim é executado (porque também é chamado de "ruby" e é o primeiro no caminho). O shim procura uma variável de ambiente ou .rbenv_versionarquivo para informar em qual versão do Ruby delegar.

RVM:

O RVM permite que você defina uma versão do Ruby diretamente ligando rvm use. Além disso, ele também substitui o cdcomando do sistema. Quando você está cdem uma pasta que contém um .rvmrcarquivo, o código dentro do.rvmrc arquivo é executado. Isso pode ser usado para definir uma versão Ruby ou qualquer outra coisa que você gosta.

Outras diferenças:

Claro que existem outras diferenças. O RVM possui gemsets prontos para uso, enquanto o rbenv requer um pouco mais de hackers (mas não muito). Ambos são soluções funcionais para o problema.

superluminário
fonte
6

A principal diferença parece ser quando e como o ruby ​​é alternado . Ruby é alternado:

  • para RVM manualmente (uso de rvm) ou automaticamente durante a alteração de diretórios
  • para rbenv automaticamente sempre que um comando ruby ​​é executado

O RVM depende do cdcomando modificado e da seleção manual de Ruby by rvm use. O rbenv usa wrappers ou "shims" para todos os comandos básicos do ruby ​​como o mecanismo padrão para selecionar o ruby. O RVM cria wrappers para ferramentas básicas de linha de comando, como gem, rake, ruby ​​também. Eles são usados, por exemplo, no CronJobs (consulte http://rvm.io/integration/cron/ ), mas não são o mecanismo padrão para alternar a versão do Ruby.

Portanto, os dois métodos selecionam "automaticamente" a versão correta do Ruby, substituindo comandos e usando wrappers. O rvm substitui os comandos do shell como o cd. O rbenv substitui todos os comandos básicos do ruby, como ruby, irb, rake e gem.

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

Fornece 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

E acrescenta:

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

para $PATH

Reactormonk
fonte