Electron のパッチ
Electron は、Chromium と Node.js という 2 つの主要な上流プロジェクトを基盤として構築されています。これらのプロジェクトそれぞれにも、多くの依存関係があります。Electron では、これらの依存関係を可能な限りそのまま使用しようとしますが、場合によっては、ユースケースに合うように上流の依存関係にパッチを適用しなければ目標を達成できないことがあります。
パッチの正当性
Electron のすべてのパッチは、メンテナンスの負担となります。上流のコードが変更されると、パッチが壊れる可能性があり、パッチの競合やコンパイルエラーが発生しない場合もあります。パッチセットを最新の状態に保ち、効果的に機能させるために、継続的な努力が必要です。そのため、パッチの数を最小限に抑えるよう努めています。その目的を達成するために、すべてのパッチは、その存在理由をコミットメッセージで説明する必要があります。その理由は、次のいずれかである必要があります。
- パッチは一時的なものであり、上流にコミットされる予定であるか、既にコミットされているか、または最終的に削除される予定です。可能な場合は、上流の PR またはコードレビューへのリンク、または後でパッチが必要かどうかを確認する手順を含めます。
- パッチにより、Electron 環境でコードをコンパイルできますが、Electron 固有のものであるため(例:Chrome の `Profile` への参照をパッチで削除する)、上流に送ることができません。パッチなしで変更を実装できない理由(例:サブクラス化またはコードのコピーによる)について説明します。
- パッチは、上流と根本的に互換性のない Electron 固有の機能変更を行います。
一般的に、Electron が連携する上流プロジェクトはすべてフレンドリーな人たちであり、問題のコードを Electron と上流プロジェクトの両方で互換性を持つようにリファクタリングすることを喜んで受け入れることがよくあります。(例:Chromium のこの変更は、同じことを行うパッチを削除することを可能にしたか、Node のこの変更は、Node ではノーオペレーションでしたが、Electron のバグを修正しました。)**変更は可能な限り上流に送るべきであり、無期限のパッチは避けるべきです。**
パッチシステム
上流プロジェクトにパッチを適用するしかないという不幸な状況に陥った場合は、Electron でパッチを管理する方法を知る必要があります。
Electron の上流プロジェクトへのすべてのパッチは、`patches/` ディレクトリに含まれています。`patches/` の各サブディレクトリには、いくつかのパッチファイルと、パッチを適用する順序をリストした `.patches` ファイルが含まれています。これらのファイルは、チェックアウト後に上流プロジェクトに適用される一連の git コミットを構成していると考えることができます。
patches
├── config.json <-- this describes which patchset directory is applied to what project
├── chromium
│ ├── .patches
│ ├── accelerator.patch
│ ├── add_contentgpuclient_precreatemessageloop_callback.patch
│ ⋮
├── node
│ ├── .patches
│ ├── add_openssl_is_boringssl_guard_to_oaep_hash_check.patch
│ ├── build_add_gn_build_files.patch
│ ⋮
⋮
これらのパッチセットの管理を支援するために、`git-import-patches` と `git-export-patches` という 2 つのツールを提供しています。`git-import-patches` は、各パッチを正しい順序で適用し、それぞれにコミットを作成することにより、一連のパッチファイルを git リポジトリにインポートします。`git-export-patches` はその逆を行います。リポジトリ内の一連の git コミットを、ディレクトリ内のファイルセットとそれに付随する `.patches` ファイルにエクスポートします。
補足:適用されたパッチの順序を維持するために、`001-` のような番号を各ファイルの先頭に付けるのではなく、`.patches` ファイルを使用する理由は、パッチの順序に関連する競合を減らすためです。これは、2 つの PR がどちらも同じ番号付けでシリーズの最後にパッチを追加し、両方ともマージされて重複した識別子が発生する状況を防ぎ、また、シリーズの中央でパッチを追加または削除した場合の変更量も削減します。
使用方法
新しいパッチの追加
$ cd src/third_party/electron_node
$ vim some/code/file.cc
$ git commit
$ ../../electron/script/git-export-patches -o ../../electron/patches/node
**注記**:`git-export-patches` は、コミットされていないファイルをすべて無視するため、変更をエクスポートする場合はコミットを作成する必要があります。コミットメッセージの件名行を使用してパッチファイル名が導出され、コミットメッセージの本文にはパッチの存在理由を含める必要があります。
パッチを再エクスポートすると、関連のないパッチの shasum が変更される場合があります。これは一般的には無害であり、無視できます(ただし、それらの変更を PR に追加してください。他のユーザーに表示されなくなります)。
既存のパッチの編集
$ cd src/v8
$ vim some/code/file.cc
$ git log
# Find the commit sha of the patch you want to edit.
$ git commit --fixup [COMMIT_SHA]
$ git rebase --autosquash -i [COMMIT_SHA]^
$ ../electron/script/git-export-patches -o ../electron/patches/v8
パッチの削除
$ vim src/electron/patches/node/.patches
# Delete the line with the name of the patch you want to remove
$ cd src/third_party/electron_node
$ git reset --hard refs/patches/upstream-head
$ ../../electron/script/git-import-patches ../../electron/patches/node
$ ../../electron/script/git-export-patches -o ../../electron/patches/node
`git-import-patches` は、実行時に `HEAD` であったコミットを `refs/patches/upstream-head` としてマークすることに注意してください。これにより、Electron パッチからのコミット(`refs/patches/upstream-head` の後のコミット)と上流のコミット(`refs/patches/upstream-head` の前のコミット)を区別できます。
競合の解決
上流の依存関係を更新すると、パッチがクリーンに適用されない場合があります。多くの場合、3 方マージを使用して git によって競合を自動的に解決できます。`-3` 引数を渡すことで、`git-import-patches` に 3 方マージアルゴリズムを使用するように指示できます。
$ cd src/third_party/electron_node
# If the patch application failed midway through, you can reset it with:
$ git am --abort
# And then retry with 3-way merge:
$ ../../electron/script/git-import-patches -3 ../../electron/patches/node
`git-import-patches -3` が自動的に解決できないマージの競合に遭遇した場合、一時停止して手動で競合を解決できます。競合を解決したら、解決済みのファイルを `git add` し、`git am --continue` を実行して残りのパッチの適用を続けます。