Jak właściwie działają RVM i rbenv?

140

Interesuje mnie, jak faktycznie działają RVM i rbenv.

Oczywiście zamieniają się między różnymi wersjami Ruby i klejnotów, ale jak to się robi? Zakładałem, że po prostu aktualizują dowiązania symboliczne, ale po zagłębieniu się w kod (i muszę przyznać, że moja wiedza na temat Basha jest powierzchowna) wydają się robić coś więcej.

superluminium
źródło

Odpowiedzi:

241

Krótkie wyjaśnienie: rbenv działa poprzez podłączanie się do pliku środowiska PATH. Koncepcja jest prosta, ale diabeł tkwi w szczegółach; pełna miarka poniżej.

Po pierwsze, rbenv tworzy podkładek dla wszystkich poleceń ( ruby, irb, rake, gemi tak dalej) we wszystkich zainstalowanych wersji Ruby. Ten proces nazywa się ponownym haszowaniem . Za każdym razem, gdy instalujesz nową wersję Rubiego lub instalujesz klejnot, który udostępnia polecenie, uruchom, rbenv rehashaby upewnić się, że wszystkie nowe polecenia są podklejone.

Te podkładki znajdują się w jednym katalogu ( ~/.rbenv/shimsdomyślnie). Aby użyć rbenv, wystarczy dodać katalog shims na początku PATH:

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

Następnie za każdym razem, gdy uruchamiasz rubyz wiersza poleceń lub uruchamiasz skrypt, którego shebang czyta #!/usr/bin/env ruby, twój system operacyjny znajdzie ~/.rbenv/shims/rubypierwszy i uruchomi go zamiast dowolnego innego rubyzainstalowanego pliku wykonywalnego.

Każda podkładka to mały skrypt Bash, który z kolei działa rbenv exec. Więc z rbenv na twojej ścieżce, irbjest równoważne rbenv exec irbi ruby -e "puts 42"jest równoważne rbenv exec ruby -e "puts 42".

Te rbenv execdane polecenie, co wersja Ruby, którego chcesz użyć, a następnie uruchamia odpowiednie polecenie dla tej wersji. Oto jak:

  1. Jeśli RBENV_VERSIONzmienna środowiskowa jest ustawiona, jej wartość określa wersję Rubiego, której chcesz użyć.
  2. Jeśli bieżący katalog roboczy zawiera .rbenv-versionplik, jego zawartość jest używana do ustawiania RBENV_VERSIONzmiennej środowiskowej.
  3. Jeśli .rbenv-versionw bieżącym katalogu nie ma pliku, rbenv przeszukuje każdy katalog nadrzędny w poszukiwaniu .rbenv-versionpliku, dopóki nie trafi on do katalogu głównego twojego systemu plików. Jeśli taki zostanie znaleziony, jego zawartość jest używana do ustawienia RBENV_VERSIONzmiennej środowiskowej.
  4. Jeśli RBENV_VERSIONnadal nie jest ustawiona, rbenv próbuje ją ustawić używając zawartości ~/.rbenv/versionpliku.
  5. Jeśli nigdzie nie podano wersji, rbenv zakłada, że ​​chcesz użyć "systemowego" Rubiego - tj. Dowolnej wersji, która byłaby uruchomiona, gdyby rbenv nie był na twojej ścieżce.

(Możesz ustawić wersję Ruby specyficzną dla projektu za pomocą rbenv localpolecenia, które tworzy .rbenv-versionplik w bieżącym katalogu. Podobnie rbenv globalpolecenie modyfikuje ~/.rbenv/versionplik.)

Uzbrojony w RBENV_VERSIONzmienną środowiskową, rbenv dodaje ~/.rbenv/versions/$RBENV_VERSION/binna początku twojego PATH, a następnie wykonuje polecenie i argumenty przekazane do rbenv exec. Voila!

Aby dokładnie przyjrzeć się temu, co dzieje się pod maską, spróbuj ustawić RBENV_DEBUG=1i uruchomić polecenie Ruby. Każde polecenie Bash, które uruchomi rbenv, zostanie zapisane na twoim terminalu.


Teraz rbenv zajmuje się tylko przełączaniem wersji, ale dobrze prosperujący ekosystem wtyczek pomoże Ci zrobić wszystko, od instalacji Rubiego po konfigurację środowiska , zarządzanie "gemsetami", a nawet automatyzacjębundle exec .

Nie jestem do końca pewien, co ma wspólnego obsługa IRC ze zmianą wersji Rubiego, a rbenv został zaprojektowany tak, aby był na tyle prosty i zrozumiały, że nie wymagał wsparcia. Ale jeśli kiedykolwiek będziesz potrzebować pomocy, narzędzie do śledzenia problemów i Twitter to tylko kilka kliknięć.

