簡體   English   中英

如何在不使用相對路徑的情況下從另一個規則訪問 bazel 規則的 output?

[英]How can I access the output of a bazel rule from another rule without using a relative path?

我正在嘗試使用 Bazel 編譯基於 dhall-kubernetes 的 dhall 程序以生成 Kubernetes YAML 文件。

使用簡單的 bazel 宏在沒有 dhall-kubernetes 的情況下進行基本 dhall 編譯可以正常工作。

我已經做了一個使用 dhall 的依賴解析來下載 dhall-kubernetes 的示例 - 請參見此處 這也有效,但速度很慢(我認為是因為 dhall 分別下載每個遠程文件),並且對 bazel 規則執行引入了網絡依賴性,我希望避免這種情況。

我首選的方法是使用 Bazel 下載 dhall-kubernetes 的存檔發行版,然后讓規則在本地訪問它(請參閱此處)。 我的解決方案需要 Prelude.dhall 和 package.dhall 中的相對路徑,用於示例/k8s package 以引用 dhall-kubernetes。 雖然它有效,但我擔心這會破壞 Bazel 沙箱,因為它需要 Bazel 內部使用的文件夾結構的特殊知識。 有沒有更好的辦法?

Prelude.dhall:

../../external/dhall-kubernetes/1.17/Prelude.dhall 

工作空間:

workspace(name = "dhall")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

DHALL_KUBERNETES_VERSION = "4.0.0"

http_archive(
    name = "dhall-kubernetes",
    sha256 = "0bc2b5d2735ca60ae26d388640a4790bd945abf326da52f7f28a66159e56220d",
    url = "https://github.com/dhall-lang/dhall-kubernetes/archive/v%s.zip" % DHALL_KUBERNETES_VERSION,
    strip_prefix = "dhall-kubernetes-4.0.0",
    build_file = "@//:BUILD.dhall-kubernetes",
)

BUILD.dhall-kubernetes:

package(default_visibility=['//visibility:public'])

filegroup(
    name = "dhall-k8s-1.17",
    srcs = glob([
        "1.17/**/*",
    ]),
)

示例/k8s/構建:

package(default_visibility = ["//visibility:public"])

genrule(
    name = "special_ingress",
    srcs = ["ingress.dhall",
            "Prelude.dhall",
            "package.dhall",
        "@dhall-kubernetes//:dhall-k8s-1.17"
    ],
    outs = ["ingress.yaml"],
    cmd = "dhall-to-yaml --file $(location ingress.dhall) > $@",
    visibility = [
        "//visibility:public"
    ]
)

有一種方法可以讓dhall進行“離線”構建,這意味着 package 管理器獲取所有 Dhall 依賴項,而不是 Dhall 獲取它們。

事實上,我為 Nixpkgs 實現了一些東西,你可以翻譯成 Bazel:

高層解釋

基本技巧是利用 Dhall 導入系統的一個特性,即如果緩存了受語義完整性檢查(即“語義哈希”)保護的 package,則 Dhall 將使用緩存而不是獲取 package。 您可以利用這個技巧讓 package 管理器通過這種方式注入依賴項來繞過 Dhall 的遠程導入。

你可以在這里找到與 Nix 相關的邏輯:

...但我會嘗試解釋它是如何以獨立於包管理器的方式工作的。

Package結構

首先,使用 Nix 構建的 Dhall“包”的最終產品是具有以下結構的目錄:

$ nix-build --attr 'dhallPackages.Prelude'         
…

$ tree -a ./result
./result
├── .cache
│   └── dhall
│       └── 122026b0ef498663d269e4dc6a82b0ee289ec565d683ef4c00d0ebdd25333a5a3c98
└── binary.dhall

2 directories, 2 files

