外部回购中数据文件的运行时路径

Runtime path to data file in external repo

假设我有以下两个 Bazel 存储库 (git repo):

repos
├── data
│   ├── BUILD.bazel
│   ├── external-data.txt
│   └── WORKSPACE
└── foo
    ├── BUILD.bazel
    ├── foo.py
    ├── local-data.txt
    └── WORKSPACE

我想弄清楚 foo 存储库中的 foo.py 脚本如何在运行时访问 data 存储库中的 external-data.txt

到目前为止,我已经设置好了 data 存储库为 external-data.txt:

定义了一个 public 文件组
# data/BUILD.bazel

filegroup(
    name = "data",
    srcs = ["external-data.txt"],
    visibility = ["//visibility:public"],
)

并且 foo 存储库将 data 存储库声明为依赖...

# foo/WORKSPACE

local_repository(
    name = "data",
    path = "../data",
)

...然后将文件组引用为 foo.py:

运行时要使用的数据
# foo/BUILD.bazel

py_binary(
    name = "foo",
    srcs = ["foo.py"],
    data = [
        "local-data.txt",
        "@data//:data"
    ]
)

但是,我再次不确定应该使用哪个路径在运行时访问 external-data.txt

# foo/foo.py

import os

def dump_file(file_path):
    print(file_path + ":")
    with open(file_path) as file:
        print(file.read())

def main():
    data_files = [
        'local-data.txt', # No problems here
        # What path should I use to access @data//:external-data.txt?
    ]
    for file in data_files:
        dump_file(file)

    print("cwd: " + os.getcwd())

if __name__ == "__main__":
    main()

对于上下文,我使用的是带有 --nolegacy_external_runfiles 标志的 Bazel 4.1.0 版:

bazel run //:foo --nolegacy_external_runfiles --sandbox_debug

该命令的输出如下:

local-data.txt:
foo
bar
baz

cwd: /home/$USER/.cache/bazel/_bazel_$USER/2da14ac18a4c150d41626b6c1957d2ad/execroot/__main__/bazel-out/k8-fastbuild/bin/foo.runfiles/__main__

我不确定这是否相关,但是当我检查目录 foo.py 输出为“cwd”时,我可以在这个相对路径中找到 external-data.txt 文件:

../../../../../../../../../../../experiments/repos/data/external-data.txt

以下是绝对路径:

/home/$USER/.cache/bazel/_bazel_$USER/2da14ac18a4c150d41626b6c1957d2ad/execroot/__main__/external/data

(好像外部文件的路径一般应该是execroot/$WORKSPACE/external/$EXTERNAL_WORKSPACE?)

runfiles.py 负责定位运行文件。它处理各种情况下的查找,包括 运行 作为运行文件的运行文件,这很棘手。它在顶部的评论中有文档。

要使用它,请将 "@rules_python//python/runfiles" 添加到 foodeps 中。然后,在 foo.py:

from rules_python.python.runfiles import runfiles

r = runfiles.Create()
print(r.Rlocation("data/data"))