株式会社クリアコード > ククログ

ククログ

タグ:

ibus-daemonの--mem-profileオプションは非推奨になりました

はじめに

IBusの1.5.19からは、ibus-daemon--mem-profileオプションは非推奨になりました。 今回はその経緯について紹介します。

修正の経緯

IBusはGLibを外部ライブラリーの一つとして使っています。 このGLibですが、2.46からメモリプロファイリングに関する機能が動作しなくなりました。*1

これまでibus-daemonでは--mem-profileというオプションを指定するとメモリプロファイリングの機能が有効になり、 SIGUSR2を送りつけることでメモリ使用量に関するレポートを標準エラーに出力することができるようになっていました。 この機能を実現するために、ibus-daemonではGLibが提供する以下のAPIを使っていました。

しかし、GLib 2.46以降ではこれらの機能は非推奨となり使えません。

とはいえ、GLib 2.46というのはやや古く、これより前のものを採用しているのはUbuntu 14.04(trusty)あたりのリリースバージョンです。*2 そういった古めの環境でわざわざ最新のIBusを採用するというのは考えにくいため、IBusではGLib 2.46以前をサポートしないようにしました。

GLib 2.46以降の環境でibus-daemon--mem-profileオプションを指定した場合には警告するようになっています。

まとめ

今回はibus-daemon--mem-profileオプションが非推奨になった経緯を紹介しました。

*1 GLibとGIOとでメモリー確保の仕組みに互換性がないため。

*2 Ubuntu 14.04ではGLib 2.40が採用されている。

2018-08-14

不具合をフィードバックする時に、不具合の様子を動画で説明する

一般的に、バグ報告は「再現手順」「期待される結果」「実際の結果」をセットで説明する事が望ましいと言われます。報告をする側にとっては自明の事でも、報告を受ける側にとってはそうではないという事は多々あり、そういった情報を過不足なく伝えるための指針と言えるでしょう。

しかしながら、特定のタイミングで操作した場合にのみ再現するというような不具合だと、言葉で説明しきるのは難しい場合があります。また、日本人が英語でフィードバックするというように自分の得意でない言語を使う場面では、説明自体がそもそも困難な場合もあります。そのような場合に便利なのが「スクリーンキャスト(screencast)」です。

スクリーンキャストとは、自分が操作しているPCの画面全体またはその一部の様子を動画にした物の事です。ゲームの実況配信などもスクリーンキャストの一種と言えます。今回、Firefoxにおいてドラッグ操作と同時にタブの復元が行われると、以後のドラッグ操作のイベントが発行されなくなる、という不具合の報告を行うにあたり、現象の再現のための操作のタイミングがシビアだったため、念のためスクリーンキャストの形式でも現象発生時の様子を報告することにしました。同様の形でフィードバックをしたい人は参考にしてみてください。

スクリーンキャストの録画方法

以下は、OS標準の機能や標準添付のアプリケーションなどによる手軽なスクリーンキャスト撮影の方法をWindows、macOS、Linuxの各プラットフォームごとに例示します。文字を入れるなどの高度な編集を行いたい場合は、動画編集ツールを別途組み合わせて使ったり、より高機能なスクリーンキャスト撮影用アプリを使ったりする事をおすすめします。

Windowsの場合

Windows 10 Creators Update(バージョン1703)以降では、「ゲームバー」という機能を標準状態で使えます。これはその名の通りゲームアプリのための機能で、前述の例のようなゲーム実況を行えるよう、アプリケーションのウィンドウ単位でのスクリーンキャスト機能を含んでいます。1つのウィンドウの中で完結する現象であれば、これを使って説明用のスクリーンキャストを作成できます。

スクリーンキャストを撮影したいウィンドウにフォーカスがある状態で、キーボードのWindowsキーを押しながら「G」キーを押すと、以下のような画面が表示されます。

ゲームバーが表示された様子

ゲームバー上部の「Allow gaming features」のチェックボックスにチェックを入れると一旦ゲームバーが消えますので、もう一度ゲームバーを開きなおします。すると、先ほどまでは使用できなかったゲームアプリ向け機能を使えるようになっています。左上の「Game capturing」という領域にあるボタンがスクリーンキャスト用の機能です。

有効化されたスクリーンキャスト機能

中央の「●」アイコンのボタンをクリックすると、即座に録画が始まります。録画中は画面の右上の方に以下のような小さなツールバーが表示され、「■」アイコンのボタンをクリックすればその時点で録画が終了します。

スクリーンキャスト録画中に表示されるツールバー

録画が終了すると、撮影された動画が「ビデオ」内の「キャプチャ」フォルダ(C:\Users\(ユーザー名)\Videos\Capturesの位置)に保存されます。

保存されたスクリーンキャスト

macOSの場合

macOSでは、標準状態で添付されているアプリの「QuickTime Player」にスクリーンキャスト撮影機能が含まれています。スクリーンキャストを撮影する準備が整ったら、QuickTime Playerを起動します。

アプリケーション一覧からQuickTime Playerを選択している様子

QuickTime Playerを起動したら、メニューの「ファイル」から「新規画面収録」を選択すればスクリーンキャスト録画用のウィンドウが開かれます。

メニューの「新規画面収録」を選択している様子 画面収録の操作用ウィンドウ

赤い「●」アイコンのボタンの横にある「⌄」マークをクリックすると、カーソルを含めるかどうかなどのオプションを設定できます。準備ができたら「●」アイコンのボタンをクリックします。すると、画面上のどの領域の様子を動画として録画するかを訪ねるメッセージが表示されます。

録画する領域を訪ねるメッセージ

デスクトップ全体を録画すると動画が大きくなりすぎますので、現象を説明するのに必要最小限の領域を設定するのがおすすめです。画面上をドラッグすると、矩形選択の要領で録画対象の領域を設定できます。

録画領域が設定された状態

録画領域が決まったら、「収録を開始」ボタンをクリックすればすぐに録画が始まります。録画中は画面上部のメニューバーに「■」アイコンのボタンが表示されており、これをクリックすると録画が終了します。

録画を終了するボタン

録画された動画のプレビューが表示されますので、後は任意のファイル名で保存すれば*1スクリーンキャストは完成です。

Linuxの場合

Linuxディストリビューションのデスクトップ環境は、標準で録画機能を備えている例は今のところ無いようですが、スクリーンキャスト録画用のアプリケーションは簡単に導入できます。ここではその例としてUbuntu 16.04LTSでKazamを使う例を紹介します。

sudo apt install kazamでパッケージをインストールして、端末上でkazamコマンドを実行するかメニューから「Kazam」を選択すると、Kazamが起動します。

Kazamが起動した様子

Kazamは画面全体の録画、アプリケーションのウィンドウ単位での録画、指定した領域の録画のそれぞれに対応しています。「Window」をクリックすると、録画対象にするウィンドウをクリックで選択する画面に切り替わります。「Area」をクリックすると、録画領域を矩形で選択する画面に切り替わります。矩形選択の場合は、範囲を選択した状態でEnterキーを押すと選択が確定されます。

録画領域を設定している様子

録画対象が決まったら、メインウィンドウの「Capture」ボタンをクリックすると録画が始まります*2。Kazamが起動している間はデスクトップ上部のバーにカメラのアイコンが表示され、これをクリックしてメニューから「Finish recording」を選択すると録画を終了できます。

録画を終了する様子

録画を終了すると、動画の取り扱いを選択するダイアログが表示されます。

録画した動画の取り扱いの選択

ここから動画編集アプリを起動して加工工程に移る事もできますが、録画した物を無加工でアップロードするだけであれば、「Save for later」を選択して動画ファイルを保存します。

スクリーンキャストの公開

FirefoxのBugzilla(bugzilla.mozilla.org)ではbugに任意のファイルを添付できますので、録画したスクリーンキャストをそのまま添付・アップロードする事も可能です。

メーリングリストへの投稿の場合のように、動画そのものを添付できない*3ケースでは、別途YouTubeのような動画共有サイトに投稿してそのURLを記載するという方法をとると良いでしょう。その場合、動画の共有範囲を「公開」とするか、またはURLを知っている人なら誰でも閲覧できるように設定しておく必要があります。

まとめ

以上、各プラットフォームでのスクリーンキャストの録画手順を簡単に紹介しました。

ところで、キーボード入力に関連する報告では「ここでこのキーを押した」という情報もスクリーンキャストに含めたくなるでしょう。そのような場合には、Linuxのデスクトップ環境であればscreenkeyというツールを使ってキー入力の様子を可視化できます

障害報告のフィードバックは分かりやすい言葉で書かれているに超した事はありませんが、「言葉で説明しなければならない物」ではありません。スクリーンキャストや、あるいはスクリーンショットのように、「言葉で説明するより見た方が早い」物については、むしろ積極的に画像や動画を活用して障害発生時の様子を伝えた方が良いでしょう。皆さんも是非、様々な手段を駆使してより分かりやすいフィードバックを行うように工夫してみてください。

*1 初期状態では「.mov」形式になります。

*2 初期状態では5秒間のカウントダウン後に録画が始まります。

*3 メールに動画を添付すると、そのファイルが全受信者に複製されて届き、各受信者の通信帯域やローカルディスクを圧迫する事になるため、メールへの大きなファイルの添付は避ける事が望ましいです。

