本頁面說明如何定義存放區規則,並提供範例以瞭解更多詳細資料。
外部存放區是目錄樹狀結構,內含可用於 Bazel 建構作業的來源檔案,這些檔案是透過執行對應的存放區規則,依需求產生。定義存放區的方式有很多種,但最終每個存放區都是透過叫用存放區規則來定義,就像建構目標是透過叫用建構規則來定義一樣。這些檔案可用於依附第三方程式庫 (例如 Maven 封裝的程式庫),也能產生 Bazel 執行所在主機專用的 BUILD
檔案。
存放區規則定義
在 .bzl
檔案中,使用 repository_rule 函式定義新的存放區規則,並將其儲存在全域變數中。定義存放區規則後,即可做為函式叫用,以定義存放區。這項呼叫通常是從模組擴充功能實作函式內部執行。
存放區規則定義的兩大元件是屬性結構定義和實作函式。屬性結構定義傳遞至存放區規則調用的屬性名稱和類型,且當存放區需要擷取時,實作函式就會執行。
屬性
屬性是傳遞至 repo 規則調用的引數。使用 repository_rule
呼叫定義存放區規則時,可使用 attrs
引數指定存放區規則接受的屬性結構定義。以下範例會將 url
和 sha256
屬性定義為字串:
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
屬性。這是字串屬性,行為有點神奇:指定為存放區規則調用的輸入內容時,會採用明顯的存放區名稱;但使用 repository_ctx.attr.name
從存放區規則的實作函式讀取時,會傳回正式存放區名稱。
實作函式
每個 repo 規則都需要 implementation
函式。其中包含規則的實際邏輯,且嚴格在載入階段執行。
這個函式只有一個輸入參數,也就是 repository_ctx
。函式會傳回 None
,表示規則可根據指定參數重現,或是傳回含有該規則參數組合的字典,將規則轉換為可重現的規則,產生相同的存放區。舉例來說,如果規則追蹤的是 Git 存放區,這表示系統會傳回特定提交 ID,而不是原本指定的浮動分支。
輸入參數 repository_ctx
可用於存取屬性值,以及非密封函式 (尋找二進位檔、執行二進位檔、在存放區中建立檔案,或從網際網路下載檔案)。詳情請參閱 API 文件。範例:
def _impl(repository_ctx):
repository_ctx.symlink(repository_ctx.attr.path, "")
local_repository = repository_rule(
implementation=_impl,
...)
導入函式何時執行?
當 Bazel 需要該存放區的目標時,就會執行存放區規則的實作函式,例如另一個目標 (位於另一個存放區) 依附於該目標,或該目標在指令列中提及時。實作函式接著應在檔案系統中建立存放區。這稱為「擷取」存放區。
與一般目標不同,當導致存放區不同的項目發生變化時,存放區不一定會重新擷取。這是因為 Bazel 無法偵測變更,或每次建構都會造成過多負擔 (例如從網路擷取的項目)。因此,只有在下列其中一項變更時,系統才會重新擷取存放區:
- 傳遞至存放區規則調用的屬性。
- 包含存放區規則實作內容的 Starlark 程式碼。
- 傳遞至
repository_ctx
的getenv()
方法或以repository_rule
的environ
屬性宣告的任何環境變數值。您可以使用--repo_env
旗標,在指令列中硬式連線這些環境變數的值。 - 實作存放區規則的實作函式中,任何路徑的存在性、內容和類型。
watch
repository_ctx
的其他特定方法 (含watch
參數),例如read()
、execute()
和extract()
,也可能導致路徑受到監控。- 同樣地,
repository_ctx.watch_tree
和path.readdir
可能會導致以其他方式監控路徑。
- 執行
bazel fetch --force
時。
repository_rule
有兩個參數可控制何時重新擷取存放區:
- 如果設定
configure
旗標,系統會在bazel fetch --force --configure
重新擷取存放區 (不會重新擷取非configure
存放區)。 - 如果設定
local
標記,除了上述情況外,當 Bazel 伺服器重新啟動時,系統也會重新擷取存放區。
強制重新擷取外部存放區
有時,外部存放區可能會過時,但其定義或依附元件並未變更。舉例來說,擷取來源的存放區可能會追蹤第三方存放區的特定分支,而該分支上提供新的提交內容。在這種情況下,您可以呼叫 bazel fetch --force --all
,要求 bazel 無條件重新擷取所有外部存放區。
此外,部分 repo 規則會檢查本機,如果本機已升級,這些規則可能會過時。您可以在這裡要求 Bazel 只重新擷取定義設有 configure
屬性的外部存放區 (repository_rule
),請使用 bazel fetch --force
--configure
。
範例
C++ 自動設定工具鍊:這個工具會使用 repo 規則,尋找本機 C++ 編譯器、環境和 C++ 編譯器支援的標記,自動為 Bazel 建立 C++ 設定檔。
Go 存放區會使用多個
repository_rule
定義使用 Go 規則所需的依附元件清單。rules_jvm_external 預設會建立名為
@maven
的外部存放區,為遞移依附元件樹狀結構中的每個 Maven 構件產生建構目標。