Bazel Lockfile

回報問題 查看原始碼

Bazel 中的 Lockfile 功能可以記錄專案所需的特定版本或依附元件,或是軟體程式庫或套件的依附元件。為達到這個目標,系統會儲存模組解析度和擴充功能評估結果。Lockfile 能夠推動可重現的建構,以確保一致的開發環境。此外,在專案依附元件沒有變更時,Bazel 也會允許 Bazel 略過解析程序,藉此提升建構效率。此外,Lockfile 會防止外部程式庫發生非預期的更新或破壞性變更,從而降低出現錯誤的風險,進而改善穩定性。

產生鎖定檔案

系統會在工作區根目錄下建立名為 MODULE.bazel.lock 的 Lock 檔案。會在建構程序中建立或更新,特別是在模組解析度和擴充功能評估後。Lockfile 會擷取專案目前的狀態,包括 MODULE 檔案、旗標、覆寫值和其他相關資訊。重要的是,這個類別僅包含目前建構作業中包含的依附元件。

如果專案發生變更,且影響其依附元件,Lockfile 會自動更新以反映新狀態。這可確保 Lock 檔案能專注於目前版本所需的特定依附元件組合,以準確呈現專案已解析依附元件。

鎖定檔案使用

如有需要,您可以使用標記 --lockfile_mode 控管 Lock 檔案,以便在專案狀態與鎖定檔案不同時自訂 Bazel 的行為。可用的模式如下:

  • update (預設):如果專案狀態與 Lockfile 相符,系統會立即從 Lockfile 傳回解析結果。否則系統會執行解析,並更新 Lockfile 以反映目前狀態。
  • error:如果專案狀態與 Lockfile 相符,就會從 Lockfile 傳回解析度結果。否則,Bazel 會擲回錯誤,指出專案與 Lockfile 之間的差異。如要確保專案的依附元件維持不變,並將任何差異視為錯誤,這個模式就特別實用。
  • off:完全未檢查鎖定檔案。

鎖定檔案的優點

這個 Lockfile 的優點如下:

  • 可重現的建構內容。鎖定檔案會擷取軟體程式庫的特定版本或依附元件,確保其版本能在不同的環境和一段時間內重現。開發人員在建構專案時,可以依賴一致且可預測的結果。

  • 有效略過解析度如果專案依附元件自上次建構後沒有任何變更,Lockfile 即可略過解析程序。這可大幅提升建構效率,特別是在解決方案可能相當耗時的情況下。

  • 穩定性與風險降低。並能防止外部程式庫發生非預期的更新或破壞性變更,協助維持穩定性。將依附元件鎖定在特定版本後,就能降低因不相容或未經測試更新而產生錯誤的風險。

鎖定檔案內容

Lockfile 內含所有必要資訊,可判斷專案狀態是否已變更。這也包括以目前狀態建構專案的結果。Lockfile 由兩個主要部分組成:

  1. 模組解析度的輸入內容,例如 moduleFileHashflagslocalOverrideHashes,以及解析度的輸出內容 (moduleDepGraph)。
  2. 針對每個模組擴充功能,Lockfile 包含影響它的輸入內容 (以 transitiveDigest 表示),以及執行該擴充功能的輸出內容 (稱為 generatedRepoSpecs)

以下範例說明 Lockfile 的結構,以及每個區段的說明:

{
  "lockFileVersion": 1,
  "moduleFileHash": "b0f47b98a67ee15f9.......8dff8721c66b721e370",
  "flags": {
    "cmdRegistries": [
      "https://bcr.bazel.build/"
    ],
    "cmdModuleOverrides": {},
    "allowedYankedVersions": [],
    "envVarAllowedYankedVersions": "",
    "ignoreDevDependency": false,
    "directDependenciesMode": "WARNING",
    "compatibilityMode": "ERROR"
  },
  "localOverrideHashes": {
    "bazel_tools": "b5ae1fa37632140aff8.......15c6fe84a1231d6af9"
  },
  "moduleDepGraph": {
    "<root>": {
      "name": "",
      "version": "",
      "executionPlatformsToRegister": [],
      "toolchainsToRegister": [],
      "extensionUsages": [
        {
          "extensionBzlFile": "extension.bzl",
          "extensionName": "lockfile_ext"
        }
      ],
      ...
    }
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "general": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "transitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

模組檔案雜湊

moduleFileHash 代表 MODULE.bazel 檔案內容的雜湊。如果這個檔案發生任何變更,雜湊值會有所不同。

旗幟

Flags 物件會儲存可能影響解析度結果的所有標記。

本機覆寫雜湊

如果根模組包含 local_path_overrides,本節會將 MODULE.bazel 檔案的雜湊儲存在本機存放區中。可讓您追蹤這項依附元件的變更。

模組依附元件圖表

moduleDepGraph 代表使用上述輸入進行解決程序的結果。這會形成執行專案所需的所有模組的依附元件圖表。

模組擴充功能

moduleExtensions 區段是地圖,只包含目前叫用或先前叫用的擴充功能,但不包含任何不再使用的擴充功能。換句話說,如果依附元件圖表不再使用某個擴充功能,系統就會將其從 moduleExtensions 地圖中移除。

如果某個擴充功能與作業系統或架構類型無關,則這個部分只會提供單一「一般」項目。否則,我們會納入多個項目,並以 OS 和/或架構命名,每個項目都會對應至根據這些具體評估擴充功能的結果。

擴充功能對應中的每個項目都對應一種使用的副檔名,並以包含的檔案和名稱來識別。每個項目的對應值都包含與該擴充功能相關聯的相關資訊:

  1. transitiveDigest 是擴充功能實作及其遞移 .bzl 檔案的摘要。
  2. 使用目前輸入內容執行該擴充功能的結果 generatedRepoSpecs

另一個可能影響擴充功能結果的因素是其使用方式。雖然未儲存在鎖定檔案中,但當您比較擴充功能目前狀態與鎖定檔案中的擴充功能時,會將這些使用情形納入考量。

最佳做法

為了充分發揮鎖定檔案功能的優勢,請考慮下列最佳做法:

  • 定期更新 Lockfile,以反映專案依附元件或設定的變更。這可確保後續的建構作業都是以最新且正確的一組依附元件為基礎。

  • 將鎖定檔案納入版本控制中,以促進協同合作,並確保所有團隊成員都存取同一個鎖定檔案,在專案中推動一致的開發環境。

  • 使用 bazelisk 執行 Bazel,並在版本控制中納入 .bazelversion 檔案,指定與 Lock 檔案對應的 Bazel 版本。由於 Bazel 本身是建構作業的依附元件,因此 Lockfile 專屬於 Bazel 版本,而且會在回溯相容 Bazel 版本之間變更。使用 bazelisk 可確保所有開發人員使用的 Bazel 版本與 Lockfile 相符。

只要按照這些最佳做法操作,即可有效使用 Bazel 中的 Lockfile 功能,實現更有效、可靠且協作的軟體開發工作流程。