2018-07-31

IBus の最新版を使って問題の切り分けを行うには

はじめに

ソフトウェアを使っていると、意図しない挙動に遭遇することがあります。 ソフトウェアによっては、ディストリビューションで配布されているものが最新とは限りません。 そのため、場合によってはアップストリームではすでに修正済みということもあります。*1 せっかく報告しても最新版ですでに直っていたりすると、悲しいですね。そんなことのないように最新版でも確認するのがおすすめです。

そこで今回は IBus を例に、不可解な挙動に遭遇したときに最新版の IBusを使っても再現するかどうか確認する方法を紹介します。

問題の詳細について

Ubuntu 18.04上のibus-mozcを使っているときに、プロパティパネルから文字種を切り替えると、文字種の変更が追従しないことがあることに気づきました。 Xfce4のパネル1に表示されるアイコンをクリックしたときに表示されるメニューから文字種を変更したときにはそのような挙動はありません。*2

Xfce4のパネル1に表示される IBus のメニューとプロパティパネルに表示されるメニューはどちらも同じ IBusProperty で実装されているので基本的には挙動に違いはないはずです。そこで IBus の最新版で挙動を確認することにしました。

IBus の最新版をビルドするには

まずは IBus が依存しているパッケージをインストールします。build-depを使うと依存関係をまるごとインストールできるので便利です。

$ sudo apt build-dep ibus

次に、 IBus が必要としているファイルをあらかじめダウンロードして配置します。*3

$ sudo mkdir -p /usr/share/unicode/ucd
$ wget https://www.unicode.org/Public/UNIDATA/NamesList.txt
$ wget https://www.unicode.org/Public/UNIDATA/Blocks.txt
$ sudo cp NamesList.txt Blocks.txt /usr/share/unicode/ucd

次に、 IBus のソースコードを入手して、./autogen.shを実行します。

$ git clone https://github.com/ibus/ibus.git
$ cd ibus
$ ./autogen.sh

最後に、make を実行した後にインストールします。

$ make
$ sudo make install

これで /usr/local 以下へと IBus の最新版がインストールされました。

最新版のIBusを動かす手順

パッケージで IBus をすでに導入している場合、古いライブラリーを見に行ってしまうことがあります。 そこであらかじめ、ライブラリーのパスを環境変数にて指定しておきます。

$ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBLARY_PATH

これで準備ができたので最新版の IBus を試せるようになりました。

次のコマンドを実行すると、ibus-daemon を起動できます。

$ /usr/local/bin/ibus-daemon -x -r

今回追試したいのはパネル1上に表示されるメニューの挙動です。 それを有効にするには、次のコマンドを実行します。

$ /usr/local/libexec/ibus-ui-gtk3

これでパネル1に表示されるメニューの挙動を確認できるようになりました。 実際に試したところ、最新版でも同様の問題を抱えていたため、アップストリームに報告しておきました。

まとめ

今回は IBus の最新版を使って問題の切り分けを行う方法を紹介しました。

*1 細かいことをいうと、ディストリビューションが配布しているバージョンで特別にパッチを当てることで対応している場合もあります。

*2 実装が異なるibus-anthyやibus-skkにはこの問題はないようです。

*3 この作業を忘れるとautogen.shを実行したときにconfigureでエラーになります。

2018-07-25

mozregressionを使って、いつFirefoxの機能が壊れたのかを調べる

見つけた不具合をFirefoxにフィードバックする時には、それが後退バグである場合、いつの時点から不具合が発生するようになったのかという情報を書き添えておく事が大事です。この記事では、Firefoxの後退バグの発生時期を割り出す事を支援するツールであるmozregressionの使い方を解説します。

後退バグとは?

後退バグ(regression)とは、今まで正常に動いていた機能が、別の箇所の変更の影響を受けて、意図せず壊れてしまった、というケースを言い表す言葉です。

規模の大きなソフトウェアや複雑なソフトウェアでは、気をつけていても後退バグがどうしても発生してしまいがちです。後退バグが発生した直後にすぐに気付ければいいのですが、普段あまり使わない機能だと、いつからかは分からないが気がついたらその機能がずっと壊れたままだった、という事も起こりえます。

このような場面でよく使われるのが、二分探索という手法です。履歴上の「確実に正常に動作していた時点」と「現在」との中間にあたる時点のコードを調べて、その時点でまだ後退バグが発生していなければそこから「現在」との間の中間を調べ直し、その時点でもう機能が壊れていればそこから「確実に正常に動作していた時点」との中間にあたる時点のコードを調べ直す……という要領で範囲を絞り込んでいく事で、当てずっぽうで調べたり虱潰しに調べたりするよりも遙かに効率よく後退バグの発生時点を割り出す事ができます。

Gitでバージョン管理されているプログラムであればgit bisectというコマンドを使ってそれを行えますし、Mercurialにも同様にhg bisectというコマンドがあります。ただ、Firefoxのように大規模なソフトウェアでは、二分探索でその都度ビルドするというのは現実的ではありませんし、「特定の時点のNightlyのビルド済みバイナリをダウンロードしてきて展開して起動して……」という事を繰り返すのも大変です。そこで登場するのがmozregressionなのです。

mozregression-guiの使い方

Quick Startのページに英語音声の動画での解説がありますが、ここではアドオンのサイドバーパネル上のツールチップの表示がおかしくなる不具合を例に、後退バグの発生時点を割り出してみる事にします*1

mozregressionの配布ページから辿ってGUI版のWindows用ビルドをダウンロードすると、「mozregression-gui.exe」というファイルを入手できます。これはインストーラで、ダブルクリックして実行すると自動的にC:\Program Files (x86)\mozregression-guiへインストールされます。起動用のショートカットは自動的には作成されないため、インストール先フォルダを開いて「mozregression-gui.exe」のショートカットをデスクトップなどに作成しておくと良いでしょう。

二分探索の開始

mozregression-guiを起動すると、3ペインのウィンドウが開かれます。

mozregression-guiのメイン画面

メニューバーの「File」をクリックし、「Run a new bisection(新しく二分探索を始める)」を選択すると、「Bisection wizard」というタイトルのウィザードが開かれて、どのような内容で二分探索を始めるかの設定が始まります。

基本設定の画面

今回は以下のように設定しました。

  • Application(アプリケーションの種類): firefox(この他に「fennec(Android版Firefox)」「Thunderbird」も選択できます)
  • Bits(バイナリの種別): 64(Windows版のバイナリは現在は64bit版が主流なので。32bit版特有の不具合であれば「32」を選択します)
  • Build Type(ビルドの種別):opt(この他に「debug」(詳細なデバッグログを出力できるビルド)と「pgo」(最適化ビルド)も選択できます)
  • Repository(リポジトリ):mozilla-central(この他に「mozilla-beta」などのブランチや「comm-release」などのThunderbird用リポジトリも選択できます)

「Next」ボタンをクリックすると、テスト時のFirefoxの状態を設定する画面になります。

プロファイル設定の画面

特定のプロファイルで起動したときだけ後退バグが再現するという場合、再現に必要なプロファイルのパスを「Profile」欄に入力します。「Profile persistence(プロファイルの永続性)」は初期状態では「clone」になっており、テスト実行のたびに元のプロファイルを複製した物を使い捨てする事になります。「reuse」を選択すると指定したプロファイルをそのまま使う事になります。「clone-first」は両者の中間で、最初のテスト実行時に元のプロファイルを複製した後、以後のテストではそれを再使用します。ただ、新規のプロファイルでも現象を再現できる場合は、「Profile」欄は空にしておくことをお勧めします。

「Custom preferences」には、テスト実行時にあらかじめ設定しておく設定値を記述します。Bug 1474784の当初の報告内容は「extensions.webextensions.remotefalseの時に再現する」という物ですので、そのように設定する事にします。「Add preference」をクリックすると行が追加されますので、「name」欄にextensions.webextensions.remote、「value」欄には"false"と引用符でくくらずにそのままfalseと入力しておきます。

「Custom addons」には、テスト実行時にあらかじめインストールしておくアドオンを登録します。Bug 1474784の当初の報告内容はツリー型タブを使用したときという説明になっているため、アドオンの配布ページの「Firefoxへ追加」ボタンを右クリックしてリンク先のファイル(アドオンのインストールパッケージ)をダウンロードし、mozregression-guiのウィザードの「Add addon」ボタンをクリックしてファイルを選択しておきます。

さらに「Next」ボタンをクリックすると、二分探索を行う範囲を指定する画面になります。

二分探索の範囲の設定

初期状態では、起動した日とその1年前の日の範囲で二分探索を行うように入力されています。「Last known good build」欄には最後に正常に動いていたと確認できているビルドの日付を、「First known bad build」欄には最初に異常に気づいたビルドの日付を入力します。この探索範囲は、狭ければそれだけ効率よく絞り込みを行えます。Bug 1474784は7月の1週目までは起こっていない問題だったので、ここでは2018年7月6日から2018年7月11日までを範囲として入力しました。

探索の範囲を入力したら、準備は完了です。「Finish」ボタンをクリックするとウィザードが終了し、二分探索が始まります。

