我有一个测试工具(粗略地说,是一个不同的工具),它接受两个输入,并返回一个输出(两个输入之间的差异)和一个返回代码(如果两个输入匹配,返回代码为0,否则为1)。它建在科特林,可在//java/fr/enoent/phosphorus
在我的回购。
我想要编写一条规则,测试由某物生成的文件是否与存储库中已经存在的引用文件相同。我用ctx.actions.run
尝试了一些东西,问题是我的规则,有test = True
设置,需要返回由该规则构建的可执行文件(所以不是为规则提供的工具)。然后,我尝试将它封装在示例后面的shell脚本中,如下所示:
def _phosphorus_test_impl(ctx):
output = ctx.actions.declare_file("{name}.phs".format(name = ctx.label.name))
script = phosphorus_compare(
ctx,
reference = ctx.file.reference,
comparison = ctx.file.comparison,
out = output,
)
ctx.actions.write(
output = ctx.outputs.executable,
content = script,
)
runfiles = ctx.runfiles(files = [ctx.executable._phosphorus_tool, ctx.file.reference, ctx.file.comparison])
return [DefaultInfo(runfiles = runfiles)]
phosphorus_test = rule(
_phosphorus_test_impl,
attrs = {
"comparison": attr.label(
allow_single_file = [".phs"],
doc = "File to compare to the reference",
mandatory = True,
),
"reference": attr.label(
allow_single_file = [".phs"],
doc = "Reference file",
mandatory = True,
),
"_phosphorus_tool": attr.label(
default = "//java/fr/enoent/phosphorus",
executable = True,
cfg = "host",
),
},
doc = "Compares two files, and fails if they are different.",
test = True,
)
(phosphorus_compare
只是一个生成实际命令的宏。)
然而,这种方法有两个问题:
java/fr/enoent/phosphorus/phosphorus: line 359: /home/kernald/.cache/bazel/_bazel_kernald/58c025fbb926eac6827117ef80f7d2fa/sandbox/linux-sandbox/1979/execroot/fr_enoent/bazel-out/k8-fastbuild/bin/tools/phosphorus/tests/should_pass.runfiles/remotejdk11_linux/bin/java: No such file or directory
总的来说,我觉得使用shell脚本只是添加了一个不必要的间接方向,并且失去了一些上下文(例如,工具的runfiles)。理想情况下,我只需要使用ctx.actions.run
并依赖于它的返回代码,但它似乎不是一个选项,因为测试显然需要生成一个可执行文件。写这样一条规则的正确方法是什么?
发布于 2019-10-09 08:02:55
事实证明,生成脚本是正确的方法,(据我所知)不可能返回指向ctx.actions.run
的某种指针。测试规则需要有一个可执行的输出。
关于工具正在生成的输出文件:根本不需要声明它。我只需要确保它是在$TEST_UNDECLARED_OUTPUTS_DIR
中生成的。这个目录中的每个文件都将被Bazel添加到一个名为output.zip
的存档中。这是(部分)文档化的这里。
关于runfile,我有这个工具的二进制文件,但没有它自己的runfile。这是一个固定的规则:
def _phosphorus_test_impl(ctx):
script = phosphorus_compare(
ctx,
reference = ctx.file.reference,
comparison = ctx.file.comparison,
out = "%s.phs" % ctx.label.name,
)
ctx.actions.write(
output = ctx.outputs.executable,
content = script,
)
return [
DefaultInfo(
runfiles = ctx.runfiles(
files = [
ctx.executable._phosphorus_tool,
ctx.file.reference,
ctx.file.comparison,
],
).merge(ctx.attr._phosphorus_tool[DefaultInfo].default_runfiles),
executable = ctx.outputs.executable,
),
]
def phosphorus_test(size = "small", **kwargs):
_phosphorus_test(size = size, **kwargs)
_phosphorus_test = rule(
_phosphorus_test_impl,
attrs = {
"comparison": attr.label(
allow_single_file = [".phs"],
doc = "File to compare to the reference",
mandatory = True,
),
"reference": attr.label(
allow_single_file = [".phs"],
doc = "Reference file",
mandatory = True,
),
"_phosphorus_tool": attr.label(
default = "//java/fr/enoent/phosphorus",
executable = True,
cfg = "target",
),
},
doc = "Compares two files, and fails if they are different.",
test = True,
)
关键部分是返回的.merge(ctx.attr._phosphorus_tool[DefaultInfo].default_runfiles)
中的DefaultInfo
。
我还犯了一个关于配置的小错误,因为这个测试的目的是在目标配置上运行,而不是在主机上运行,因此已经相应地修复了它。
https://stackoverflow.com/questions/58253616
复制相似问题