存放區規則

回報問題 查看原始碼 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

本頁面將說明如何定義存放區規則,並提供詳細範例。

外部存放區是目錄樹狀結構,其中包含可在 Bazel 建構中使用的來源檔案,這些檔案會在需要時透過執行對應的 repo 規則產生。您可以透過多種方式定義 repo,但最終,每個 repo 都是透過叫用 repo 規則來定義,就像建構目標是透過叫用建構規則來定義一樣。這些檔案可用於依附第三方程式庫 (例如 Maven 封裝的程式庫),但也可以用於產生特定於 Bazel 執行主機的 BUILD 檔案。

存放區規則定義

.bzl 檔案中,使用 repository_rule 函式定義新的存放區規則,並儲存在全域變數中。定義了存放區規則後,即可將其做為函式叫用,以便定義存放區。這項叫用通常會在模組擴充功能實作函式中執行。

存放區規則定義的兩個主要元件是屬性結構定義和實作函式。屬性結構定義會決定傳遞至 repo 規則叫用作業的屬性名稱和類型,而實作函式會在需要擷取 repo 時執行。

屬性

屬性是傳遞至 repo 規則叫用作業的引數。當您透過呼叫 repository_rule 定義 repo 規則時,Repo 規則接受的屬性結構定義會使用 attrs 引數指定。將 urlsha256 屬性定義為字串的範例:

http_archive = repository_rule(
    implementation=_impl,
    attrs={
        "url": attr.string(mandatory=True),
        "sha256": attr.string(mandatory=True),
    }
)

如要在實作函式中存取屬性,請使用 repository_ctx.attr.<attribute_name>

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

所有 repository_rule 都具有隱含定義的屬性 name。這是一個字串屬性,其行為有點神奇:當您將其指定為 repo 規則叫用作業的輸入內容時,它會採用明顯的 repo 名稱;但如果使用 repository_ctx.attr.name 從 repo 規則的實作函式讀取,則會傳回正式的 repo 名稱。

實作函式

每個 repo 規則都需要 implementation 函式。這項元素包含規則的實際邏輯,且會嚴格地在載入階段執行。

這個函式只有一個輸入參數 repository_ctx。這個函式會傳回 None,表示在指定參數下可重現規則,或是傳回含有該規則一組參數的字典,可將該規則轉換為可重現的規則,產生相同的 repo。舉例來說,如果規則用於追蹤 Git 存放區,則會傳回特定提交 ID,而非原先指定的浮動分支版本。

輸入參數 repository_ctx 可用於存取屬性值和非密封函式 (尋找二進位檔、執行二進位檔、在存放區中建立檔案或從網際網路下載檔案)。詳情請參閱 API 說明文件。範例:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

實作函式何時執行?

當 Bazel 需要該存放區的目標時,就會執行存放區規則的實作函式,例如當其他目標 (在其他存放區) 依附於該存放區,或是在指令列中提及該存放區時。實作函式接著會在檔案系統中建立存放區。這就是所謂的「擷取」存放區。

與一般目標相比,如果某些變更會導致存放區發生不同的變更,您不一定必須重新擷取存放區。這是因為 Bazel 無法偵測變更,或是會導致每次建構作業產生過多額外負擔 (例如從網路擷取的內容)。因此,只有在下列其中一個項目發生變更時,系統才會重新擷取存放區:

  • 傳送至 repo 規則叫用作業的屬性。
  • 包含存放區規則實作的 Starlark 程式碼。
  • 傳遞至 repository_ctxgetenv() 方法,或使用 repository_ruleenviron 屬性宣告的任何環境變數值。您可以使用 --repo_env 旗標,在指令列上硬連線這些環境變數的值。
  • 在 repo 規則的實作函式中,watch的存在、內容和類型。
    • repository_ctx 的其他方法 (含有 watch 參數),例如 read()execute()extract(),也可能會導致路徑受到監控。
    • 同樣地,repository_ctx.watch_treepath.readdir 也可能會以其他方式監控路徑。
  • 執行 bazel fetch --force 時。

repository_rule 有兩個參數可控制重新擷取存放區的時間:

  • 如果已設定 configure 旗標,系統會在 bazel fetch --force --configure 上重新擷取存放區 (不會重新擷取非 configure 存放區)。
  • 如果設定了 local 標記,則除了上述情況之外,系統也會在 Bazel 伺服器重新啟動時重新擷取存放區。

強制重新擷取外部存放區

有時,外部存放區可能會在定義或依附元件未變更的情況下過時。舉例來說,存放區擷取來源可能會追蹤第三方存放區的特定分支,而該分支會提供新的提交。在這種情況下,您可以呼叫 bazel fetch --force --all,要求 Bazel 無條件重新擷取所有外部存放區。

此外,部分存放區規則會檢查本機電腦,如果本機電腦已升級,則可能會過時。您可以要求 Bazel 只重新擷取 repository_rule 定義設有 configure 屬性集的那些外部存放區,請使用 bazel fetch --force --configure

範例

  • C++ 自動設定工具鍊:使用存放區規則,透過查看本機 C++ 編譯器、環境和 C++ 編譯器支援的標記,自動為 Bazel 建立 C++ 設定檔。

  • Go 存放區會使用多個 repository_rule 定義使用 Go 規則所需的依附元件清單。

  • rules_jvm_external 預設會建立名為 @maven 的外部存放區,為傳遞依附元件樹狀結構中的每個 Maven 構件產生建構目標。