二分探索が始まると、検証用として先ほど指定した範囲の日付の中からいずれかの日のNightlyビルドがダウンロードされ、新規プロファイルで起動されます。この時には、ウィザードで設定した設定やアドオンが反映された状態になっていますので、後退バグが発生しているかどうかを実際に確かめてみることができます。

二分探索が始まり、後退バグの発生を確認した状態

この例では、このビルドでは後退バグが発生している事を確認できています(スクリーンショット内のNightlyのウィンドウにおいて、サイドバー部分のツールチップが適切にスタイル付けされていない事が見て取れます)。検証用のFirefoxを終了した後、mozregression-guiのメインウィンドウ左上の領域にある「Testing (ブランチ名) build: (日付)」の項目の「good」「bad」の二つのボタンのうち「bad」の方をクリックしましょう。すると再び別のビルドのダウンロードが始まり、ダウンロードが完了するとまたそのビルドが新規プロファイルで起動します。

二分探索中に、後退バグが発生していないビルドに遭遇した状態

最初のビルドに続き2番目のビルドも後退バグが発生していましたが、3番目のビルドでは後退バグは発生していませんでした(スクリーンショット内のNightlyのウィンドウにおいて、サイドバー部分のツールチップが適切にスタイル付けされている事が見て取れます)。このような場合は、mozregression-guiのメインウィンドウ左上の項目の「good」「bad」の二つのボタンのうち「good」の方をクリックしましょう。

このようにして「good」と「bad」を振り分けていくと、やがて、次のビルドが起動されない状態になります。

二分探索が終了した状態

この状態になると、二分探索は終了ということになります。mozregression-guiのメインウィンドウの左上の領域に表示される項目のうち最も下にある緑色の行が「最後の正常ビルド(last good build)」、最も下にある赤色の行が「最初の異常ビルド(first bad build)」を表しており、行をクリックすると右上の領域にそのビルドの詳細が表示されます。この例では、「最後の正常ビルド」は以下の通りでした。

app_name: firefox
build_date: 2018-07-09 14:02:55.353000
build_file: C:\Users\clearcode\.mozilla\mozregression\persist\140937d55bd0--mozilla-inbound--target.zip
build_type: inbound
build_url: https://queue.taskcluster.net/v1/task/eyRSVJsJT4WGMysouGUC_w/runs/0/artifacts/public%2Fbuild%2Ftarget.zip
changeset: 140937d55bd0babaaaebabd11e171d2682a8ae01
pushlog_url: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?fromchange=140937d55bd0babaaaebabd11e171d2682a8ae01&tochange=e711420b85f70b765c7c69c80a478250bc886229
repo_name: mozilla-inbound
repo_url: https://hg.mozilla.org/integration/mozilla-inbound
task_id: eyRSVJsJT4WGMysouGUC_w

また、「最初の異常ビルド」は以下の通りでした。

app_name: firefox
build_date: 2018-07-09
build_file: C:\Users\clearcode\.mozilla\mozregression\persist\2018-07-09--mozilla-central--firefox-63.0a1.en-US.win64.zip
build_type: nightly
build_url: https://archive.mozilla.org/pub/firefox/nightly/2018/07/2018-07-09-22-12-47-mozilla-central/firefox-63.0a1.en-US.win64.zip
changeset: 19edc7c22303a37b7b5fea326171288eba17d788
pushlog_url: https://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=ffb7b5015fc331bdc4c5e6ab52b9de669faa8864&tochange=19edc7c22303a37b7b5fea326171288eba17d788
repo_name: mozilla-central
repo_url: https://hg.mozilla.org/mozilla-central

これらの情報をbugの報告に書き添えておくと、実際に修正を行おうとする人の調査の手間が大幅に軽減されます。

なお、最初の異常ビルドの「pushlog_url」欄に現れているURLを開くと、前のビルドからそのビルドまでの間に行われた変更の一覧が現れます。この例では40以上のコミットが一度にマージされた時点から後退バグが発生したという事が読み取れ、後はこの中のどの変更が原因だったかを割り出すという事になります。運がよければ、最初の異常ビルドでの変更が1コミットだけに絞り込める場合もあり、その場合は調査範囲が一気に限定されます。

まとめ

以上、mozregressionを使ってFirefoxの後退バグの発生時点を割り出す手順をご紹介しました。

後退バグの修正にあたっては、いつの時点から機能が壊れていたのか、どの変更の影響で機能が壊れたのか、という事を特定する事が重要です。どの変更でおかしくなったのかが分かれば、原因箇所を特定する大きな手がかりになります。また、新たな別の後退バグを生み出さないためには、後退バグの発生原因となった変更の意図を踏まえつつ対応策を検討する事が有効です。後退バグを報告する場合は、できる限り「どの変更から問題が発生するようになったか」を調べてから報告することが望ましいです。

ただ、このように二分探索で後退バグの発生時点を割り出すためには、各コミット段階で「問題が発生するかどうかを確実に確認できる事」が必須条件となります。ミスが原因で「そもそも起動すらしない」状態のコミットが途中に存在していると、動作を確認できるのは「正常に起動するコミット」の間だけになってしまい、二分探索を有効に行えません。GitHub Flowのようにmasterを常にいつでもリリースできる状態に保ったり、プルリクエストのマージには必ずCIが通る事を条件にしたりといった運用をとる事もセットで行う必要があります。後退バグが発生しても原因をすぐに特定しやすいよう、健全なプロジェクト運営を心がけたいものですね。

*1 このBug自体は実際には既に報告済みの他のBugと同じ原因であったことが分かったため、既にあった方のBugで続きをトラッキングするよう誘導されて閉じられています。

2018-07-18

MozReviewでのFirefoxへのパッチ投稿方法

はじめに

前回の記事ではFirefoxへのフィードバックの仕方を紹介しました。当記事で紹介したように、Firefoxへのパッチ投稿は、以前はBugzillaにパッチファイルを手動で添付する形で行われていました。その方法は今でも通用するのですが、最近ではMozReviewというReview Boardベースのコードレビューシステムも導入されています。GitHubと同様にソースコードにインラインでコメントを付けられますし、パッチをリモートリポジトリでバージョン管理できるので、現在ではこちらを使用する方がおすすめです。しかし最初に少し設定が必要ですので、使い始めるまでに心理的障壁があるのも事実かと思います。そこで今回はMozReviewの使用方法について紹介します。

セットアップ

本記事で紹介するセットアップ方法はMozReview User Guideを元にしています。詳細はそちらを参照して下さい。

用意するもの
  • BMO(bugzilla.mozilla.org)のアカウント
    • まだBMOアカウントを取得していない場合は https://bugzilla.mozilla.org/createaccount.cgi で作成します。
    • Real nameにはYour Name [:ircnick]のような形で末尾にニックネームを付けておきましょう。
      • Review Board上ではこのニックネームがユーザー名として表示されます。
      • ただし、既に存在するニックネームは使用できません(代わりにメールアドレスのアカウント名+任意の数字になります)。
  • mozilla-centralのワーキングコピー
    • 前回の記事等を参考に、hg clone https://hg.mozilla.org/mozilla-centralで取得して下さい。
    • 本記事ではバージョン管理システムとしてMercurialを使用する場合のみを対象とします
      • MozReviewはgitでも使用できるようですが、本記事では対象としていません。
Review Boardへのログイン確認

MozillaのReview Boardは https://reviewboard.mozilla.org でアクセスできます。Bugzillaアカウントの登録が終わったら、Review Boardにもログインできることを確認してみましょう。アカウントはBugzillaと連携されているため、Review Boardのログインページにアクセスすると、自動的にログインすることができます。

Review Boardにログインできたら、画面右上のユーザー名を確認して、先ほど設定したニックネームを使用出来ていることを確認すると良いでしょう。

MozReviewユーザー名

APIキーの生成

自分がソースコードに対して行った変更をMercurialでreviewboard.mozilla.orgにpushするためには、BugzillaのAPIキーが必要になります。この後のMercurialのセットアップの際に必要になりますので、事前に生成しておきましょう。APIキーの作成はBugzillaアカウント設定画面のAPI Keysページで行うことができます。

APIキーリスト

Mercurialの追加セットアップ

MercurialでMozReviewと連携できるようにするためには、Mercurialに追加の設定が必要になります。この設定は前回の記事でも紹介した./mach bootstrapの中で対話的に行うことができます。ただし、前回はMozReviewについての説明は省略したため、それに関するセットアップは飛ばしてしまっているかもしれませんね。Mercurialを最初から設定し直したい場合は、既存の~/.hgrcを退避させて、./mach mercurial-setupで実行することができます。

$ cd /path/to/mozilla-central
$ mv ~/.hgrc ~/.hgrc.bak
$ ./mach mercurial-setup

後はコンソールに表示される指示に従って必要な項目(自分のフルネーム、メールアドレス、ニックネーム等)をセットアップして行けば良いです。Yes/Noで答えるものについては、基本的には全てYesで良いでしょう。

以下の項目については、一度MozReviewを設定してしまえは他の方法でパッチを投稿することは無いでしょうから、1で良いでしょう。

Commits to Mozilla projects are typically sent to MozReview. This is the
preferred code review tool at Mozilla.

