跳至主要內容

Electron 中的修補程式

Electron 建基於兩個主要的上游專案:Chromium 和 Node.js。這些專案各自也有一些依賴項。我們盡力完全依照它們的現狀來使用這些依賴項,但有時候,如果沒有修補這些上游依賴項以符合我們的使用案例,我們就無法達成我們的目標。

修補程式的理由

Electron 中的每一個修補程式都是一個維護負擔。當上游程式碼變更時,修補程式可能會失效—有時甚至不會有修補程式衝突或編譯錯誤。保持我們的修補程式集更新且有效是一個持續的努力。因此,我們力求將我們的修補程式數量保持在最低限度。為此,每個修補程式都必須在其提交訊息中描述其存在的原因。該原因必須是以下之一:

  1. 此修補程式是暫時的,並且旨在(或已經)提交到上游,或最終移除。如果有的話,請包含一個指向上游 PR 或程式碼審查的連結,或一個用於驗證此修補程式是否在稍後日期仍然需要的程序。
  2. 此修補程式允許程式碼在 Electron 環境中編譯,但由於它是 Electron 特有的,因此無法上游化(例如,修補掉對 Chrome 的 Profile 的引用)。請包含關於為什麼在沒有修補程式的情況下無法實現變更的推理(例如,透過子類化或複製程式碼)。
  3. 此修補程式在功能上進行了 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-patchesgit-export-patchesgit-import-patches 會透過按照正確的順序套用每個修補程式並為每個修補程式建立一個提交,將一組修補程式檔案匯入 git 儲存庫中。git-export-patches 執行相反的操作;它將儲存庫中的一系列 git 提交匯出到目錄中的一組檔案和一個隨附的 .patches 檔案中。

附註:我們使用 .patches 檔案來維護已套用修補程式的順序,而不是在每個檔案前面加上一個數字,例如 001-,原因是它可以減少與修補程式順序相關的衝突。它可以防止兩個 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

請注意,^ 符號可能會在 Windows 上造成問題。解決方法是引用它 "[COMMIT_SHA]^" 或避免它 [COMMIT_SHA]~1

移除修補程式

$ 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 之前的提交)。

解決衝突

當更新上游依賴項時,修補程式可能無法順利套用。通常,衝突可以由 git 透過 3 向合併自動解決。您可以透過傳遞 -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 繼續套用剩餘的修補程式。