Ujawnienie: jestem autorem rbenv, ruby-build i rbenv-vars.

Sam Stephenson
źródło
14
Dziękuję za poświęcenie czasu na udzielenie tak doskonałej odpowiedzi.
superluminarium
2
Wow, dzięki za tak zrozumiałe i zrozumiałe wyjaśnienie. Urodzony nauczyciel.
racl101
Hej, Sam, ponieważ ta odpowiedź ma dwa lata, czy chcesz wprowadzić jakieś aktualizacje? Z pewnością od tego czasu coś się zmieniło w rbenv.
Nakilon
Nie. Najlepszy opis hakera, jaki kiedykolwiek widziałem. Myślę, że jedyną aktualizacją, która wymaga zmiany, jest link do rbenv-gemset (link nadal Cię tam prowadzi. To tylko kolejny dodatkowy krok od przekierowania).
Jeffrey 'jf' Lim
18

Napisałem dogłębny artykuł: http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

Podstawowa różnica dotyczy miejsca zmiany środowiska powłoki:

  • RVM: zmienia się, gdy zmieniasz Rubiego.
  • rbenv: zmienia się, kiedy uruchamiasz plik wykonywalny Ruby / gem.

Rzecz w tym, że RVM obejmuje znacznie więcej niż tylko zarządzanie Rubinami, ma o wiele więcej niż jakiekolwiek inne narzędzie (oprócz RVM i rbenv istnieją inne: https://twitter.com/#!/mpapis/ status / 171714447910502401 )

Nie zapomnij o natychmiastowym wsparciu, które otrzymujesz na IRC w kanale "#rvm" na serwerach Freenode.

mpapis
źródło
1
Dzięki, to naprawdę wspaniałe, że ludzie z obu społeczności się w to angażują.
superluminium
15

Podsumowując powyższe doskonałe odpowiedzi, główna praktyczna różnica między RVM a rbenv polega na wybraniu wersji Rubiego.

rbenv:

rbenv dodaje podkładkę na początku ścieżki, polecenie o tej samej nazwie co Ruby. Kiedy rubypiszesz w wierszu poleceń, zamiast tego uruchamiana jest podkładka (ponieważ jest również nazywana „ruby” i znajduje się na pierwszym miejscu w ścieżce). Podkładka szuka zmiennej środowiskowej lub .rbenv_versionpliku, aby powiedzieć, do której wersji Rubiego ma być delegowana.

RVM:

RVM umożliwia ustawienie wersji Rubiego bezpośrednio przez wywołanie rvm use. Ponadto zastępuje również cdpolecenie systemowe. Po przejściu cddo folderu zawierającego plik wykonywany jest .rvmrckod znajdujący się w .rvmrcpliku. Można to wykorzystać do ustawienia wersji Rubiego lub czegokolwiek innego, na co masz ochotę.

Inne różnice:

Istnieją oczywiście inne różnice. RVM ma klejnoty po wyjęciu z pudełka, podczas gdy rbenv wymaga tylko trochę więcej hakowania (ale niewiele). Oba są funkcjonalnymi rozwiązaniami problemu.

superluminium
źródło
6

Wydaje się, że główna różnica polega na tym, kiedy i jak zmienia się rubin . Ruby jest przełączany:

  • dla RVM ręcznie (użycie rvm) lub automatycznie podczas zmiany katalogów
  • for rbenv automatycznie za każdym razem, gdy wykonywane jest polecenie ruby

RVM polega na zmodyfikowanym cdpoleceniu i ręcznym wyborze Rubiego przez rvm use. rbenv używa wrapperów lub "shims" dla wszystkich podstawowych poleceń ruby ​​jako domyślnego mechanizmu wyboru ruby. RVM tworzy otoki dla podstawowych narzędzi wiersza poleceń, takich jak gem, rake, ruby. Są używane na przykład w CronJobs (patrz http://rvm.io/integration/cron/ ), ale nie są domyślnym mechanizmem przełączania wersji Rubiego.

Dlatego obie metody wybierają „automatycznie” właściwą wersję Rubiego, nadpisując polecenia i używając opakowań. rvm zastępuje polecenia powłoki, takie jak cd. rbenv zastępuje wszystkie podstawowe polecenia ruby, takie jak ruby, irb, rake i gem.

0x4a6f4672
źródło
5
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before

Daje około:

< 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

I poprzedza:

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

do $PATH

Reactormonk
źródło