Bazel 的鎖定檔案功能可記錄專案所需軟體程式庫或套件的特定版本或依附元件。方法是儲存模組解析和擴充功能評估的結果。鎖定檔案可促進可重現的建構作業,確保開發環境一致。此外,它還可讓 Bazel 略過解析程序中不受專案依附元件變更影響的部分,進而提升建構效率。此外, Lockfile 可防止外部程式庫發生非預期更新或破壞性變更,從而提高穩定性,降低引入錯誤的風險。
產生鎖定檔案
這個 Lockfile 會在工作區根目錄下產生,名為 MODULE.bazel.lock
。這項資訊會在建構程序期間建立或更新,特別是在模組解析和擴充功能評估之後。重要的是,其中只包含目前版本叫用中包含的依附元件。
當專案發生變更,並影響其依附元件時,系統會自動更新鎖定檔案,以反映新的狀態。這麼做可確保鎖定檔案持續專注於目前版本所需的特定依附元件組合,並準確呈現專案已解析的依附元件。
鎖定檔案用途
鎖定檔案可透過標記 --lockfile_mode
進行控制,在專案狀態與鎖定檔案不同時,可自訂 Bazel 的行為。可用的模式如下:
update
(預設):使用鎖定檔案中的資訊,略過已知登錄檔的下載作業,並避免重新評估結果仍為最新狀態的擴充功能。如果缺少資訊,系統會將資訊新增至鎖定檔案。在這個模式中,Bazel 也會避免針對未變更的依附元件,重新整理可變更的資訊 (例如已撤銷的版本)。refresh
:與update
類似,但在切換至此模式時,以及在這個模式下大約每小時,變更資訊一律會重新整理。error
:類似update
,但如果缺少任何資訊或資訊過時,Bazel 就會失敗並顯示錯誤。這個模式絕不會在解析期間變更鎖定檔案或執行網路要求。標示為reproducible
的模組擴充功能仍可能執行網路要求,但預期會一律產生相同結果。off
:系統未檢查或更新鎖定檔案。
鎖定檔案的優點
Lockfile 提供多項優點,且可多種運用方式:
可重現的建構作業:鎖定檔會擷取軟體程式庫的特定版本或依附元件,確保建構作業可在不同環境中重現,並且隨時間推移。開發人員在建構專案時,可以依賴一致且可預測的結果。
快速增加解析度。鎖定檔可讓 Bazel 避免下載先前建構中已使用的登錄檔案。這可大幅改善建構效率,特別是在解析度可能費時。
穩定性和風險降低。鎖定檔案可防止外部程式庫發生意外更新或破壞性變更,進而維持穩定性。將依附元件鎖定至特定版本,可降低因不相容或未經測試的更新而引入錯誤的風險。
鎖定檔案內容
鎖定檔案包含判斷專案狀態是否已變更所需的所有必要資訊。並包含在目前狀態下建構專案的結果。鎖定檔案包含兩個主要部分:
- 模組解析輸入內容的所有遠端檔案雜湊值。
- 對於每個模組擴充功能,鎖定檔案都會納入影響該擴充功能的輸入內容,以
bzlTransitiveDigest
、usagesDigest
和其他欄位表示,以及執行該擴充功能的輸出內容,稱為generatedRepoSpecs
以下範例說明瞭鎖定檔案的結構,以及各個部分的說明:
{
"lockFileVersion": 10,
"registryFileHashes": {
"https://bcr.bazel.build/bazel_registry.json": "8a28e4af...5d5b3497",
"https://bcr.bazel.build/modules/foo/1.0/MODULE.bazel": "7cd0312e...5c96ace2",
"https://bcr.bazel.build/modules/foo/2.0/MODULE.bazel": "70390338... 9fc57589",
"https://bcr.bazel.build/modules/foo/2.0/source.json": "7e3a9adf...170d94ad",
"https://registry.mycorp.com/modules/foo/1.0/MODULE.bazel": "not found",
...
},
"selectedYankedVersions": {
"foo@2.0": "Yanked for demo purposes"
},
"moduleExtensions": {
"//:extension.bzl%lockfile_ext": {
"general": {
"bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
"usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
}
},
"//:extension.bzl%lockfile_ext2": {
"os:macos": {
"bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
"usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
},
"os:linux": {
"bzlTransitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
"usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
...,
"generatedRepoSpecs": {
"hello": {
"bzlFile": "@@//:extension.bzl",
...
}
}
}
}
}
}
登錄檔雜湊
registryFileHashes
部分包含模組解析期間存取的遠端登錄資料庫中所有檔案的雜湊值。由於解析演算法在提供相同輸入內容並對所有遠端輸入內容進行雜湊時,可完全確定結果,因此可確保完全可重現的解析結果,同時避免在鎖定檔案中重複使用過多遠端資訊。請注意,當特定登錄不含特定模組,但優先順序較低的登錄含有該模組時,也需要記錄這項資訊 (請參閱範例中的「not found」項目)。這項本質可變動的資訊可透過 bazel mod deps --lockfile_mode=refresh
更新。
Bazel 會使用鎖定檔案中的雜湊值,在下載之前查詢存放區快取中的登錄檔案,藉此加快後續的解析作業。
已選取的已撤銷版本
selectedYankedVersions
區段包含模組解析所選取的模組版本。由於這通常會在嘗試建構時產生錯誤,因此只有在透過 --allow_yanked_versions
或 BZLMOD_ALLOW_YANKED_VERSIONS
明確允許的變形版本時,這個區段才不會空白。
這個欄位是必要的,因為與模組檔案相比,已取代版本資訊本質上是可變動的,因此無法由雜湊參照。您可以透過 bazel mod deps --lockfile_mode=refresh
更新這項資訊。
模組擴充功能
moduleExtensions
區段是一個地圖,只包含目前叫用或先前叫用所用的擴充功能,並排除不再使用的擴充功能。換句話說,如果依附元件圖表中不再使用某個擴充功能,就會從 moduleExtensions
地圖中移除。
如果擴充功能與作業系統或架構類型無關,本節只會顯示單一「一般」項目。否則,系統會納入多個項目,並以作業系統、架構或兩者命名,每個項目都會對應到針對這些特定項目評估擴充功能的結果。
擴充功能對應中的每個項目都會對應至使用的擴充功能,並以含有檔案和名稱識別。每個項目的對應值都包含與該擴充功能相關的相關資訊:
bzlTransitiveDigest
是擴充功能實作項目的摘要,以及由擴充功能間接載入的 .bzl 檔案。usagesDigest
是依附元件圖表中擴充功能的「用途」摘要,其中包含所有標記。- 其他未指定的欄位,可追蹤擴充功能的其他輸入內容,例如所讀取檔案或目錄的內容,或是所使用的環境變數。
generatedRepoSpecs
會使用目前的輸入內容將擴充功能建立的存放區進行編碼。- 選用的
moduleExtensionMetadata
欄位包含擴充功能提供的中繼資料,例如是否應透過根模組透過use_repo
匯入擴充功能所建立的特定存放區。這項資訊可供bazel mod tidy
指令使用。
模組擴充功能可以使用 reproducible = True
設定傳回中繼資料,選擇不納入鎖定檔案。如此一來,就能保證在輸入相同資料的情況下,一律都會建立相同的存放區。
最佳做法
如要充分運用鎖定檔案功能的優點,請參考下列最佳做法:
定期更新鎖定檔案,反映專案依附元件或設定的異動。這麼做可確保後續建構作業以最新且正確的依附元件為基礎。如要一次鎖定所有擴充功能,請執行
bazel mod deps --lockfile_mode=update
。在版本控制中加入鎖定檔案,以利協同合作,並確保所有團隊成員都能存取相同的鎖定檔案,促進專案中一致的開發環境。
請使用
bazelisk
執行 Bazel,並在版本管控中加入.bazelversion
檔案,指定與鎖定檔案對應的 Bazel 版本。由於 Bazel 本身是建構作業的依附元件,因此鎖定檔案會依 Bazel 版本而異,即使在向下相容的 Bazel 版本之間,也會有所變動。使用bazelisk
可確保所有開發人員都使用與 Lockfile 相符的 Bazel 版本。
只要遵循這些最佳做法,就能有效運用 Bazel 的鎖定檔案功能,打造更有效率、可靠且可協作的軟體開發工作流程。
合併衝突
鎖定檔案格式旨在盡量減少合併衝突,但仍可能發生。
自動解析
Bazel 提供自訂的 git 合併驅動程式,可協助自動解決這些衝突。
將這行程式碼新增至 Git 存放區根目錄中的 .gitattributes
檔案,即可設定驅動程式:
# A custom merge driver for the Bazel lockfile.
# https://bazel.build/external/lockfile#automatic-resolution
MODULE.bazel.lock merge=bazel-lockfile-merge
接著,每位想要使用驅動程式的開發人員都必須按照下列步驟註冊一次:
- 安裝 jq (1.5 以上版本)。
- 執行下列指令:
jq_script=$(curl https://raw.githubusercontent.com/bazelbuild/bazel/master/scripts/bazel-lockfile-merge.jq)
printf '%s\n' "${jq_script}" | less # to optionally inspect the jq script
git config --global merge.bazel-lockfile-merge.name "Merge driver for the Bazel lockfile (MODULE.bazel.lock)"
git config --global merge.bazel-lockfile-merge.driver "jq -s '${jq_script}' -- %O %A %B > %A.jq_tmp && mv %A.jq_tmp %A"
手動解決
只要保留衝突兩邊的所有項目,即可安全解決 registryFileHashes
和 selectedYankedVersions
欄位中的簡單合併衝突。
請勿手動解決其他類型的合併衝突。請改採以下做法:
- 透過
git reset MODULE.bazel.lock && git checkout MODULE.bazel.lock
還原鎖定檔案的先前狀態。 - 解決
MODULE.bazel
檔案中的任何衝突。 - 執行
bazel mod deps
更新鎖定檔案。