這個目錄的內容是:

  • ./cache/dhall/1220XXX…XXX

    包含單個構建產品的 Dhall 的有效緩存目錄:解釋的 Dhall 表達式的二進制編碼。

    您可以使用dhall encode創建這樣的二進制文件,並且可以通過將上面的XXX…XXX替換為表達式的sha256編碼來計算文件名,您可以使用dhall hash命令獲得。

  • ./binary.dhall

    一個方便的 Dhall 文件,其中包含missing sha256:XXX…XXX的表達式。 僅當我們構建的與 hash sha256:XXX…XXX匹配的表達式已被緩存時,解釋此表達式才會成功。

    該文件被稱為binary.dhall ,因為它是“二進制”package 發行版的 Dhall 等價物,這意味着只能從二進制緩存中獲取導入,而不能從源中獲取和解釋。

  • 可選: ./source.dhall

    這是一個包含與緩存的表達式等效的完全 αβ 標准化表達式的文件。 默認情況下,除了頂級 package 之外的所有包都應該省略它,因為它包含存儲在./cache/1220XXX…XXX內部的相同表達式,盡管效率較低(因為二進制編碼更緊湊)

    該文件被稱為./source.dhall ,因為它是“源”package 發行版的 Dhall 等價物,它包含產生相同結果的有效源代碼。

用戶界面

用於構建 package 的 function 需要四個 arguments:

  • package 名稱

    這對構建來說並不重要。 這只是命名,因為每個 Nix package 都必須有一個人類可讀的名稱。

  • 構建的依賴項

    這些依賴項中的每一個都是生成目錄樹的構建產品,就像我上面描述的那樣(即./cache目錄、. ./binary.dhall文件和可選的./source.dhall文件)

  • 一個 Dhall 表達式

    這可以是任意的 Dhall 源代碼,只有一個警告:由表達式傳遞引用的所有遠程導入必須受到完整性檢查的保護,並且這些導入必須與此 Dhall package 的依賴項之一匹配(以便可以通過以下方式滿足導入緩存而不是 Dhall 運行時獲取 URL)

  • 一個 boolean 選項指定是否保留./source.dhall文件,默認為False

執行

Dhall package 構建器的工作方式是:

  • 首先,使用-f-with-http標志構建 Haskell Dhall package

    此標志編譯出對 HTTP 遠程導入的支持,這樣如果用戶忘記為遠程導入提供依賴項,他們將收到一條錯誤消息,指出Import resolution is disabled

    我們將在所有后續步驟中使用這個可執行文件

  • 在當前工作目錄中創建一個名為.cache/dhall的緩存目錄

    ...並使用存儲在每個依賴項的./cache/目錄中的二進制文件填充緩存目錄

  • 配置解釋器使用我們創建的緩存目錄

    ...通過設置XDG_CACHE_HOME指向我們剛剛在當前工作目錄中創建的.cache目錄

  • 解釋和 α 標准化 package 的 Dhall 源代碼

    ...使用dhall --alpha命令。 將結果保存到$out/source.dhall ,其中$out是存儲最終構建產品的目錄

  • 獲取表達式的 hash

    ...使用dhall hash命令。 我們將需要這個 hash 用於以下兩個步驟。

  • 創建對應的二進制緩存文件

    ...使用dhall encode命令並將文件保存到$out/cache/dhall/1220${HASH}

  • 創建./binary.dhall文件

    ...只需將包含missing sha256:${HASH}的文本文件寫入$out/binary.dhall

  • 可選:刪除./source.dhall文件

    ...如果用戶沒有要求保留文件。 默認情況下省略此文件有助於節省 package 存儲中的空間,因為不會將相同的表達式存儲兩次(作為二進制文件和源代碼)。

包裝約定

一旦你有了這個 function,有幾個約定可以幫助簡化“大體上”的操作

  • 默認情況下,package 應該構建項目的./package.dhall文件

  • 輕松覆蓋 package 版本

  • 輕松覆蓋 package 中構建的文件

    換句話說,如果用戶更喜歡導入單個文件,例如https://prelude.dhall-lang.org/List/map而不是頂級./package.dhall文件,那么他們應該有一種方法可以指定依賴像Prelude.override { file = "./List/map"; } Prelude.override { file = "./List/map"; }來獲得一個 package 來構建和緩存那個單獨的文件。

結論

希望對您有所幫助,如果您對如何執行此操作有更多疑問,可以在這里提問,或者您也可以在我們的 Discourse 論壇上討論更多內容:尤其是在這個成語最初起源的線程上:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM