我正在寻找在Bazel中运行“检查”或“验证”步骤的好方法,例如go vet
,gofmt
,pylint
,cppcheck
。这些步骤不会创建任何输出文件。唯一重要的是返回代码(如测试)。
现在我正在使用以下食谱:
sh_test(
name = "verify-pylint",
srcs = ["verify-pylint.sh"],
data = ["//:all-srcs"],
)
verify-pylint.sh
看起来像这样:
find . -name '*.py' | xargs pylint
这有两个问题:
//:all-srcs
),bazel test verify-pylint
会在每个文件上重新运行pylint
(这可能很昂贵/很慢)。bazel执行这些步骤的惯用方法是什么?
答案 0 :(得分:2)
有多种解决方案。
最简洁的方法是在构建时进行验证:为要验证的每个文件(或一批文件)创建genrule
,如果验证成功,则genrule输出一些内容,如果失败,然后规则不输出任何内容,这也会自动使构建失败。
由于验证的成功取决于文件的内容,并且相同的输入应该产生相同的输出,因此genrules应该产生一个输出文件,该输出文件取决于输入的内容。最方便的是在验证成功时将文件的摘要写入输出,如果验证失败则不输出。
要使验证程序可重复使用,您可以创建Skylark macro并在所有程序包中使用它。
要把这些放在一起,你可以写下面的内容。
//tools:py_verify_test.bzl
的内容:
def py_verify_test(name, srcs, visibility = None):
rules = {"%s-file%d" % (name, hash(s)): s for s in srcs}
for rulename, src in rules.items():
native.genrule(
name = rulename,
srcs = [s],
outs = ["%s.md5" % rulename],
cmd = "$(location //tools:py_verifier) $< && md5sum $< > $@",
tools = ["//tools:py_verifier"],
visibility = ["//visibility:private"],
)
native.sh_test(
name = name,
srcs = ["//tools:build_test.sh"],
data = rules.keys(),
visibility = visibility,
)
//tools:build_test.sh
的内容:
#!/bin/true
# If the test rule's dependencies could be built,
# then all files were successfully verified at
# build time, so this test can merely return true.
//tools:BUILD
的内容:
# I just use sh_binary as an example, this could
# be a more complicated rule of course.
sh_binary(
name = "py_verifier",
srcs = ["py_verifier.sh"],
visibility = ["//visibility:public"],
)
任何想要验证文件的包的内容:
load("//tools:py_verify_test.bzl", "py_verify_test")
py_verify_test(
name = "verify",
srcs = glob(["**/*.py"]),
)
答案 1 :(得分:1)
一个简单的解决方案。
在您的BUILD文件中:
load(":gofmt.bzl", "gofmt_test")
gofmt_test(
name = "format_test",
srcs = glob(["*.go"]),
)
在gofmt.bzl
:
def gofmt_test(name, srcs):
cmd = """
export TMPDIR=.
out=$$(gofmt -d $(SRCS))
if [ -n "$$out" ]; then
echo "gmfmt failed:"
echo "$$out"
exit 1
fi
touch $@
"""
native.genrule(
name = name,
cmd = cmd,
srcs = srcs,
outs = [name + ".out"],
tools = ["gofmt.sh"],
)
一些评论:
$$
而不是$
(请参阅documentation)gofmt_test
实际上不是测试版,会以bazel build :all
运行。如果您确实需要测试,请参阅Laszlo的示例并致电sh_test
。touch
来创建文件,因为genrule
要求输出成功。export TMPDIR=.
是必需的,因为默认情况下沙箱会阻止在其他目录中写入。要缓存每个文件的结果(并避免重新检查未更改的文件),您需要创建多个操作。请参阅Laszlo的for
循环。
为简化代码,我们可以提供通用规则。也许这是我们应该放在标准库中的东西。