英文:
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"))
...但我希望避免明确指定文件夹结构。
英文:
I have a BUILD.bazel file containing a go_binary target. Inside this application, I need to access a YAML file (eg. config.yml) located in the same directory.
The go_binary looks like this:
go_binary(
name = "app1",
data = ["config.yml"],
embed = [":app1_lib"],
visibility = ["//visibility:public"],
)
I can see the file is added to the /private/var/tmp/_bazel/52b44015c7f2ec78df04b9a822df93c1/execroot/__main__/bazel-out/darwin-fastbuild/bin/services/app1/app1_/app1.runfiles/__main__/services/app1
folder.
What is the best way to access this file inside my Go app?
So far I found that I could do
url := fmt.Sprintf("%s/services/app1/config.yml", os.Getenv("PWD"))
...but I would like to avoid having to specify the folder structure explicitly.
答案1
得分: 2
这只是在Bazel中访问数据文件的简单方法...你需要指定文件的完整路径,从WORKSPACE根目录开始。如果你的文件目标是//services/app1:config.yml
,那么路径就是services/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:target
变成了external/some-repo-dir/pkg/target
...即使在你的BUILD文件中只是":target"
。有点烦人,对吧?
为什么Bazel要这样做?
你的代码可能链接来自工作区各个位置的包。在你的情况下,你可能只是想从与包相同的目录中读取config.yml
,但你也可以将data = ["config.yml"]
传递给一些在你的deps
中的go_library()
。
为了使它在任何地方都能正常工作,每个人都需要使用数据文件的完整路径。这有点冗长,但没办法。
如果你只是从genrule
或构建规则中调用go_binary
,而不是使用bazel run
,你可以将配置文件的路径作为命令行参数传递,如果你愿意的话。这样可以让你在不使用完整路径的情况下指定它。
英文:
That is simply how you access data files in Bazel... you specify the full path to the file, from the WORKSPACE root. If your file has target //services/app1:config.yml
, then the path is just serivces/app1/config.yml
.
It is not necessary to prefix $PWD
unless you need an absolute path for some reason. The preferred way to do that would be this:
const config = "services/app1/config.yml"
abs, err := filepath.Abs(config)
if err != nil {
return err
}
This assumes you haven't called chdir... I avoid calling chdir in my programs, mostly for this reason.
Note that it's not a URL, if you need a URL, you would:
u := url.URL{Scheme: "file", Path: filepath.ToSlash(abs)}
Also note that if you are working with files in multiple repositories, you have to include the repository, prefixed by "external"
. For example, @some-repo//dir/pkg:target
is external/some-repo-dir/pkg/target
... even if it's just ":target"
in your BUILD file. Ugh, right?
Why Does Bazel Do This?
Your code may link together packages from all over your workspace. It may seem obvious that in your case, you just want to be able to read config.yml
from the same directory as the package, but you could equally pass data = ["config.yml"]
to some go_library()
that is in your deps
.
In order to make it work the same everywhere, everyone needs to use the full path to the data files. It's a bit verbose, but oh well.
If you are only invoking the go_binary
from a genrule
or build rule rather than bazel run
, you can pass the path to the config file as a command-line argument, if you prefer. This would let you specify it without the full path.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论