miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

pik を使って Windows に ruby をインストール

ruby を複数のバージョン入れて適宜切り替えたりしたい場合、*nix では rvm を使いますが、Windows では rvm は 動作しないそうなので pik を使います。

pik を使えば複数バージョンの切り替えが行えますが、それだけではなくコマンド一発で特定バージョンの CRuby や JRubyIronRuby なんかが入れられますし、複数の ruby に対して

みたいなこともできるようなので、その辺りも魅力です。

pik のインストールというと、すでに ruby がインストールされている環境で gem を使ってインストールしている方が多いようなのですが、せっかく pik で ruby のインストールが行えるわけなので、外部の ruby に頼らずにインストールする方法のメモです。(ちょっと強引です。)

pik の概要について

pik の使い方を解説しているサイトはいくつかありますが、とりあえずひとつだけ引いておきます。

ここは数少ない .msi でのインストール方法が書いてあった(外部の ruby を使う手順にはなっていますが)のと、私が最初勘違いしてた「pik コマンドでの ruby 環境の切り替えはグローバルに適用されるわけじゃなくて、そのプロセス内だけに適用される」旨も書いてあったので。

(2011-01-25 追記)

0.3.0 が近日リリース予定ということで、0.3.0.pre の MSI が公開されています。

こちらを使えば後述する設定ファイルの手動作成等は必要ありません。

(2011-01-25 追記ここまで)

pik のインストール

pik の README には msiexec でインストールする手順が書かれていますが、この方法はうまくいきません(長くなるので後述します)ので、

から .msi をダウンロードして実行してください。今回は pik 2.8.0 を使いました。

インストーラでチェックを入れれば PATH に pik のインストールディレクトリが追加されるはずですが、環境変数が更新されない環境もありました。イベントビューアに

'' のインストール時に更新された環境変数の更新中に、エラーが発生しました。コンピューターにログオンしている一部のユーザーは、ログオフしてからログオンしないと、これらの変更が見れない可能性があります。

のようなエラーが残っていたので、一度ログオフしたら大丈夫かもしれません。(ログオフしたくない環境だったので私は試していません。)

ruby のインストール→このままでは失敗する

じゃあさっそく pik install でインストールを・・・と思ったのですが。

>pik install ruby

