从Bazel中调用CheckStyle的最佳方式是什么?
我正在尝试添加对调用Checkstyle的支持,作为Bazel构建的一部分。我已经看到一些代码使用额外的操作来实现这一点,但我希望避免这种方法,并使其与纯Skylark代码一起工作。我设法使用以下(可怕的)通用规则让JVM对一组源文件执行Checkstyle,但我意识到这是非常棘手的:
native.genrule(
name = name,
srcs = srcs,
outs = ["src_output.txt"],
cmd = "$(JAVA) -Dconfig_loc=<full-config-loc-path> -classpath <path>/checkstyle-8.4-all.jar com.puppycrawl.tools.checkstyle.Main -c <config-file-path> -o $@ $(SRCS)",
**kwargs
)
对如何正确地做这件事有什么建议?我已经在Dependencies.bzl文件中拥有了所有必需的JAR依赖项,所以我很乐意引用这些依赖项,而不是check style-all jar。
解决方案
正如irc上所讨论的,这是我一直在使用的规则(在本文的末尾)。我有一个目录config/
,其中包含我的CheckStyle配置、抑制和许可证文件,这里引用这些文件作为默认参数。在您的工作区中,您可以使用一个宏将所有的副手都拉进来:
load("//tools:checkstyle.bzl", "checkstyle_repositories")
checkstyle_repositories()
在您的生成文件中导入规则并将其用于:
load("//tools:checkstyle.bzl", "checkstyle_test")
filegroup(
name = "java-srcs",
srcs = glob(["src/main/java/**/*.java"]),
)
checkstyle_test(
name = "check",
srcs = [
":java-srcs",
],
)
然后您可以使用bazel test //path/to/dir:check
运行它。
此规则有一个限制,即它在命令行接受参数,因此对于较大的模块,您需要拆分文件组以停止达到命令行长度限制,例如
load("//tools:checkstyle.bzl", "checkstyle_test")
filegroup(
name = "java-foo-srcs",
srcs = glob(["src/main/java/foo/**/*.java"]),
)
filegroup(
name = "java-bar-srcs",
srcs = glob(["src/main/java/bar/**/*.java"]),
)
checkstyle_test(
name = "check-foo",
srcs = [
":java-foo-srcs",
],
)
checkstyle_test(
name = "check-bar",
srcs = [
":java-bar-srcs",
],
)
test_suite(
name = "check",
tests = [
":check-bar",
":check-foo",
],
)
如果您每个包都有一个构建文件,这可能是不必要的,但如果您正在转换一个大的Maven模块并在Bazel构建文件中保持类似的结构,这可能会成为一个问题。
工具/检查样式.bzl
load("//tools/gerrit:maven_jar.bzl", "maven_jar")
def checkstyle_repositories(
omit = [],
versions = {
"antlr_antlr": "2.7.7",
"org_antlr_antlr4_runtime": "4.5.1-1",
"com_puppycrawl_tools_checkstyle": "8.2",
"commons_beanutils_commons_beanutils": "1.9.3",
"commons_cli_commons_cli": "1.4",
"commons_collections_commons_collections": "3.2.2",
"com_google_guava_guava23": "23.0",
"org_slf4j_slf4j_api": "1.7.7",
"org_slf4j_slf4j_jcl": "1.7.7",
}
):
if not "antlr_antlr" in omit:
maven_jar(
name = "antlr_antlr",
attach_source = False,
artifact = "antlr:antlr:" + versions["antlr_antlr"],
)
if not "org_antlr_antlr4_runtime" in omit:
maven_jar(
name = "org_antlr_antlr4_runtime",
artifact = "org.antlr:antlr4-runtime:" + versions["org_antlr_antlr4_runtime"],
)
if not "com_puppycrawl_tools_checkstyle" in omit:
maven_jar(
name = "com_puppycrawl_tools_checkstyle",
artifact = "com.puppycrawl.tools:checkstyle:" + versions["com_puppycrawl_tools_checkstyle"],
)
if not "commons_beanutils_commons_beanutils" in omit:
maven_jar(
name = "commons_beanutils_commons_beanutils",
artifact = "commons-beanutils:commons-beanutils:" + versions["commons_beanutils_commons_beanutils"],
)
if not "commons_cli_commons_cli" in omit:
maven_jar(
name = "commons_cli_commons_cli",
artifact = "commons-cli:commons-cli:" + versions["commons_cli_commons_cli"],
)
if not "commons_collections_commons_collections" in omit:
maven_jar(
name = "commons_collections_commons_collections",
artifact = "commons-collections:commons-collections:" + versions["commons_collections_commons_collections"],
)
if not "com_google_guava_guava23" in omit:
maven_jar(
name = "com_google_guava_guava23",
artifact = "com.google.guava:guava:" + versions["com_google_guava_guava23"],
)
if not "org_slf4j_slf4j_api" in omit:
maven_jar(
name = "org_slf4j_slf4j_api",
artifact = "org.slf4j:slf4j-api:" + versions["org_slf4j_slf4j_api"],
)
if not "org_slf4j_slf4j_jcl" in omit:
maven_jar(
name = "org_slf4j_slf4j_jcl",
artifact = "org.slf4j:jcl-over-slf4j:" + versions["org_slf4j_slf4j_jcl"],
)
def _checkstyle_test_impl(ctx):
name = ctx.label.name
srcs = ctx.files.srcs
deps = ctx.files.deps
config = ctx.file.config
properties = ctx.file.properties
suppressions = ctx.file.suppressions
opts = ctx.attr.opts
sopts = ctx.attr.string_opts
classpath=""
add=False
for file in ctx.files._classpath:
if add:
classpath += ":"
add=True
classpath += file.path
for file in ctx.files.deps:
classpath += ":" + file.path
args = ""
inputs = []
if config:
args += " -c %s" % config.path
inputs.append(config)
if properties:
args += " -p %s" % properties.path
inputs.append(properties)
if suppressions:
inputs.append(suppressions)
cmd = " ".join(
["java -cp %s com.puppycrawl.tools.checkstyle.Main" % classpath] +
[args] +
["--%s" % x for x in opts] +
["--%s %s" % (k, sopts[k]) for k in sopts] +
[x.path for x in srcs]
)
ctx.file_action(
output = ctx.outputs.executable,
content = cmd,
executable = True,
)
files = [ctx.outputs.executable, ctx.file.license] + srcs + deps + ctx.files._classpath + inputs
runfiles = ctx.runfiles(
files = files,
collect_data = True
)
return struct(
files = depset(files),
runfiles = runfiles,
)
checkstyle_test = rule(
implementation = _checkstyle_test_impl,
test = True,
attrs = {
"_classpath": attr.label_list(default=[
Label("@com_puppycrawl_tools_checkstyle//jar"),
Label("@commons_beanutils_commons_beanutils//jar"),
Label("@commons_cli_commons_cli//jar"),
Label("@commons_collections_commons_collections//jar"),
Label("@org_slf4j_slf4j_api//jar"),
Label("@org_slf4j_slf4j_jcl//jar"),
Label("@antlr_antlr//jar"),
Label("@org_antlr_antlr4_runtime//jar"),
Label("@com_google_guava_guava//jar"),
]),
"config": attr.label(allow_single_file=True, default = "//config:checkstyle"),
"suppressions": attr.label(allow_single_file=True, default = "//config:suppressions"),
"license": attr.label(allow_single_file=True, default = "//config:license"),
"properties": attr.label(allow_single_file=True),
"opts": attr.string_list(),
"string_opts": attr.string_dict(),
"srcs": attr.label_list(allow_files = True),
"deps": attr.label_list(),
},
)
"""Run checkstyle
Args:
config: A checkstyle configuration file
suppressions: A checkstyle suppressions file
license: A license file that can be used with the checkstyle license
target
properties: A properties file to be used
opts: Options to be passed on the command line that have no
argument
string_opts: Options to be passed on the command line that have an
argument
srcs: The files to check
"""
相关文章