Some still practice a legacy code review workflow that uploads patches
to Bugzilla.

1. MozReview only (preferred)
2. Both MozReview and Bugzilla
3. Bugzilla only

Which code review tools will you be submitting code to?  

以下の項目では、先ほどBugzillaで生成したAPIキーをコピペして入力します。

Bugzilla API Keys can only be obtained through the Bugzilla web interface.

Please perform the following steps:

  1) Open https://bugzilla.mozilla.org/userprefs.cgi?tab=apikey
  2) Generate a new API Key
  3) Copy the generated key and paste it here

./mach mercurial-setupが正常に終了したら、~/.hgrcを確認して必要な項目が適切に設定されていることを確認します。

[ui]
username = Your Name <your.name@example.com>

[extensions]
reviewboard = /path/to/home/.mozbuild/version-control-tools/hgext/reviewboard/client.py

[paths]
review = https://reviewboard-hg.mozilla.org/autoreview

[mozilla]
ircnick = nick

[bugzilla]
username = your.name@example.com
apikey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

レビューリクエストの作成

前回の記事で紹介したように、Firefoxで何かパッチを投稿したい場合は、全てBugzilla上の該当Bugを起点に作業を行います。何か新機能を追加したり、不具合修正を行いたい場合は、まず該当するBugが既に存在するかどうかを確認し、無い場合は新たに自分で新しいBugをfileします。

該当Bugでソースコードに対して何か変更を行って、いざMozReviewでパッチを投稿したいとなった場合、まずはMercurialで手元のリポジトリに変更をコミットします。

$ hg commit

このとき、コミットメッセージの形式に注意しましょう。具体的には以下のような形式にする必要があります。

Bug [Bug番号] - [Bugの概要(一行)]

以下、Bugの詳細についての記述...

Mercurialでリモートリポジトリにpushする際、上記のコミットメッセージのBug番号から自動的にBugzillaの該当Bugにパッチが投稿されます。

また、末尾にr?ircnickという形式でレビュアーを指定すると、push後に自動的に該当レビュアーにレビューリクエストを投げることもできます。このレビュアーの指定はpushした後にReview BoardのWeb UIから行うこともできますので、必ずしもコミットメッセージに含める必要はありません。

以下に、筆者が実際にパッチを投稿した際のコミットメッセージを示します。

Bug 1306529 - OmxDataDecoder: Fix a stall issue on shutting down r?jya

Because the shutdown closure awaits finishing itself by
TaskQueue::AwaitShutdownAndIdle(), the function blocks infinitely.

The code is wrongly introduced at the following commit:

  * https://bugzilla.mozilla.org/show_bug.cgi?id=1319987
    * https://hg.mozilla.org/mozilla-central/rev/b2171e3e8b69

This patch calls it on mTaskQueue intead of mOmxTaskQueue to
avoid the issue.

詳細な議論はBug番号から辿ることができるため、コミットメッセージには必ずしも詳細な記述は必要ないようです。有った方が好ましいとは思いますが、慣れていない場合には、まずはBug番号と一行サマリを適切に記載することに注力すると良いでしょう。

ローカルリポジトリへのコミットが完了したら、リモートリポジトリにpushします。

$ hg push review

pushが完了すると、以下のようにReview Board上のURLが表示されますので、後の操作はWeb UI上で行うことができます。

...
submitting 1 changesets for review

changeset:  424886:1e4bfbffe0de
summary:    Bug 1451816 - [Wayland] Avoid closing popup window on button-press on Weston r?stransky
review:     https://reviewboard.mozilla.org/r/254690 (draft)

review id:  bz://1451816/takuro
review url: https://reviewboard.mozilla.org/r/254688 (draft)

この状態では、レビューリクエストはまだ公開されておらず、レビュアーにも通知は届いていません。 最後に以下のようにレビューリクエストを公開するかどうかを尋ねられますので、

publish these review requests now (Yn)?  

ここでyを入力すると、レビューリクエストが公開され、レビュアーに通知されます。 ここではいったんnとしておいて、Web UI上でレビュアーを指定した上でレビューリクエストを公開することも可能です。この場合は下記画面のReviewersでレビュアーを指定した後、Publishを押してレビューリクエストを公開します。

Review Board

これでレビューリクエストは完了ですが、Bugzillaの該当Bugの方も確認して、Review Board側のレビューリクエストと正しく紐付けられていることを確認しておくと良いでしょう。

なお、先ほどコミットした内容をhg exportで確認してみると、以下のようにMozReview-Commit-IDという行が追加されていることに気が付きます。

# HG changeset patch
# User Your Name <your.name@example.com>
# Date 1530688340 -32400
#      Wed Jul 04 16:12:20 2018 +0900
# Node ID 1e4bfbffe0de2870b7539a8ed42b9b6d6721fc87
# Parent  987ea0d6a000b95cf93928b25a74a7fb1dfe37b2
Bug 1451816 - [Wayland] Avoid closing popup window on button-press on Weston r?stransky

MozReview-Commit-ID: 2khX59CotQK

...

これは後にレビュー結果を受けてパッチを修正する際に必要になります。

パッチの修正

レビュアーによってパッチがレビューされ、Review Board上で修正箇所を指摘されたら、パッチを修正して再度Review Boardにpushすることになります。この際、同一のレビューリクエストに対する修正であることを指定するために、先ほどと同じMozReview-Commit-IDをコミットメッセージに含めてhg commitし、hg push reviewします。

Mercurialでのパッチ管理方法は本記事のスコープ外のため割愛しますが、パッチ(コミット)が1つのみで、ローカルリポジトリに過去のバージョンが不要である場合、もっとも簡単な修正方法はhg commit --amendで前回のコミットをやり直す方法でしょう。この方法の場合、コミットメッセージは特に修正しなければ前回のままとなりますので、MozReview-Commit-IDも前回と同じものが使用されます。ローカルリポジトリの修正は上書きされてしまいますが、リモートリポジトリ上では過去のバージョンも管理され、その差分を確認することもできます。

Review Board Diff

修正をpushしたら、Review Board上でレビュアーのコメントに返信をします。この際も、最後にPublishボタンを押すことを忘れないで下さい。なお、Review Board上の会話は自動的にBugzillaの該当Bugの方にも同じ内容が投稿されます。

レビューが通ったら

レビュアーによってパッチが問題ないと判断された場合、r?あるいはr-となっていた部分がr+に変更されます。この状態になったら、前回の記事と同様に、Bugzilla上で「whiteboard」欄にcheckin-neededのキーワードを付加して、パッチをチェックインしてもらいます。

まとめ

MozReviewでのFirefoxへのパッチ投稿方法について紹介しました。

なお、記事中で例として紹介したBug 1451816はGNU/LinuxのWestonという環境でポップアップウィンドウのボタンを操作できないという問題です。本質的な修正は他のBugで行う必要があり、投稿しているパッチは必ずしも本体に入れるつもりの無いad-hocなパッチです。このようなパッチでも、アップストリームに報告しておけば同じ問題で困っている人の助けになるかもしれませんし、本質的な修正のヒントになる可能性もあります。自分のパッチに価値があるかないかは出してみないと分かりませんので、皆さんも臆することなくどんどんパッチを提出してみてはいかがでしょうか。

2018-07-05

Firefoxへのフィードバックの仕方:Windows編

近年はOSS・フリーソフトウェアのリポジトリを公開する場所としてGitHubが選ばれる事が多くなりましたので、フィードバックをする際も、GitHub上のIssuesで障害を報告したり、Pull Requestという形で具体的なソースコードの変更を提案したりといった形を取る事が多くなりました。同様のフィードバック方法が、BitBucketやGitLabなどの競合サービスにおいても可能です。

その一方で、歴史の長いプロジェクトではフィードバックの受け付けがメーリングリストに限られていたり、ソースコードがGitHub等での公開ではないため実装の提案をプルリクエストの形では行えなかったりという事があります。Firefoxもそういった例の1つで、不具合の報告や機能の追加要望はBugzillaで行い、実装内容は伝統的なパッチやMozReviewといった専用ツールで送付する必要があります。

そこでこの記事では、Windows上でFirefoxに対してパッチを含むフィードバックを行う際の流れをご紹介します。基本的にはHow to submit a patchという記事日本語訳)に書かれている内容ですが、本記事では周辺情報も併せてまとめています。Firefoxに直接的なフィードバックをしてみたいという方は、ぜひ参考にしてみて下さい。

まずは、ソースコードからFirefoxをビルドできるようにする

パッチを送付するようなフィードバックを行うためには、まずソースコードからFirefoxをビルドできる環境を整えておきます。1行だけの変更なのに大袈裟な……と思うかもしれませんが、Firefoxほどの規模のソフトウェアでは、些細な変更が予想もしない所に影響を及ぼす事があります。ファイルの内容に変更を行う際は必ずビルドと自動テストを行い、後退バグ(regression)が発生していない事を確認する必要があります。

基本的には、Windows上でのビルド環境一式がセットになっている「MozillaBuild」というツールを使う事になります。これにはMSYSベースのUnix系コマンド群やPython、Mercurialなどが含まれています。また、以下の手順の中に含まれていますが、それ以外の必要なツール類も半自動でインストールされるので、準備は非常に簡単です。

