blob: 76563d04244ec003c948e33387892ada66acd352 [file] [log] [blame]
# Copyright 2019 The Kythe Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load(
":verifier_test.bzl",
"KytheVerifierSources",
"extract",
"index_compilation",
"verifier_test",
)
load(
"//kythe/cxx/indexer/proto/testdata:proto_verifier_test.bzl",
"proto_extract_kzip",
)
KytheGeneratedSourcesInfo = provider(
doc = "Generated Java source directory and jar.",
fields = {
"srcjar": "Source jar of generated files.",
"dir": "Directory of unpacked files in srcjar.",
},
)
def _invoke(rulefn, name, **kwargs):
"""Invoke rulefn with name and kwargs, returning the label of the rule."""
rulefn(name = name, **kwargs)
return "//{}:{}".format(native.package_name(), name)
def _filter_java_sources(src):
if type(src) != "File":
return src
src = src.path
if src.endswith(".java"):
return src
return None
def _java_extract_kzip_impl(ctx):
deps = []
for dep in ctx.attr.deps:
deps += [dep[JavaInfo]]
srcs = []
srcjars = []
dirs = []
for src in ctx.attr.srcs:
if KytheGeneratedSourcesInfo in src:
srcjars += [src[KytheGeneratedSourcesInfo].srcjar]
dirs += [src[KytheGeneratedSourcesInfo].dir]
else:
srcs += [src.files]
srcs = depset(transitive = srcs).to_list()
# Actually compile the sources to be used as a dependency for other tests
jar = ctx.actions.declare_file(ctx.outputs.kzip.basename + ".jar", sibling = ctx.outputs.kzip)
# Use find_java_toolchain / find_java_runtime_toolchain after the next Bazel release,
# see: https://github.com/bazelbuild/bazel/issues/7186
if hasattr(java_common, "JavaToolchainInfo"):
java_toolchain = ctx.attr._java_toolchain[java_common.JavaToolchainInfo]
host_javabase = ctx.attr._host_javabase[java_common.JavaRuntimeInfo]
else:
java_toolchain = ctx.attr._java_toolchain
host_javabase = ctx.attr._host_javabase
java_info = java_common.compile(
ctx,
javac_opts = ctx.attr.opts,
java_toolchain = java_toolchain,
host_javabase = host_javabase,
source_jars = srcjars,
source_files = srcs,
output = jar,
deps = deps,
)
jars = depset(transitive = [dep.compile_jars for dep in deps]).to_list()
args = ctx.actions.args()
args.add_all(ctx.attr.opts + ["-encoding", "utf-8"])
args.add_joined("-cp", jars, join_with = ":")
args.add_all(dirs, map_each = _filter_java_sources, expand_directories = True)
extract(
srcs = srcs,
ctx = ctx,
extractor = ctx.executable.extractor,
kzip = ctx.outputs.kzip,
mnemonic = "JavaExtractKZip",
opts = args,
vnames_config = ctx.file.vnames_config,
deps = jars + ctx.files.data + dirs,
)
return [
java_info,
KytheVerifierSources(files = depset(srcs)),
]
java_extract_kzip = rule(
attrs = {
"srcs": attr.label_list(
mandatory = True,
allow_empty = False,
allow_files = True,
),
"data": attr.label_list(
allow_files = True,
),
"extractor": attr.label(
default = Label("@io_kythe//kythe/java/com/google/devtools/kythe/extractors/java/standalone:javac_extractor"),
executable = True,
cfg = "host",
),
"opts": attr.string_list(),
"vnames_config": attr.label(
default = Label("//external:vnames_config"),
allow_single_file = True,
),
"deps": attr.label_list(
providers = [JavaInfo],
),
"_host_javabase": attr.label(
cfg = "host",
default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
),
"_java_toolchain": attr.label(
default = Label("@bazel_tools//tools/jdk:toolchain"),
),
},
fragments = ["java"],
host_fragments = ["java"],
outputs = {"kzip": "%{name}.kzip"},
implementation = _java_extract_kzip_impl,
)
_default_java_extractor_opts = [
"-source",
"9",
"-target",
"9",
]
def java_verifier_test(
name,
srcs,
meta = [],
verifier_deps = [],
deps = [],
size = "small",
tags = [],
extractor = None,
extractor_opts = _default_java_extractor_opts,
indexer_opts = ["--verbose"],
verifier_opts = ["--ignore_dups"],
load_plugin = None,
extra_goals = [],
vnames_config = None,
visibility = None):
"""Extract, analyze, and verify a Java compilation.
Args:
srcs: The compilation's source file inputs; each file's verifier goals will be checked
verifier_deps: Optional list of java_verifier_test targets to be used as Java compilation dependencies
deps: Optional list of Java compilation dependencies
meta: Optional list of Kythe metadata files
extractor: Executable extractor tool to invoke (defaults to javac_extractor)
extractor_opts: List of options passed to the extractor tool
indexer_opts: List of options passed to the indexer tool
verifier_opts: List of options passed to the verifier tool
load_plugin: Optional Java analyzer plugin to load
extra_goals: List of text files containing verifier goals additional to those in srcs
vnames_config: Optional path to a VName configuration file
"""
kzip = _invoke(
java_extract_kzip,
name = name + "_kzip",
testonly = True,
srcs = srcs,
data = meta,
extractor = extractor,
opts = extractor_opts,
tags = tags,
visibility = visibility,
vnames_config = vnames_config,
# This is a hack to depend on the .jar producer.
deps = deps + [d + "_kzip" for d in verifier_deps],
)
indexer = "//kythe/java/com/google/devtools/kythe/analyzers/java:indexer"
tools = []
if load_plugin:
# If loaded plugins have deps, those must be included in the loaded jar
native.java_binary(
name = name + "_load_plugin",
main_class = "not.Used",
runtime_deps = [load_plugin],
)
load_plugin_deploy_jar = ":{}_load_plugin_deploy.jar".format(name)
indexer_opts = indexer_opts + [
"--load_plugin",
"$(location {})".format(load_plugin_deploy_jar),
]
tools += [load_plugin_deploy_jar]
entries = _invoke(
index_compilation,
name = name + "_entries",
testonly = True,
indexer = indexer,
opts = indexer_opts,
tags = tags,
tools = tools,
visibility = visibility,
deps = [kzip],
)
goals = extra_goals
if len(goals) > 0:
goals += [entries] + [dep + "_entries" for dep in verifier_deps]
return _invoke(
verifier_test,
name = name,
size = size,
srcs = goals,
opts = verifier_opts,
tags = tags,
visibility = visibility,
deps = [entries] + [dep + "_entries" for dep in verifier_deps],
)
def _generate_java_proto_impl(ctx):
# Generate the Java protocol buffer sources into a directory.
# Note: out contains .meta files with annotations for cross-language xrefs.
out = ctx.actions.declare_directory(ctx.label.name)
protoc = ctx.executable._protoc
ctx.actions.run_shell(
outputs = [out],
inputs = ctx.files.srcs,
tools = [protoc],
command = "\n".join([
"#/bin/bash",
"set -e",
# Creating the declared directory in this action is necessary for
# remote execution environments. This differs from local execution
# where Bazel will create the directory before this action is
# executed.
"mkdir -p " + out.path,
" ".join([
protoc.path,
"--java_out=annotate_code:" + out.path,
] + [src.path for src in ctx.files.srcs]),
]),
)
# Produce a source jar file for the native Java compilation in the java_extract_kzip rule.
# Note: we can't use java_common.pack_sources because our input is a directory.
srcjar = ctx.actions.declare_file(ctx.label.name + ".srcjar")
args = ctx.actions.args()
args.add_all(["--output", srcjar])
args.add_all(["--resources", out], map_each = _filter_java_sources, expand_directories = True)
ctx.actions.run(
outputs = [srcjar],
inputs = [out],
executable = ctx.executable._singlejar,
arguments = [args],
)
return [
DefaultInfo(files = depset([out, srcjar])),
KytheGeneratedSourcesInfo(dir = out, srcjar = srcjar),
]
_generate_java_proto = rule(
attrs = {
"srcs": attr.label_list(
mandatory = True,
allow_files = True,
providers = [JavaInfo],
),
"_protoc": attr.label(
default = Label("@com_google_protobuf//:protoc"),
executable = True,
cfg = "host",
),
"_singlejar": attr.label(
default = Label("@bazel_tools//tools/jdk:singlejar"),
executable = True,
cfg = "host",
),
},
implementation = _generate_java_proto_impl,
)
def java_proto_verifier_test(
name,
srcs,
size = "small",
proto_srcs = [],
tags = [],
java_extractor_opts = _default_java_extractor_opts,
verifier_opts = ["--ignore_dups"],
vnames_config = None,
visibility = None):
"""Verify cross-language references between Java and Proto.
Args:
name: Name of the test.
size: Size of the test.
tags: Test target tags.
visibility: Visibility of the test target.
srcs: The compilation's Java source files; each file's verifier goals will be checked
proto_srcs: The compilation's proto source files; each file's verifier goals will be checked
verifier_opts: List of options passed to the verifier tool
vnames_config: Optional path to a VName configuration file
Returns: the label of the test.
"""
proto_kzip = _invoke(
proto_extract_kzip,
name = name + "_proto_kzip",
srcs = proto_srcs,
tags = tags,
visibility = visibility,
vnames_config = vnames_config,
)
proto_entries = _invoke(
index_compilation,
name = name + "_proto_entries",
testonly = True,
indexer = "//kythe/cxx/indexer/proto:indexer",
opts = ["--index_file"],
tags = tags,
visibility = visibility,
deps = [proto_kzip],
)
_generate_java_proto(
name = name + "_gensrc",
srcs = proto_srcs,
)
kzip = _invoke(
java_extract_kzip,
name = name + "_java_kzip",
srcs = srcs + [":" + name + "_gensrc"],
opts = java_extractor_opts,
tags = tags,
visibility = visibility,
vnames_config = vnames_config,
deps = [
"@com_google_protobuf//:protobuf_java",
"@javax_annotation_jsr250_api//jar",
],
)
entries = _invoke(
index_compilation,
name = name + "_java_entries",
testonly = True,
indexer = "//kythe/java/com/google/devtools/kythe/analyzers/java:indexer",
opts = ["--verbose"],
tags = tags,
visibility = visibility,
deps = [kzip],
)
return _invoke(
verifier_test,
name = name,
size = size,
srcs = [entries, proto_entries] + proto_srcs,
opts = verifier_opts,
tags = tags,
visibility = visibility,
deps = [entries],
)