Mac OSXでsvkを使ってRubyをハックする。

はじめに

最近、ruby(MRI) の Readline モジュールの libedit 対応や rdoc の記述を行っています。しかし、私は ruby のコミッタではないので、作業の成果を trunk には反映できません。パッチを作成しては ruby-dev ML に報告し、それを revert して rdoc を記述する、といったことをしています。さすがにこれは面倒なので続きません。
そこで、SVK を使って、パッチの作成や変更点の管理を試してみたいと思います。
私の手元の環境は、Mac OSX 10.5 でパッケージ管理システムに Fink を使っています。残念ながら MacPorts ではありません。移行に失敗しました。
FinkSVK をインストールし、ruby のレポジトリをミラーし、パッチの作成やローカルへのコミットを行ってみます。

SVK のインストール

Fink を使って SVK をインストールします。関連するパッケージが多く、結構時間がかかりました。

ragdoll$ sudo fink install svk

SVK を使用する環境を初期化します。

ragdoll$ svk depotmap --init 
Repository /Users/kouji/.svk/local does not exist, create? (y/n)y

Rubyのレポジトリのミラー

ruby のレポジトリは大きいため、ミラーするのは trunk の最新のコミットログのみとしました。こうすることで短時間(2、3分)でミラーが完了しました。

ragdoll$ svk mirror //mirror/ruby/trunk http://svn.ruby-lang.org/repos/ruby/trunk
Committed revision 1.

ragdoll$ svk sync //mirror/ruby/trunk -s HEAD
Syncing http://svn.ruby-lang.org/repos/ruby/trunk
Retrieving log information from 18233 to 18233
Committed revision 2 from revision 18233.

作業用のブランチの作成

ragdoll$ svk copy -p -m 'copied "ruby/trunk" from mirror to local.' //mirror/ruby/trunk //ruby/trunk 
Committed revision 3.

チェックアウト

私が使用している Emacs で使いやすいように、普段は svk コマンドではなく svn コマンドを使うことにしました。これで準備が整いました。

ragdoll$ svn co file:///Users/kouji/.svk/local/ruby/trunk svk-trunk
A    svk-trunk/complex.c
...
 U   svk-trunk
Checked out revision 3.

ローカルへのコミット

早速、Readline モジュールへのパッチをコミットしてみます。無駄かもしれませんが、 ChangeLog も書いてみました。

ragdoll$ svn log -v --limit=1
------------------------------------------------------------------------
r4 | kouji | 2008-07-28 00:10:24 +0900 (Mon, 28 Jul 2008) | 20 lines
Changed paths:
   M /ruby/trunk/ChangeLog
   M /ruby/trunk/ext/readline/extconf.rb
   M /ruby/trunk/ext/readline/readline.c
   A /ruby/trunk/test/readline/test_readline_history.rb

* ext/readline/extconf.rb: checked to have clear_history in
  readline library.
* ext/readline/readline.c (hist_get, hist_each, Init_readline): 
  The offset specified for the argument of history_get() might be
  different in GNU Readline and libedit. If use libedit, it was
  corrected that the computational method of the offset specified
  for the argument of history_get() when the Readline module was
  initialized was decided.
* ext/readline/readline.c (hist_get, hist_set): If use libedit,
  accesses first an input content in history when specifies the
  negative offset for the argument of history_get() or
  replace_history_entry(). Then checks the offset is negative in
  ruby.
* ext/readline/readline.c (rb_remove_history): When compiling, it
  corrects it to warning when libedit is used.
* ext/readline/readline.c (hist_clear, Init_readline): added
  Readline::HISTORY.clear method.
* test/readline/test_readline_history.rb: added unit test for
  Readline::HISTORY.

trunkを最新の状態に更新する

trunkの変更をミラーし、ワーキングコピーを最新の状態にします。

ragdoll$ svk sync //mirror/ruby/trunk
Syncing http://svn.ruby-lang.org/repos/ruby/trunk
Retrieving log information from 18234 to 18234
Committed revision 5 from revision 18234.

ragdoll$ svk pull //ruby/trunk
Auto-merging (2, 5) /mirror/ruby/trunk to /ruby/trunk (base /mirror/ruby/trunk:2).
Conflict found in ChangeLog:
e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e]

予想していたことですが、 ChangeLog がコンフリクトします。
デフォルトの e(edit) を選択し、コンフリクトしている箇所を修正します。

<1/V1pXiLInG-WGnqamJqeocE+++TI/-Tmp-/svk-merged-csHbe" 48245L, 1551571C written
Merged ChangeLog:
a)ccept, e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [a] 

コンフリクトを修正したので、デフォルトの a(accept) を選択します。
しかし、ChangeLog のマージは毎回行うことになるので面倒です。なんとかする方法はないのでしょうかね。

G   ChangeLog
U   test/openssl/test_ssl.rb
New merge ticket: b2dd03c8-39d4-4d8f-98ff-823fe69b080e:/trunk:18234
Committed revision 6.

ragdoll$ cd ~/work/ruby/svk-trunk
ragdoll$ svn up
U    ChangeLog
U    test/openssl/test_ssl.rb
 U   .
Updated to revision 6.

trunkに修正を反映する

残念ながらできません。私は ruby のコミッターではありません。。。いつかコミッターになりたい。

パッチの作成

私の修正をパッチとして取得します。
まずはログを確認し、修正箇所を把握します。該当するのは r4 です。

ragdoll$ svn log -v limit=10
------------------------------------------------------------------------
r6 | kouji | 2008-07-28 00:22:45 +0900 (Mon, 28 Jul 2008) | 5 lines
Changed paths:
   M /ruby/trunk
   M /ruby/trunk/ChangeLog
   M /ruby/trunk/test/openssl/test_ssl.rb

 r5@ragdoll (orig r18234):  mame | 2008-07-27 23:33:05 +0900
 * test/openssl/test_ssl.rb (server_loop): rescue Errno::EINVAL and
   Errno::ECONNABORTED.
 

------------------------------------------------------------------------
r4 | kouji | 2008-07-28 00:10:24 +0900 (Mon, 28 Jul 2008) | 20 lines
Changed paths:
   M /ruby/trunk/ChangeLog
   M /ruby/trunk/ext/readline/extconf.rb
   M /ruby/trunk/ext/readline/readline.c
   A /ruby/trunk/test/readline/test_readline_history.rb

修正内容を取得し、パッチを作成します。パッチのファイル名の「no212」 は、 ruby の ITS(Redmine) の #212 のチケットに対応したパッチという意味です。

ragdoll$ svn diff -c4 > patches/no212.r4.patch 

まとめ

これで、 SVK を使って、ローカルの環境で ruby の trunk をハックできるようになりました。ruby のコミッタではないので、一段落した修正をコミットできる環境があるのは非常に助かります。
あとは、 ruby のコミッタになって svk の push を試せばこの文書は完成ですね。(いつのことだか。。。)