There was an error.
 Error: can't dup NilClass

  in: pathname.rb:205:in `dup'
  in: pathname.rb:205:in `initialize'
  in: pik/commands/add_command.rb:17:in `new'
  in: pik/commands/add_command.rb:17:in `add'
  in: pik/commands/add_command.rb:13:in `execute'
  in: pik_runner:27

のようなエラーになってしまいました。(pik 2.7.0 でも同様でした。)

エラーメッセージでググると、

のように「ruby をあらかじめインストールしておく必要がある」という説明がされているんですが・・・ちょっと待てと。

pik の README には

If you want to install to a machine that doesn’t have Ruby installed yet, you can download the latest msi file from github.

と書いてありますし、出てるエラーも Ruby のエラーです(依存モジュールを見るとわかりますが、Ruby スクリプトExerb で実行形式に変換しているようです)ので、外部の ruby なしで動作させる前提で作られてるのは間違いないはずで。

このエラーがなぜ起きているか調べてみると、

  • 設定ファイル(%USERPROFILE%\.pik\config.yml)が存在していない場合は pik add を実行してこれを作ろうとする
  • このタイミングでインストール済みの ruby を探しにいく
  • パスが通っている場所に ruby がいない場合は nil が返るけど、気にせずに後続の処理を行っている

という感じのようで。

適当な ruby を pik add で登録してやれば解決するんですが、外部の ruby に頼りたくないので、適当な設定ファイルを自分で作成してしまいます。

設定ファイルを作成する

%USERPROFILE%\.pik\config.yml として

--- 
"000: ruby 0.0.0 (dummy ruby for pik)": 
  :path: !ruby/object:Pathname 
    path: C:/pik/dummy
--- {}

のようなファイルを作成しておきましょう。

この状態であれば

>pik list
  000: ruby 0.0.0 (dummy ruby for pik)

のように pik は正常に実行できます。

ruby のインストール

ではさっそくインストールを。.7z がダウンロードされた場合は途中で 7zip をインストールするか聞かれるので、ここは Enter を押下しましょう。

(2011-01-09 追記)
pik install ruby だと ruby-1.9.2dev-preview3 が入りますが、これはリリース前のプレビュー版みたいですね。pik install ruby 1.9.2-p136 として回避するのがいいみたいです。(参考
(2011-01-09 追記 ここまで)

>pik install ruby
** Downloading:  http://rubyforge.org/frs/download.php/71175/ruby-1.9.2dev-preview3-i386-mingw32-1.7z
   to:  C:\Users\miau\.pik\downloads\ruby-1.9.2dev-preview3-i386-mingw32-1.7z

ruby-1.9.2dev-preview3-i...7z: 100% |oooooooooo|   5.7MB/  5.7MB Time: 00:00:29

You need the 7zip utility to extract this file.
Would you like me to download it? (yes/no)  |yes|

** Downloading:  http://downloads.sourceforge.net/sevenzip/7za465.zip
   to:  C:\Users\miau\.pik\downloads\7za465.zip

7za465.zip: 100% |ooooooooooooooooooooooooooooo| 352.5KB/352.5KB Time: 00:00:00

** Extracting:  C:\Users\miau\.pik\downloads\ruby-1.9.2dev-preview3-i386-mingw32-1.7z
   to:  C:\Users\miau\.pik\rubies\Ruby-192dev-preview3-1
done

** Adding:  192: ruby 1.9.2dev (2010-05-31) [i386-mingw32]
 Located at:  C:\Users\miau\.pik\rubies\Ruby-192dev-preview3-1\bin

状態を確認してみます。

>pik list
  000: ruby 0.0.0 (dummy ruby for pik)
  192: ruby 1.9.2dev (2010-05-31) [i386-mingw32]

1.9.2 がインストールされているようなので、ここに環境を切り替えてバージョンを確認してみましょう。

>pik switch 192

>ruby --version
ruby 1.9.2dev (2010-05-31) [i386-mingw32]

うまくインストールされているようです。

これでこのプロセスでは ruby が使えますが、普段使いの ruby がないと不便でしょうから、インストールした ruby に PATH を通しておきましょう。pik list -v でインストールされている ruby のパスが確認できます。

ダミーの ruby を削除

pik list でダミーの ruby が出るのは邪魔なので、コマンドで消してしまいます。

>pik remove 000
Are you sure you'd like to remove '000: ruby 0.0.0 (dummy ruby for pik)'?  |yes|

000: ruby 0.0.0 (dummy ruby for pik) removed.

感想とか

以前は WindowsRuby の環境を構築するのは面倒だったので InstantRails に頼ったりしていたものですが、いつの間にか簡単になってて驚きました。

NilClass のエラーについては、余裕を見て本家に報告しておこうと思います。せっかくの .msi がもったいないので。

追記

胡散臭く報告しておきました。英語怪しいのでツッコミ&補足お願いします。(このページ、Chrome だとうまく開けないかも・・・。)

最初に報告したときは気付かなかったので慌てて再度コメントしたんですけど、master では修正されているけど .msi が古い、ということみたいですね。

      • -

さて、以下蛇足です。結構長いので、興味のある方だけどうぞ。

蛇足その1: msiexec がうまくいかない件

pik の README には

msiexec /i http://github.com/downloads/vertiginous/pik/pik-n.n.n.msi

のような形でインストールできるという記載があります。どうせ pik はコマンドラインで使いますし、わざわざ .msi をダウンロードするよりもこちらのほうが好みなのですが・・・実際に

msiexec /i https://github.com/downloads/vertiginous/pik/pik-0.2.8.msi

とやってみると、

インストール パッケージを開くことができませんでした。パッケージが存在し、アクセスできることを確認してください。またはアプリケーション ベンダーに問い合わせ、このパッケージが有効な Windows インストーラー パッケージであることを確認してください。

のようなエラーになってうまくいきません。Windows7 の問題かなと XP でも試してみたんですが、こちらでも同じエラー。

詳細なログを残すべく、

msiexec /i https://github.com/downloads/vertiginous/pik/pik-0.2.8.msi /l*vx+ msiexec.log

とやってみると、

=== Verbose logging started: 2011/01/06  13:59:45  Build type: SHIP UNICODE 3.01.4001.5512  Calling process: C:\WINDOWS\system32\msiexec.exe ===
MSI (c) (A8:CC) [13:59:45:359]: Resetting cached policy values
MSI (c) (A8:CC) [13:59:45:359]: Machine policy value 'Debug' is 0
MSI (c) (A8:CC) [13:59:45:359]: ******* RunEngine:
           ******* Product: https://github.com/downloads/vertiginous/pik/pik-0.2.8.msi
           ******* Action: 
           ******* CommandLine: **********
MSI (c) (A8:CC) [13:59:45:359]: Using WinHttp to perform URL download
MSI (c) (A8:CC) [13:59:45:359]: File path is a URL. Downloading file. . .
MSI (c) (A8:CC) [13:59:45:390]: MSI WinHttp: Proxy Settings Proxy: (none) | Bypass: (none) | AccessType: 0
MSI (c) (A8:CC) [13:59:46:437]: Download of URL resource https://github.com/downloads/vertiginous/pik/pik-0.2.8.msi failed with last error 2
MSI (c) (A8:CC) [13:59:46:437]: MainEngineThread is returning 2
=== Verbose logging stopped: 2011/01/06  13:59:46 ===

とのことで。「last error 2」ってあるけど、

ERROR_FILE_NOT_FOUND	2	0x00000002	指定されたファイルが見つかりません。

のこと??

他の http サイトではちゃんと動作するし、去年の中旬くらいまではこの方法でインストールできるという報告があるので、おそらく

あたりの問題なんじゃないかなと。

  • 2010-11-03 から github は前面的に https を利用するようになった
    • http でアクセスしても https にリダイレクトされる
  • github が使っているサーバ証明書は「*.github.com」という名称になっている
  • ここにサブドメインなしの「github.com」でアクセスした場合に、このドメインに一致しないとして証明書エラーになってしまうクライアントがある
    • wget にこのバグがあったそうで、1.12.1 で解決しているとのこと

msiexec 側が対応してくれないとどうしようもなさそう(ちょっと OllyDbg で追ったけど、時間かかりそう)なので、ひとまず諦めました。

蛇足その2: .pik/config.yml を手動で設置しない方法

NilClass の対応ですが、設定ファイルを手動で作成せずに適当なファイルを pik add で登録すればいいと思われる方もいるかもしれません。

しかし、pik add で指定するパスは

  • ファイルが実際に存在すること
  • ruby.exe、ir.exe、jruby.exe、jruby.bat という名称であること
  • -v オプションを指定して呼び出して、標準出力に吐かれた内容を元にバージョンを判定できること

を満たす必要があり、適当なパスではうまくいきません。

とはいえ、上記を満たせばいいだけですから、「ruby のバージョンっぽい文字列を標準出力に吐く .exe ファイル」を作ってしまえば事足りるわけで、ダミーの ruby.exe を作ればいいですよね。

普段こういうときは

で紹介されている arghelper や multifile を使ったりするんですけど、このあたりは GUI のアプリケーションになっていて、今回みたいに標準出力を仲介するのには使えない雰囲気。

まあ C で printf() を書いてしまえばいいんですが、余計な処理が入ってしまいそうなのでアセンブリでやってみたいなと、

を参考にして「ruby 1.0.0 (dummy ruby for pik)」と返すだけの .exe を作ってみたりもしてました。

いちおうこれを使えば

>pik add C:\pik\dummy
** Adding:  100: ruby 1.0.0 (dummy ruby for pik)
 Located at:  C:\pik\dummy

こんな感じでちゃんと登録できました。ですが外部 .exe に頼るよりは手動で設定ファイルを書くほうが穏便だろうということで、最初に書いた方法に落ち着いたのでした。

ちなみにこの「適当な文字列を出力するための .exe」を適当に長い文字列で作っておけば、バイナリエディタで編集するだけで任意の文字列を返す .exe が作れるなーと思ってた(そんな感じでいじりやすいようにアセンブリにしてた)んですが、WriteFile は文字列長を指定する必要があるので、ちょっと面倒ですね。こういうツールをご存知な方は教えてください。