如何查询Bazel测试使用的数据文件列表

时间:2018-06-20 19:48:14

标签: bazel

我有一个cc_test定义如下:

filegroup(
    name = "test_data",
    srcs = [
        "abc/abc.txt",
        "def.txt",
    ],
)

cc_test(
    name = "my_test",
    size = "small",
    srcs = [
        "test_a.cpp",
    ],
    data = [
        ":test_data",
    ],
)

我想使用data查询用于此测试的runfiles文件(或abc/abc.txt)(在这种情况下为def.txtbazel query)。

我需要在脚本中使用一些测试所使用的数据文件列表。

这是我所走的路:

$bazel query 'kind("source file", deps(//xxx/...))'
@bazel_tools//tools/test:test-setup.sh
@bazel_tools//tools/test:collect_coverage.sh
@bazel_tools//tools/def_parser:no_op.bat
@bazel_tools//tools/def_parser:def_parser.exe
@bazel_tools//tools/cpp:link_dynamic_library.sh
@bazel_tools//tools/cpp:grep-includes.sh
@bazel_tools//tools/cpp:build_interface_so
@bazel_tools//tools/coverage:dummy_coverage_report_generator
@bazel_tools//third_party/def_parser:def_parser_main.cc
@bazel_tools//third_party/def_parser:def_parser.h
@bazel_tools//third_party/def_parser:def_parser.cc
//xxx:test_a.cpp
//xxx:def.txt
//xxx:abc/abc.txt

我只想要此列表的子集,也就是测试文件(//xxx:def.txt//xxx:abc/abc.txt

可以这样做吗?

1 个答案:

答案 0 :(得分:2)

我不认为可以使用bazel query来做到这一点,但是我们可以使用Aspects来做到这一点。

Bazel中的方面允许您遍历属性图边缘(例如depssrcs)的依存关系图并创建自定义动作。

示例:

鉴于此BUILD文件,我们可以创建一个自定义规则和方面以通过deps遍历依赖关系图,并将data文件收集到一个文件中。

load("//:collect_data_files.bzl", "collect_data_files")

filegroup(
    name = "test_foo_data",
    srcs = [
        "foo.txt",
        "foo/foo.txt",
    ],
)

cc_test(
    name = "test_foo",
    size = "small",
    srcs = [
        "test_foo.cpp",
    ],
    data = [
        ":test_foo_data",
    ],
)

filegroup(
    name = "test_bar_data",
    srcs = [
        "bar.txt",
        "bar/bar.txt",
    ],
)

filegroup(
    name = "test_bar_lib_data",
    srcs = [
        "bar_lib.txt",
        "bar_lib/bar_lib.txt",
    ],
)

cc_library(
    name = "test_bar_lib",
    srcs = ["test_bar_lib.cpp"],
    data = [":test_bar_lib_data"],
)

cc_test(
    name = "test_bar",
    size = "small",
    srcs = [
        "test_bar.cpp",
    ],
    data = [
        ":test_bar_data",
    ],
    deps = [":test_bar_lib"],
)

collect_data_files(
    name = "collect_data",
    testonly = 1,
    deps = [
        "test_bar",
        "test_foo",
    ],
)

这是依赖关系图:

enter image description here

我们有两个测试,test_footest_bar,具体取决于数据文件。 test_bar还取决于拥有自己数据文件的cc_library

collect_data_files.bzl中,我们可以创建一个方面来通过目标的传递deps收集目标上的数据文件。

DataFilesInfo = provider(
    fields = {
        "data_files": "Data files for this target",
    },
)

def _collect_data_aspect_impl(target, ctx):
    data_files = []
    if hasattr(ctx.rule.attr, "data"):
        for src in ctx.rule.attr.data:
            for f in src.files:
                data_files += [f]
    for dep in ctx.rule.attr.deps:
        data_files += dep[DataFilesInfo].data_files
    return [DataFilesInfo(data_files = data_files)]

collect_data_aspect = aspect(
    attr_aspects = [
        "deps",
    ],
    implementation = _collect_data_aspect_impl,
)

然后在同一文件中,我们可以定义collect_data_files规则以将目标标签及其数据文件的列表写入文件。

def _collect_data_rule_impl(ctx):
    data_files_string = ""
    for dep in ctx.attr.deps:
        data_files = [f.path for f in dep[DataFilesInfo].data_files]
        data_files_string += str(dep.label) + ","
        data_files_string += ",".join(data_files) + "\n"
    ctx.actions.write(ctx.outputs.data_files, data_files_string)

collect_data_files = rule(
    attrs = {
        "deps": attr.label_list(aspects = [collect_data_aspect]),
    },
    outputs = {
        "data_files": "%{name}_data_files.txt",
    },
    implementation = _collect_data_rule_impl,
)

现在,我们可以建立collect_data_files目标:

$ bazel build :collect_data
INFO: Analysed target //:collect_data (10 packages loaded).
INFO: Found 1 target...
Target //:collect_data up-to-date:
  bazel-bin/collect_data_data_files.txt
INFO: Elapsed time: 1.966s, Critical Path: 0.01s
INFO: 0 processes.
INFO: Build completed successfully, 2 total actions

结果被写入输出文件:

$ cat bazel-bin/collect_data_data_files.txt
//:test_bar,bar.txt,bar/bar.txt,bar_lib.txt,bar_lib/bar_lib.txt
//:test_foo,foo.txt,foo/foo.txt