如何通过 Bazel go_binary 访问 Go 应用程序 运行 中的数据文件

How to access data files inside Go application running through Bazel go_binary

我有一个包含 go_binary 目标的 BUILD.bazel 文件。在这个应用程序中,我需要访问位于同一目录中的 YAML 文件(例如 config.yml)。

go_binary 看起来像这样:

go_binary(
    name = "app1",
    data = ["config.yml"],
    embed = [":app1_lib"],
    visibility = ["//visibility:public"],
)

我可以看到文件已添加到 /private/var/tmp/_bazel/52b44015c7f2ec78df04b9a822df93c1/execroot/__main__/bazel-out/darwin-fastbuild/bin/services/app1/app1_/app1.runfiles/__main__/services/app1 文件夹中。

在我的 Go 应用程序中访问此文件的最佳方式是什么?

到目前为止我发现我可以做到

url := fmt.Sprintf("%s/services/app1/config.yml", os.Getenv("PWD"))

...但我想避免必须明确指定文件夹结构。

这就是您在 Bazel 中访问数据文件的简单方式...您指定文件的完整路径,从 WORKSPACE 根目录开始。如果您的文件有目标 //services/app1:config.yml,那么路径就是 serivces/app1/config.yml.

不需要前缀$PWD除非你出于某种原因需要一个绝对路径。这样做的首选方法是:

const config = "services/app1/config.yml"
abs, err := filepath.Abs(config)
if err != nil {
    return err
}

假设您没有调用 chdir...我避免在我的程序中调用 chdir,主要是出于这个原因。

请注意,这不是 URL,如果您需要 URL,您可以:

u := url.URL{Scheme: "file", Path: filepath.ToSlash(abs)}

另请注意,如果您使用多个存储库中的文件,则必须包括存储库,并以 "external" 为前缀。例如,@some-repo//dir/pkg:targetexternal/some-repo-dir/pkg/target... 即使它在您的 BUILD 文件中只是 ":target"。呃,对吧?

为什么 Bazel 这样做?

您的代码可能 link 将来自整个工作区的包打包在一起。看起来很明显,在您的情况下,您只希望能够从与包相同的目录中读取 config.yml,但您同样可以将 data = ["config.yml"] 传递给某些 go_library()你的 deps.

为了让它在任何地方都一样工作,每个人都需要使用数据文件的完整路径。有点冗长,但是哦。

如果您只是从 genrule 或构建规则而不是 bazel run 调用 go_binary,您可以将配置文件的路径作为命令行参数传递,如果你比较喜欢。这会让您在没有完整路径的情况下指定它。