以下は、2018年7月3日時点でのビルド環境整備手順の要約となります。

  1. MozillaBuildの最新版リリースをダウンロードし、インストールする。一般的にはc:\mozilla-buildにインストールする。
  2. C:\mozilla-sourceの位置にフォルダを作る。Firefoxのソースコード一式はこの配下に置く事になる。
  3. c:\mozilla-build\start-shell.batを実行して、MozillaBuildのシェル(Bash)を起動する。
  4. export PATH=$PATH:~/.cargo/bin という行を、~/.bash_profile~/.bash_login、または~/.profileのいずれかに追記する。echo 'export PATH=$PATH:~/.cargo/bin' >> ~/.bash_profileのようにするとよい。
  5. MozillaBuildのシェルを一旦終了し、c:\mozilla-build\start-shell.batで起動し直す。
  6. cd /c/mozilla-sourceして、パッチを書く対象となるFirefoxのMercurialリポジトリをcloneする。
    • 通常は、最新の開発版のリポジトリであるmozilla-centralをcloneする。hg clone https://hg.mozilla.org/mozilla-centralでcloneできる。以下の説明はこちらのケースを前提とする。
    • ベータフェーズにあるバージョンへのパッチを作りたい場合は、releases/mozilla-betaをcloneする。hg clone https://hg.mozilla.org/releases/mozilla-betaでcloneできる。
    • 既にリリースされたバージョンへのパッチを作りたい場合は、releases/mozilla-releaseをcloneする。hg clone https://hg.mozilla.org/releases/mozilla-releaseでcloneできる。
  7. cd mozilla-centralしてリポジトリに入り、./mach bootstrapを実行する。これにより、Visual StudioやRustなどのビルドに必要なソフトウェア群が自動インストールされる。

必要なソフトウェア群が揃ったら、./mach buildでFirefoxをビルドして、ビルドが完了後に./mach runでFirefoxを起動してみましょう。無事に起動すれば、準備は完了です。

ビルド時間を短縮するには

Firefoxのビルドに要する時間のほとんどは、C++で実装された基盤部分のバイナリのビルド時間です。フィードバックしたい変更がGUI部分のJavaScriptの実装に関わる部分だけであるという場合、ビルド済みバイナリを使ってビルド時間を短縮する事もできます。これはartifact buildと呼ばれます。

artifact buildを使うためには、リポジトリ直下に置く.mozconfigというファイルを使ってFirefoxのビルドオプションを指定する必要があります。具体的には以下の要領です。

cd /c/mozilla-build/mozilla-central
echo 'ac_add_options --enable-artifact-builds' >> ./.mozconfig
echo 'mk_add_options MOZ_OBJDIR=./objdir-frontend' >> ./.mozconfig

この状態で./mach buildを実行すると、C++のコンポーネントをビルドする代わりにビルド済みバイナリが自動でダウンロードされてきて、それと組み合わせる形でFirefoxがビルドされるようになります。

筆者はJavaScript部分だけのフィードバックとC++部分に関わるフィードバックのどちらも行う場合があるため、/c/mozilla-source/mozilla-central-artifact/c/mozilla-source/mozilla-central-fullという具合にリポジトリ自体を2つcloneしておき、片方をartifact build専用にして使っています。

「自分の名前」を設定しておく

作業を始める前に、Mercurialリポジトリへのコミットに表示される作業者名を設定しましょう。これは、MozillaBuildのシェルから見た時に~/.hgrcの位置にあるファイルで指定します。具体的には、以下のように書きます。

[ui]
username = YUKI "Piro" Hiroshi <yuki@clear-code.com>

パッチを書けそうなBugを報告する、または見付ける

Firefoxでは、不具合の報告や新機能の提案はすべて「Bug」としてbugzilla.mozilla.orgのバグトラッカーで管理されています。

Bugを登録する場合は、まずアカウントを作成してログインします。ログイン済みの状態だと、ページ上部に鉛筆型のアイコンの「File a new bug」というリンクが現れ、そこから新しいBugを報告・登録することができます。Bugの登録時にはまずそれがどの部分(プロダクト)の話なのかを指定する必要がありますが、基本的には、FirefoxというWebブラウザ固有のUIや機能に関わる話題は「Firefox」プロダクト、Thunderbird等と共通の基盤部分のうちJavaScriptで実装されている物は「toolkit」プロダクト、C++で実装された低レベルの基盤技術に関わる物は「core」と覚えておくとよいでしょう。また、プロダクトの選択後はさらに細分化された「コンポーネント」を選択する必要がありますが、リストの中からそれらしいものを選んでおけば大丈夫です。もしプロダクトやコンポーネントを間違えたとしても、他の開発者の人がBugの内容に合わせた適切なプロダクト・コンポーネントを再設定して誘導してくれます。その後、「summary(要約)」と、コメントとして「steps to reproduce(詳細な再現手順)」「expected result(期待される結果)」「actual result(実際の結果)」を入力して投稿すれば、Bugの報告は完了です。

既ににあるBugの中からパッチを書けそうな物を探す場合は、good-first-bugというキーワードで検索すると、比較的難易度が低いと考えられているBugを一覧表示することができます。興味のある話題のBugを見付けたら、これまでの経緯を読んで、どのようなパッチが求められているのかを読み取ってみましょう。

パッチを書くBugを登録あるいは検索結果から見付けたら、他の人が同時に作業を始めないように、自分がこれからパッチを書いてみますという事を宣言しておくとよいでしょう。これは、単純に「Now I'm trying to write a patch for this bug.」のように書いてもいいですし、「Assignee(担当者)」という欄に自分のアカウント名を設定しても良いです(前者のようにだけしていても、他の人が気を利かせてあなたの名前をAssigneeに設定してくれる事もあります)。

パッチを実際に作成する

準備ができましたので、早速パッチを作ってみる事にします。

クリーンな環境に戻す

以前にパッチを作るために変更した結果が残っていると、作成したパッチが期待と異なる内容になってしまいます。Mozilla公式のリポジトリの内容に対するパッチを作るために、まず以下のようにコマンドを実行し、リポジトリの状態をMozilla公式の物と同じに揃えておきましょう。

hg update -C default # 変更を全て取り消す
hg pull -u # Mozillaのリポジトリから変更点を複製し、手元のコピーに反映する
作業用のブランチを作る

次に、作業用の一時的なブランチを作成します。hg branch fix-bug-xxxxx-workingのように実行して、新しいブランチの作成を予約しましょう(gitではgit checkout -b branch-nameのようにするとその瞬間にブランチが作られますが、Mercurialではこのように「ブランチの作成を予約」した後で何かコミットした段階で初めてブランチが作られます)。

このブランチそのものは、後でパッチを作るための素材として使うだけなので、名前には「working」を付けて作業用である事を示しています。(用事が終わったら、このブランチはhg branch -C xxxxxコマンドで消去してしまって問題ありません。)

コードを改変する

問題を修正するための変更(新機能を追加するための変更)を行います。変更はhg commit path/to/fileでコミットすることができ、新しいファイルを追加する場合はhg add path/to/fileでリポジトリに登録できます。作業経過を失わないように、こまめに「Bug XXXXX - 変更の概要」といった要領のコミットメッセージを付けてコミットするようにしましょう。コミット時にはEmacsが起動しますが、普通にコミットメッセージを入力して、上書き保存して終了すればOKです。

方針を間違えたなどの理由でコミットを取り消したくなった場合は、hg log -Gでコミットツリーを表示して、取り消したいコミットの番号(XXXX:YYYYYYYという形式の、数字と文字列の組)を調べた上で、調べたコミットの番号の「:」より手前の数字を指定してhg strip XXXXと言うコマンドを実行します。こうすると、指定したコミットとその後に続くコミットが無かったことになります。

また、コミット単位ではなく作業そのものを最初からやり直したいという場合には、ブランチそのものを破棄して作り直すのが手っ取り早いです。その場合はhg update -C defaultでデフォルトブランチに戻した上で、hg branch -f fix-bug-xxxxx-working-fオプションを付けて同名のブランチ作成を予約すれば、ブランチ作成の時点から作業をやり直す事ができます。

自動テストを書く

不具合の修正でも新機能の追加でも、対応する自動テストの追加は原則として必要です。変更対象のファイルの近傍に自動テストのファイル群が配置されている事が多いはずなので、それらを参考にして、関連していそうなテストファイルにテストケースを追加したり、あるいはテストのファイルそのものを新たに追加したりしましょう。

新しいテストファイルを追加する場合は、hg addでのリポジトリへの登録だけでは不十分で、同じディレクトリのiniファイルにもテストファイル名を追記する必要があります。

自動テストを実行する

自分で追加した自動テスト(テストケースを追加したファイルや、自分で追加したテストファイル)は、./mach test path/to/test/dir/or/fileとすると適切なフレームワークで実行する事ができます。テストが確実に通る事を確認しておきましょう。また、ディレクトリを指定すると複数のテストを一括実行できますので、関連する他の機能に意図しない影響を及ぼしていないか(他のテストが失敗するようになっていないか)も確かめておきましょう。

(なお、何度もパッチを投稿していると、tryserverという自動テスト専用のサーバーの使用権を貰えることがあります。tryserverを使うとWindows以外のプラットフォームでも自動テストを実行できますし、手元での実行ではないのでテストの実行中も他の作業を並行して行えるので、非常に有用です。tryserverの使用権を持っている場合は、./mach try -b o -p linux,macosx64,win64 -u all -t none --no-artifactというコマンド列を実行するだけで、現在作業中のブランチの内容を反映した状態でtryserver上で全てのテストを実行する事ができます。)

変更の完了とパッチ作成の準備

作業用ブランチ上で複数回コミットしていた場合、変更内容を1つにまとめたコミットを作成してパッチにします。これは以下の手順で行うことができます。

hg diff -r default > ../working.diff # 変更内容を差分ファイルに出力する
hg update -C default # デフォルトブランチに切り替える
hg pull -u # 念のためデフォルトブランチの状態を最新にする
hg branch -f fix-bug-xxxxx # ブランチを作り直す
patch -p 1 < ../working.diff # 差分ファイルに出力した内容を書き戻す
hg add path/to/added/files # ファイルを追加していた場合は、この時点で手動で追加し直す。
hg commit

この時のコミットメッセージは「Bug XXXXX - 変更の概要」のようにします。このコミットメッセージはパッチに含まれる事になります。

複数回のコミットがあった状態のままでパッチを作成すると、1コミットが1パッチとして分割される事になります。大規模な変更を行う場合はパッチも複数に分けて段階的に反映する場合がありますが、そのような大規模な変更を行う機会は一般の外部コントリビューターはまず行う機会がありませんので、基本的には上記の手順で1コミットにまとめるようにしましょう。

なお、自分が作業を始めた時点のデフォルトブランチの状態とhg pull -uで更新したデフォルトブランチの状態が異なっていた場合(自分が作業中に他の人の変更が反映された場合)、パッチの適用に失敗する事があります。このような場合、衝突箇所を修正して(自動テストも再実行して)、「最新のデフォルトブランチに対して行った変更」という体裁のパッチに手直しする必要があります。

変更の完了とパッチの提出

準備が整ったら、このブランチの変更内容をパッチとしてBugに添付します。hg bzexport -eというコマンドを実行すると、Emacsが起動してコメントの入力を求められます。対応するBugの番号が最初の行に「Bug XXXXX」と表示されていれば大丈夫なので、そのまま保存して終了して下さい(「No changes made; continue with current values (y/n)?」と訊かれるので、yと入力して下さい)。コミットメッセージにBugの番号を入れ忘れていた場合は、対応するBugの番号を「Bug XXXXX」のように記入した上で、変更を保存してEmacsを終了します。すると、パッチがBugに自動的に添付されます。 (なお、同じBugに複数回パッチを送信すると、前のパッチは自動的に「Obsolete」扱いになります。)

Mercurialの拡張機能がまだインストールされていないと、hg bzexport -eはエラーになります。その場合は、先に./mach mercurial-setupを実行して必要なプラグインをMercurialにインストールしておいて下さい。

Mozillaでは、全てのパッチはレビュアーによるレビューを経てからマージされる運用になっています。このパッチをFirefoxに取り込んでもらうためには、レビューを依頼しなくてはいけません。

パッチがBugに添付されたら、Bugのページをブラウザで開いて、添付されたパッチの「Details」のリンクをクリックします。「review」という欄があるので「?」を選択し、その隣の入力欄にレビュアーを指定してレビューを依頼します。基本的にはそのモジュールの担当者を設定するのですが、誰に依頼したらいいか分からない場合は、suggested reviewersという所をクリックすると、お薦めレビュアーが出てきます(モジュールから自動的に検索された結果が一覧表示されます)。基本的には、レビューのキューの数が少ない人を設定するのがお薦めです。ただし、レビューの件数が多くても猛烈なスピードで消化する人や、レビューの件数が少なくてもなかなかキューが減らない人もいるので、できれば類似のBugを見て活動がアクティブな人を設定する方が望ましいです。

その後、指定した人物によりレビューが行われます。レビューを無事通過できれば、パッチのメタ情報に「r+」と表示されるようになります。

パッチの内容に不具合や考慮不足、コーディングルールに反している部分などがあると、レビューが却下され、パッチのメタ情報のステータスが「r-」になります。その場合は、指摘された問題点を修正してパッチを再提出しましょう。

なお、このように伝統的な差分ファイル形式のパッチを使ったパッチ提出のやり方の他に、現在ではMozReviewという専用の仕組みを使ったレビュー運用も行われています。こちらについては別途、別の記事で詳しく解説します。

チェックインの依頼

パッチのステータスが「r+」になったら、いよいよチェックインです。Bugの「whiteboard」欄にcheckin-neededと記入してBugを更新しておくと、担当者の人がそれを見付けて、だいたいその日の中に「inbound」というリポジトリにパッチをチェックインしてくれます。このinboundの自動ビルドと自動テストで何もエラーが検出されなければ、同じ内容が自動的にmozilla-centralなどのリポジトリにチェックインされます。

もしinboundのビルドや自動テストが失敗した場合は、その旨のコメントがBugに書かれますので、適切に対応してパッチを再提出する事になります。もし自分の行った変更が原因で他の自動テストが失敗したようなら、それらのテストに悪影響を与えた原因を修正したり、あるいは、もし他の部分の方に問題がある場合(例えば、やっつけで実装されていたテストが、自分の行った変更の影響で失敗するようになった場合など)はそちら側を修正したりします。

また、inboundへのチェックイン自体に失敗したという事でパッチが差し戻される事もあります。これは、自分が作業した時のデフォルトブランチの状態と、担当者がinboundにパッチをチェックインしようとした時の最新の状態とがずれていて、パッチが衝突してしまったという場合に起こります。その場合、複数コミットを1つのコミットにまとめる時と同じ要領で、最新のデフォルトブランチを対象にしてパッチを作り直しましょう。他の変更と衝突はしていたものの、パッチは全体的に以前の物から代わっていないと言える場合は、再レビュー依頼を省略できます。再提出したパッチに対して「r?」を設定する代わりに「r+」を自分で付けて、コメントには「r+ is carried-over from the previous patch」のように書いておきましょう。

Beta版のBugを直したい場合は

次期リリースのBeta版を使っていて見付けた問題でも、まずはmozilla-centralに対して修正を行います。以下は、変更が既にmozilla-centralに反映されたという前提での話になります。

まず、releases/mozilla-betaのリポジトリをローカルにcloneして、mozilla-centralにチェックインされたパッチをpatch -p 1 < path/to/patch.diffで反映します。もし衝突が発生してパッチを反映できなかった場合は、衝突箇所を修正してコミットし、新しいパッチを作り直して改めて提出します。内容的に変更がなければ、ここでもレビューを省略して「r+」を自分で付け、前のパッチからレビュー済みの状態を引き継いだ旨を書いておきます。

元のパッチがそのままBetaに反映できる状態、またはBeta向けにパッチを再提出し終えた状態で、そのパッチをreleases/mozilla-betaに取り込んでもらうよう依頼する事を、uplift申請と言います。Beta版またはリリース版に対しては原則としてこのuplift申請を経由してパッチが取り込まれるようになっています。

uplift申請をするには、当該パッチの詳細情報の画面で「approval-mozilla-beta」欄に「?」を設定します。すると、コメント入力欄にuplift申請のテンプレートが自動入力されますので、「ベータフェーズでクオリティを高める段階にある今、新たな問題を引き起こすリスクを押してでもこの変更を反映するべき理由」「この変更を反映しても問題は起こらないと言える理由」を説明するよう各欄を埋めて投稿します。実際の申請例(Firefox 60betaに対して、セーフモード無効化のポリシー設定を導入するパッチのuplift申請を行っている物)も参照して下さい。申請が受理されれば、パッチはチェックインされます。

充分な理由を示せていなかった場合、申請は却下される場合もあります。その場合、改めてその修正の重要性を説明し直したり、味方に付いてくれる人(Mozillaの中の人)にコメントを求めたりという形で、説得・交渉を行う事になります。

まとめ

以上、Windows上での作業を前提とした、Firefoxへのパッチ提出の流れを解説しました。

「Firefoxのような大規模プロジェクト、しかもGitHubではない独自のやり方でソースコードや問題を管理している所にコントリビュートする」というのは、GitHub上でフィードバックした事がある人でも、心理的に高いハードルがあるかもしれません。しかし、根本的な部分ではそう大きな違いはなく、むしろ、Bugzillaのような高機能のバグトラッキングシステムやinboundのような規定は、GitHub上でのプロジェクト運営では「運用でカバー」されているものをシステムとしてきちんと体系化した物と言う事ができるでしょう。皆さんも必要以上に恐れずフィードバックしてみて下さい。

2018-07-03

IBus変換エンジンでネストしたメニューを正しく表示できるようにするには

はじめに

GNOME Shellには、ネストしたメニューを正しく展開できないという不具合があります。 今回はその問題への対処方法について紹介します。

問題の詳細

IBus変換エンジンのメニューは、IBusPropertyIBusPropList を組み合わせて実装します。 サンプルコードの抜粋を以下に示します。

IBusText *label = ibus_text_new_from_static_string("Menu");
IBusPropList *root = ibus_prop_list_new();
g_object_ref_sink(root);
IBusPropList *submenulist = ibus_prop_list_new();
IBusProperty *menu = ibus_property_new("InputMode",
                                       PROP_TYPE_MENU,
                                       label,
                                       NULL,
                                       NULL,
                                       TRUE,
                                       TRUE,
                                       PROP_STATE_UNCHECKED,
                                       submenulist);
g_object_ref_sink(menu);
ibus_prop_list_append(root, menu);

label = ibus_text_new_from_static_string("SubMenu");
IBusPropList *subsubmenulist = ibus_prop_list_new();
IBusProperty *submenu = ibus_property_new("SubMenuKey",
                                          PROP_TYPE_MENU,
                                          label,
                                          NULL,
                                          NULL,
                                          TRUE,
                                          TRUE,
                                          PROP_STATE_UNCHECKED,
                                          subsubmenulist);
g_object_ref_sink(submenu);
ibus_prop_list_append(submenulist, submenu);

label = ibus_text_new_from_static_string("SubSubMenu");
IBusProperty subsubmenu = ibus_property_new("SubSubMenuKey",
                                            PROP_TYPE_NORMAL,
                                            label,
                                            NULL,
                                            NULL,
                                            TRUE,
                                            TRUE,
                                            PROP_STATE_UNCHECKED,
                                            NULL);
g_object_ref_sink(subsubmenu);
ibus_prop_list_append(subsubmenulist, subsubmenu);

メニューが子のメニューを持つ場合には、該当するメニューは IBusPropList を保持する、というのが基本です。 上記の例だと menu の下に submenulist という IBusPropList を追加して、その下に IBusProperty である submenu を追加しています。 このようにすることでメニューの親子関係を表現できるというわけです。 孫にあたるメニューの追加も同様です。

では、ネストしたメニューを実装したIBus変換エンジンのメニューは実際にどのように表示されるでしょうか。

GNOME ShellとXfceそれぞれでみてみましょう。

GNOME Shellの場合

GNOME Shellの場合、SubMenu をクリックしてもその子階層に配置したはずの SubSubMenu は表示されません。 SubMenu が閉じられてしまうという挙動になります。

Xfceの場合

Xfceの場合、SubMenu をクリックしたらその子階層に配置した SubSubMenu も期待通りに表示されます。

したがって、3階層のメニューを実装した場合、GNOME Shellでは正常に機能しないということがわかります。

問題への対応について

ネストしたメニューが表示されないというこの挙動ですが、既知の問題でした。 しかし、報告から何年も経過しているものの、まだ修正されていません。 GNOME Shell自体の修正が必要なケースですが、たいていのIBus変換エンジンではそれほどネストが深いメニューを実装していないために大きな問題にはなっていないのかもしれません。

幸いにも、該当バグにパッチが投稿されていました。 最近のバージョンに合わせて多少手直しすることで、Ubuntu 18.04のGNOME Shellで問題が解決できることがわかっています。

そのため、以下のようにパッチを更新して追加のフィードバックをしておきました。

まとめ

今回は、IBusでネストしたメニューを正しく表示できないことに気づいてフィードバックしたときの知見を紹介しました。 まだアップストリームであるGNOME Shellにパッチが取り込まれていませんが、修正されればGNOME Shellでもネストしたメニューをきちんと表示できるようになるはずです。

つづき: 2018-07-06
2018-06-27

GNOME環境で作成したパスワード付きZIPが解凍できない時は

p7zipパッケージをシステムから取り除くと、 解凍できるZIPファイルが作れるようになるかもしれません。

こんにちは、クリアコードの藤本です。今回の記事では:

  1. GNOME標準のアーカイバでパスワード付きZIPファイルを作成したら、
  2. Windowsのエクスプローラやunzipコマンドで開けなかった。

という方向けに、この問題の原因と対策をお伝えしたいと思います。

問題の要点

GNOMEには標準のアーカイバとして「File Roller」というプログラムが付属しています。 普段意識して使うことは少ないかもしれないのですが、例えば、 Nautilusの「ファイルを圧縮する」メニューはこのプログラムが提供しており、 意外と多くの場面で利用されています。

今回取り上げる問題は、このプログラムでパスワード付きZIPファイルを作成すると、 他のプログラムで解凍できなくなることがある、というものです。 実際に、私の環境でFile Rollerを使ってパスワード付きZIPファイルを作成し、 unzipコマンドで解凍しようとすると、次のような警告が表示されます:

$ unzip  password.zip
Archive:  password.zip
   skipping: test.txt               need PK compat. v5.1 (can do v4.6)

また、このZIPファイルをWindows 10のエクスプローラで展開しようとすると、 例外が発生して処理が中断してしまいます。

予期しないエラーのため、ファイルをコピーできません。このエラーが再発する場合は、
エラーコードを利用して、この問題についてのヘルプを検索してください。

エラー 0x80004005: エラーを特定できません。
何が原因なのか?

この現象の本質的な原因は、File Rollerが「AES-128」でファイルを暗号化することにあります。

まず話の前提として、ZIPファイルの暗号化方式について簡単に整理します:

  1. もともと、ZIPには(PKZIP v1.0の時代から)単純なストリーム暗号が備え付けられており、 これが2018年現在も最もよく使われる暗号化方式となっています。

  2. しかし、この方式は暗号としては非常に弱く、 比較的簡単に突破できることが既に20年以上前から知られています。

  3. このため、「もっと強固な暗号化方式を導入して、セキュリティの向上を図ろう」という改良が、 いくつかのグループで進められており、その改良案の中でも現在最も有力なのが、 WinZipが2003年に導入したAESベースの暗号化仕様です。

  4. ただし「有力」とは言っても、他の実装の追従は極めて遅く、 公開から15年近く経った今でも、多くのZIPアーカイバはこの暗号化仕様をサポートしていません。

ここで、File Rollerに話を戻すと、 このプログラムは『7-Zipがインストールされている時は、AES-128を利用して暗号化する』 という実装になっています。システムに7-Zipが見つからない場合は、伝統的な暗号化方式が使われます。 File Rollerで生成したZIPファイルが、他のアーカイバで解凍できなくなったりする原因はここにあります。 要するに、実行時のシステムの状態によって、適用される暗号アルゴリズムがバックグラウンドで切り替わるのです。

実際に、先ほど解凍できなかったZIPアーカイブを検査してみると、 格納されているファイルがAES-128で暗号化されていることが確認できます:

$ 7z l -slt password.zip | grep Method
Method = AES-128 Store
暫定的な対応策

結論を先に述べると、File Rollerの暗号化方式を互換性のある旧方式に戻したい場合、 ユーザーには「7-Zipをアンインストールする」という選択肢しか現状はありません。 というのも、前節で解説した処理はソースに(暗号化アルゴリズムの選択含めて) ハードコードされており、設定やオプションで変えられる仕組みになっていないからです。

# Red Hat系なら `dnf remove p7zip`
$ sudo apt remove p7zip-full

参考までに、以下に該当するソースコードの箇所を示します:

もちろん、適切な環境があれば、 該当箇所を変更した独自ビルドを作ることで問題を迂回することもできます。 しかし、手元でコードをいじって回避するよりは、 アップストリームで根本から問題を解決したいものです。

根本的な解決に向けて

そこで私たちは、今回の問題についてGNOMEプロジェクトに修正パッチを投げています。

https://gitlab.gnome.org/GNOME/file-roller/merge_requests/1

ただし、このパッチがそのまま取り込まれることはさほど期待しておらず、 これを起点に議論を進めていきたい、というのが基本的な立場です (というのも、最終的な解決までに議論が必要な論点がいくつかあるためです)。 詳細はパッチに付けた説明をご参照ください。

もし読者の皆様の中で、「これは」という意見をお持ちの方がいらっしゃれば、 ぜひとも上のスレッドにコメントをお寄せください。 皆様のご意見をお待ちしています。

2018-06-13

Firefox 62で修正されたFirefox 61での後退バグに見る、不要なコードを削除する事の大切さ

一般的に、プログラムの継続的な開発においては「機能の追加」や「不具合の修正」が行われる事は多いですが、「機能の削除」が明示的に行われる事はそう多くないのではないでしょうか*1。この度、使われなくなっていた機能が残っていた事により意図しない所で不具合が発生し、機能を削除することで不具合が解消された事例がありましたので、使われなくなった機能を削除する事の意義を示す一時例としてご紹介いたします。

発生していた現象

現在のFirefoxでは、インストールするアドオンは必ずMozillaによる電子署名が施されていなくてはならず、未署名のファイルからはアドオンをインストールできないようになっています。ただ、それではアドオンの開発そのものができないため、開発者向けの機能であるabout:debuggingから、開発中のアドオンを「一時的なアドオン」として読み込んで動作させられるようになっています。

この機能について、Firefox 61で「条件によっては、アドオンを一時的なアドオンとして読み込めない」「条件によっては、一時的なアドオンの読み込みに非常に時間がかかる」という不具合が発生していましたが、Firefox 62で修正される事になりました*2

現象が起こり始めたきっかけと、原因の調査

