おおいしつかさ


旅行とバイクとドライブと料理と宇宙が好き。
Ubie Discoveryのプログラマ。
Share:  このエントリーをはてなブックマークに追加

rubyにコントリビュートする方法

Large

rubyのバグらしき挙動を見つけたのでパッチを書いて送ってみたら、すぐに取り込んでもらえました。
https://bugs.ruby-lang.org/issues/12948
https://github.com/ruby/ruby/commit/f6e77b9d3555c1fbaa8aab1cdc0bd6bde95f62c6

rubyはGithub上でもPullRequestを受け付けているようなのですが、せっかくの機会なので正規のルートでパッチを送ってみることにしました。
やり方について調べてみたことを、次の機会のためにここに記しておきます。

バグの発見

Loggerがおかしな挙動をしていることを同僚の方が発見したので調べてみました。
ずっと昔にrubyのバージョンを2.2系にあげたのですが、そのタイミングからログファイルがローテーションされていないようなのです。
すでに存在しているログファイルがどれだけ過去のものであろうと、Loggerはローテーションせずに書き込みをしてしまいます。

require 'logger'  

File.open("tsuka.log", "w") {}  
File.utime(*[Time.mktime(2010, 1, 1)]*2, "tsuka.log")  
logger = Logger.new("tsuka.log", "daily")  
logger.info "test"  
logger.close  
p Dir.glob("tsuka.log*")  

ruby2.2以降

["tsuka.log"]  

ruby2.1以前

["tsuka.log", "tsuka.log.20161117"]  

調べてみたところ、ruby2.2以降と2.1以前とで挙動が変わっています。

本当にバグか

バグの報告については正規のドキュメントがあります。
HowToReportJa

最新版で確かめてみる

最新版(2016/11/18現在では2.3.2) で確かめたところ、2.2と同じ挙動になりました。

仕様の変更の可能性

ただ単に仕様が変更された可能性もあります。ChangeLogを読んでみたりググったりしてみました。
ChangeLogから、ローテートまわりに手が加えられたことはわかりました。しかしそれはバグの修正であり、仕様の変更ではなさそうです。
2.2で変わったこと、みたいなweb上の記事にもLoggerの仕様が変わったというような話は見つかりませんでした。

すでに報告済みかどうか

これがバグだとして、すでに報告されている可能性もあります。
しかし軽くググってみたり、Ruby Issue Tracking System を検索してみましたが、この現象に関する報告らしきものはありませんでした。

rubyの開発環境を整えてデバッグする

rubyの本当の最新状態はsubversionで管理されているリポジトリのtrunkになります。
Github上のリポジトリと、本家のリポジトリを見比べてみたところ、差異はないようでしたので、Githubからコードをとってくることにしました。

コードの取得

git clone https://github.com/ruby/ruby.git  

開発環境の用意

開発のための手引きは DeveloperHowtoJaにあります。
ビルドに必要なものはここに記載されていました。

autoconfの現在のバージョンを見てみます。

$ autoconf --version  
autoconf (GNU Autoconf) 2.69  

2.60以降のため、問題なさそうです。

$ bison  --version  
bison (GNU Bison) 2.3  

bisonも2.2以降です。

このあたりが足りなかったり、バージョンが低かったりしたときは、個々のプラットフォームにあわせてインストールしたりバージョンアップしましょう。

ビルド

$ autoconf  
$ ./configure  
$ make  

テストの実行

とりあえずテストを走らせてみます。
今回はパッチも書くつもりなので、ruby全体を壊していないことを担保するために全体テストも実施します。

$ make update-rubyspec  
$ make test-rubyspec  

update-rubyspecはspecの更新、 test-rubyspecはspecへの適合をテストします。

テストも実行します。

$ make check  

checkは test と test-all を実施します。test は簡単なテストの実施、test-all は詳細なテストの実施です。

Loggerのローテートまわりの責務を持っているのは、Logger::LogDeviceのようですので、それだけを対象としたテストもパッチを書きながら都度実施したいところです。
check は全テストなので時間がかかります。単体のテストファイルを実施するには以下のようにします。

$ make test-all TESTS=test/logger/test_logdevice.rb  

デバッグ中はこれを使っていきます。

デバッグ

これはやるだけです。テストもちゃんと書きます。
完了した後、rubyを壊していないかを確かめるために以下を再度実行して問題がないことを確認しておきます。

$ make update-rubyspec  
$ make test-rubyspec  
$ make check  

パッチをそえてバグを報告する

パッチの作り方

git上で修正したのなら、ローカルリポジトリにコミットした上で以下を実行します。

$ git diff --no-prefix HEAD~ > name_of_patch.patch  

Isuueの登録

Ruby Issue Tracking Systemにバグを報告します。

日本語で書いても大丈夫のようですが、つたなくても英語で書いたほうがいいと思います。今回は自分の英語で表現できる内容では十分でないように感じたので、日本語での補足も書きました。
以下は私が報告したIssueです。
https://bugs.ruby-lang.org/issues/12948

待つ

リアクションがあるまで気長に待ちます。
今回の場合、報告してから1時間もしないうちにtrunkにパッチを取り込んでもらえました。
https://github.com/ruby/ruby/commit/f6e77b9d3555c1fbaa8aab1cdc0bd6bde95f62c6

エラーが出てテストが通らないとき

たとえば、LoadError: cannot load such file -- openssl などのエラーがでて、make test-rubyspecなどが通らないことがあります。
この場合はそれぞれの環境に応じて、.configureにオプションを渡してあげる必要があります。

私の環境はMacで、ほとんどのパッケージはhomebrewで管理しています。
opensslのエラーが出たので以下のように対応しました。これでテストが通るようになりました。

$ brew --prefix openssl  
/usr/local/opt/openssl  
$ ./configure --with-openssl-dir=/usr/local/opt/openssl  
$ make