開発中のアドオンを一時的なアドオンとして読み込めないという現象について、現象発生のタイミングを二分探索で絞り込むツールであるmozregressionを使って調査した所、1452827 - XPIInstall has a bunch of cruft that needs to be cleaned upでの変更が投入されて以降発生するようになっていた事が分かりました。

また、この現象が発生していた場面では、WSL*3で作成したシンボリックリンクがリポジトリ内に含まれている場合に、開発者用のコンソールにwinLastError: 1920という情報が出力されるという状況でした。これはWindowsが返すファイル関連のエラーコードのひとつであるERROR_CANT_ACCESS_FILEを意味する物で、Bugzilla上において、上記変更の中に含まれているファイルの情報を取得する処理がWSLのシンボリックリンクに対してこのエラーを報告している、という情報を頂く事ができました。

実際の修正

ファイルの情報を調べようとして何らかのエラーが発生するファイルというものは、WSLのシンボリックリンク以外にも存在し得ます。また、一般的に、規模が大きな変更は予想外の影響をもたらすリスクがあり、変更は可能な限り最小限に留める事が望ましいとされます。これらの理由から、当初は「ファイルの情報を取得しようとした時のエラーを適切にハンドルすることで、特殊なファイルがあっても問題が起こらないようにする」という方向でパッチを作成し提出しました。

しかしながら、このパッチはレビューの結果却下され、そもそもこの「ファイルの情報を取得する処理」自体が不要だからそれを削除する方がよいのではないかという指摘を受けました。そこで改めて調査したところ、以下の状況である事を確認できました。

  • この処理は、アドオンの総ファイルサイズを計算する過程で呼ばれている。
  • しかしながら、現行のFirefoxではアドオンのファイルサイズは画面上に表示される事が無く、また、ファイルサイズの情報が有効に使われる部分も存在していない。
    • 過去には使われていた機能のようだが、機能の改廃が進んだ結果、現在は「ファイルサイズの計算が正しいかどうか」を検証する自動テストの中で参照されるだけの機能になっていた。
    • 類似の情報として、自動更新を通じてダウンロードされたアドオンのインストールパッケージのファイルサイズという物もある。
      • こちらは現在も使われているが、今回問題となっている「アドオンの総ファイルサイズ」とは別の物である。
  • よって、アドオンの総ファイルサイズという情報自体が現在では無用となっている。

既にある機能や情報の削除は、その機能を使っている箇所が1つでも残っていれば不可能なため、影響範囲の調査は特に念入りに行う必要があります。今回の事例では、

  • Mozillaのスタッフの人から、使われていない機能を削除する方向での対応が望ましい旨のコメントが出ていた。
  • 実際に調査した限りでは、確かに目に見える部分や他の機能からは参照されていないという事の確認が取れた。

という2つの根拠があったため、思い切って、アドオンの総ファイルサイズの計算に関わるコードと、サイズ情報を参照している箇所*4を削除するという内容でパッチを再作成しました。その結果、パッチは無事に取り込まれ、Firefox 62ではこの問題が修正される事になりました。

また、このパッチが取り込まれた結果、「条件によって一時的なアドオンの読み込みに非常に時間がかかる」という別のBugにも影響が及んでいた事が後になって分かりました。こちらのBugは、開発中のアドオンのフォルダー配下にnode_modulesのようなフォルダーがあると*5、その配下の大量のファイルをスキャンするために時間がかかるようになってしまった、という物です。アドオンの総ファイルサイズの計算自体を行わなくした事により、棚ぼた的にこちらのBugも解消されたという状況でした。

ただ、実はその後、「WSLのシンボリックリンクのせいでエラーが発生してアドオンを読み込めない」という状況自体が今となってはほぼ発生しなくなっているという事も分かりました。具体的には、Bugの報告時にエラーの原因になっていたシンボリックリンクはWindows 10 Creators UpdateやWindows 10 Fall Creators UpdateのWSLで作成された物でしたが、その後Windows 10 April 2018 UpdateのWSLなどではNTFSの妥当なシンボリックリンクが作成されるようWSLが改良されたため、この問題の影響を受けるのは「古いWSLで(npm installを実行するなどして間接的に作成される場合も含めて)シンボリックリンクを作って、それをその後もずっと使い続けている場合」だけという事になっています。一般ユーザーに影響が及ばないアドオン開発者向けの機能であるという事に加え、プラットフォーム側の改善により今では問題自体が発生しなくなっている(新たにシンボリックリンクを作り直すだけでよい)という事も相まって、このパッチはFirefox 61には取り込まれないという判断がなされています。

まとめ

以上、Firefox 62で取り込まれたパッチを題材に、既に不要となっていた機能が問題を引き起こしていた事例についてご紹介しました。

Firefox 56およびそれ以前のバージョンのFirefoxにおいて使用できていた従来型アドオンは、今回削除されたコードのような「Firefox内部では既に使われなくなった機能」を使用している事が度々ありました。そのためFirefox全体として、アドオンが動作しなくなる事を警戒して古いコードを大量に抱え込まざるを得ない状態が長く続いていました。Firefox57での「従来型アドオン(XULアドオン)廃止」という大きな変化には、このような状態を是正するためという意味合いもあったと言えるでしょう。これを反面教師として、不要になった機能や実装はその都度速やかに削除してコードを簡潔に保っていくという事の重要さを実感していただければ幸いです。

*1 ただし、機能一式の刷新にあたって「新しい実装に持ち越されなかった機能」が結果的に「旧バージョンから削除された機能」として見える、という事はあります。

*2 一般ユーザーへの影響は小さいと判断された結果、Firefox 61への修正の反映は見送られています。

*3 Windows Subsystem for Linux

*4 大半は自動テスト内で、UI上に現れる物もFirefoxでは使われていないThunderbird用に残されたコードに1箇所あるだけでした。

*5 静的な文法チェックを行うためにeslintを使っている場合などに、このような状況が発生し得ます。

2018-06-07

Gecko Embedded ESR60

はじめに

これまでにも何度か紹介してきましたが、クリアコードではGecko(Firefox)を組み込み機器向けに移植する取り組みを行っています。

当プロジェクトでは移植コストを少しでも低減するために、Firefoxの延長サポート版(ESR)のみを対象としています。これまではESR45やESR52をベースにハードウェアアクセラレーションに対応させるための作業を行ってきました。 現在はESR60に対応し、そのバグを修正する作業を進めています。

今回は、この作業の現在のステータスを紹介します。詳細なビルド方法については、Gecko Embedded 次期ESR対応 を参照してください。

現在のステータス

現在はFirefox ESR60の開発を進めています。ビルドは通るようになり、ソフトウェアレンダリングでの描画もある程度安定して動作するようになっています。Firefox 60からはWayland対応のコードも本体に入っているため、ソフトウェアレンダリングであればほぼ無修正で動作させることができています。 また、60ESRには入りませんでしたが、当プロジェクトが作成したEGLおよびOpenMAX対応のパッチも無事Firefox本体に取り込まれています。

ESR52で実現出来ていたハードウェア対応の移植作業については、2018年5月30日現在、以下のような状況です。

  • レイヤーアクセラレーション: 移植済み(RZ/G1M、R-Car M3、Raspberry Pi3 Model Bで検証)
  • OpenMAX(H.264デコード): 移植済み(RZ/G1Mで検証)
  • WebGL: 移植済み(R-Car M3で動作)
  • WebRTC: レイヤーアクセラレーションとの組み合わせでは動作せず(調査中)
  • Canvas 2D Contextのアクセラレーション: e10sオフでは動作

また、ESR52ではなかった要素として、Rustで書かれたコードが追加されてきている点が挙げられます。細かく動作検証はできていませんが、少なくともStylo(Quantum CSS)は実機(Renesas RZ/G1M)で動作することを確認できています。

前回からの改善点は以下の通りです。

  • EGL有効化時に表示されるUIと操作するときに反応する座標がずれる不具合が解消した
  • UIのタブのドラッグ&ドロップが動作するようになった
  • コピー&ペーストが動作するようになった
  • WebGLがR-Car M3で動作することを確認

現状では、以下の制限があります。

  • 動画を再生&一旦停止し、別の動画を再生した時にサウンドデバイスが解放されず、音が出力されない
  • SoCのGPUがOpenGL ES 2.0のプロファイルを持ちrobustness拡張をサポートしない場合、WebGLのコンテキストが不完全となるか、コンテキスト作成に失敗する
  • Yocto 2.4ベースのBSPではStyloのビルドが確認できていない
  • Renesas RZ/G1MのPowerVR SGX 544MPを使用する場合、コンポジターでハードウェア支援を有効にするとウィンドウリサイズ時に高確率でSEGVすることがある
  • e10s有効化時にEGLを有効化するとContentプロセスがSEGVする

動作確認を行ったハードウェア

現時点ではRenesas RZ/G1M、R-Car M3、また、コミュニティサポートのレベルですが、StyloのビルドサポートなしでRaspberry Pi3 Model Bにも移植しました。

まとめ

GeckoEmbeddedプロジェクトのESR60の状況とビルド方法について紹介しました。ESR60対応がひと段落し、対象ボードを拡充する対応は少しづつ進んでいるものの、まだまだ手が足りていない状況です。興味を持たれた方は、ぜひ当プロジェクトに参加して頂ければ幸いです。

2018-05-30

2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|
タグ: