kythe.io@v0.0.68-0.20240422202219-7225dbc01741/tools/build_rules/verifier_test/java_verifier_test.bzl (about) 1 # Copyright 2019 The Kythe Authors. All rights reserved. 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 15 load("@rules_java//java:defs.bzl", "JavaInfo", "java_binary", "java_common") 16 load( 17 ":verifier_test.bzl", 18 "KytheVerifierSources", 19 "extract", 20 "index_compilation", 21 "verifier_test", 22 ) 23 load( 24 "//kythe/cxx/indexer/proto/testdata:proto_verifier_test.bzl", 25 "proto_extract_kzip", 26 ) 27 load("//kythe/java/com/google/devtools/kythe/extractors/java/bazel:aspect.bzl", "extract_java") 28 29 KytheGeneratedSourcesInfo = provider( 30 doc = "Generated Java source directory and jar.", 31 fields = { 32 "srcjar": "Source jar of generated files.", 33 "dir": "Directory of unpacked files in srcjar.", 34 }, 35 ) 36 37 def _invoke(rulefn, name, **kwargs): 38 """Invoke rulefn with name and kwargs, returning the label of the rule.""" 39 rulefn(name = name, **kwargs) 40 return "//{}:{}".format(native.package_name(), name) 41 42 def _filter_java_sources(src): 43 if type(src) != "File": 44 return src 45 src = src.path 46 if src.endswith(".java"): 47 return src 48 return None 49 50 def _java_extract_kzip_impl(ctx): 51 deps = [] 52 for dep in ctx.attr.deps: 53 deps.append(dep[JavaInfo]) 54 55 srcs = [] 56 srcjars = [] 57 dirs = [] 58 for src in ctx.attr.srcs: 59 if KytheGeneratedSourcesInfo in src: 60 srcjars.append(src[KytheGeneratedSourcesInfo].srcjar) 61 dirs.append(src[KytheGeneratedSourcesInfo].dir) 62 else: 63 srcs.append(src.files) 64 srcs = depset(transitive = srcs).to_list() 65 66 # Actually compile the sources to be used as a dependency for other tests 67 jar = ctx.actions.declare_file(ctx.outputs.kzip.basename + ".jar", sibling = ctx.outputs.kzip) 68 69 java_toolchain = ctx.attr._java_toolchain[java_common.JavaToolchainInfo] 70 java_info = java_common.compile( 71 ctx, 72 javac_opts = ctx.attr.opts, 73 java_toolchain = java_toolchain, 74 source_jars = srcjars, 75 source_files = srcs, 76 output = jar, 77 deps = deps, 78 ) 79 80 jars = depset(transitive = [dep.compile_jars for dep in deps]).to_list() 81 82 args = ctx.actions.args() 83 args.add_all(ctx.attr.opts + ["-encoding", "utf-8"]) 84 args.add_joined("-cp", jars, join_with = ":") 85 args.add_all(dirs, map_each = _filter_java_sources, expand_directories = True) 86 87 extract( 88 srcs = srcs, 89 ctx = ctx, 90 extractor = ctx.executable.extractor, 91 kzip = ctx.outputs.kzip, 92 mnemonic = "JavaExtractKZip", 93 opts = args, 94 vnames_config = ctx.file.vnames_config, 95 deps = jars + ctx.files.data + dirs, 96 ) 97 return [ 98 java_info, 99 KytheVerifierSources(files = depset(srcs)), 100 ] 101 102 java_extract_kzip = rule( 103 attrs = { 104 "srcs": attr.label_list( 105 mandatory = True, 106 allow_empty = False, 107 allow_files = True, 108 ), 109 "data": attr.label_list( 110 allow_files = True, 111 ), 112 "extractor": attr.label( 113 default = Label("@io_kythe//kythe/java/com/google/devtools/kythe/extractors/java/standalone:javac_extractor"), 114 executable = True, 115 cfg = "exec", 116 ), 117 "opts": attr.string_list(), 118 "vnames_config": attr.label( 119 default = Label("//external:vnames_config"), 120 allow_single_file = True, 121 ), 122 "deps": attr.label_list( 123 providers = [JavaInfo], 124 ), 125 "_java_toolchain": attr.label( 126 default = Label("@rules_java//toolchains:current_java_toolchain"), 127 ), 128 }, 129 toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], 130 fragments = ["java"], 131 outputs = {"kzip": "%{name}.kzip"}, 132 implementation = _java_extract_kzip_impl, 133 ) 134 135 _default_java_extractor_opts = [ 136 "-source", 137 "9", 138 "-target", 139 "9", 140 ] 141 142 def java_verifier_test( 143 name, 144 srcs = None, 145 compilation = None, 146 meta = [], 147 verifier_deps = [], 148 deps = [], 149 size = "small", 150 timeout = None, 151 tags = [], 152 extractor = None, 153 resolve_code_facts = False, 154 extractor_opts = _default_java_extractor_opts, 155 indexer_opts = ["--verbose"], 156 verifier_opts = ["--ignore_dups"], 157 load_plugin = None, 158 extra_goals = [], 159 vnames_config = None, 160 visibility = None): 161 """Extract, analyze, and verify a Java compilation. 162 163 Args: 164 srcs: The compilation's source file inputs; each file's verifier goals will be checked 165 compilation: Specific Bazel Java target compilation to extract, analyze, and verify 166 verifier_deps: Optional list of java_verifier_test targets to be used as Java compilation dependencies 167 deps: Optional list of Java compilation dependencies 168 meta: Optional list of Kythe metadata files 169 extractor: Executable extractor tool to invoke (defaults to javac_extractor) 170 extractor_opts: List of options passed to the extractor tool 171 indexer_opts: List of options passed to the indexer tool 172 verifier_opts: List of options passed to the verifier tool 173 load_plugin: Optional Java analyzer plugin to load 174 extra_goals: List of text files containing verifier goals additional to those in srcs 175 vnames_config: Optional path to a VName configuration file 176 """ 177 if compilation: 178 kzip = name + "_kzip" 179 extract_java(name = kzip, testonly = True, compilation = compilation) 180 else: 181 kzip = _invoke( 182 java_extract_kzip, 183 name = name + "_kzip", 184 testonly = True, 185 srcs = srcs, 186 data = meta, 187 extractor = extractor, 188 opts = extractor_opts, 189 tags = tags, 190 visibility = visibility, 191 vnames_config = vnames_config, 192 # This is a hack to depend on the .jar producer. 193 deps = deps + [d + "_kzip" for d in verifier_deps], 194 ) 195 indexer = "//kythe/java/com/google/devtools/kythe/analyzers/java:indexer" 196 tools = [] 197 if load_plugin: 198 # If loaded plugins have deps, those must be included in the loaded jar 199 java_binary( 200 name = name + "_load_plugin", 201 main_class = "not.Used", 202 runtime_deps = [load_plugin], 203 ) 204 load_plugin_deploy_jar = ":{}_load_plugin_deploy.jar".format(name) 205 indexer_opts = indexer_opts + [ 206 "--load_plugin", 207 "$(location {})".format(load_plugin_deploy_jar), 208 ] 209 tools.append(load_plugin_deploy_jar) 210 211 entries = _invoke( 212 index_compilation, 213 name = name + "_entries", 214 testonly = True, 215 indexer = indexer, 216 target_indexer = indexer, 217 opts = indexer_opts, 218 tags = tags + ["manual"], 219 tools = tools, 220 target_tools = tools, 221 visibility = visibility, 222 deps = [kzip], 223 ) 224 goals = extra_goals 225 if len(goals) > 0: 226 goals += [entries] + [dep + "_entries" for dep in verifier_deps] 227 return _invoke( 228 verifier_test, 229 name = name, 230 size = size, 231 timeout = timeout, 232 srcs = goals, 233 opts = verifier_opts + [ 234 "--goal_regex='\\s*//\\s*-(.*)'", 235 ], 236 tags = tags, 237 visibility = visibility, 238 resolve_code_facts = resolve_code_facts, 239 deps = [entries] + [dep + "_entries" for dep in verifier_deps], 240 ) 241 242 def _generate_java_proto_impl(ctx): 243 # Generate the Java protocol buffer sources into a directory. 244 # Note: out contains .meta files with annotations for cross-language xrefs. 245 out = ctx.actions.declare_directory(ctx.label.name) 246 protoc = ctx.executable._protoc 247 ctx.actions.run_shell( 248 outputs = [out], 249 inputs = ctx.files.srcs, 250 tools = [protoc], 251 command = "\n".join([ 252 "#/bin/bash", 253 "set -e", 254 # Creating the declared directory in this action is necessary for 255 # remote execution environments. This differs from local execution 256 # where Bazel will create the directory before this action is 257 # executed. 258 "mkdir -p " + out.path, 259 " ".join([ 260 protoc.path, 261 "--java_out=annotate_code:" + out.path, 262 ] + [src.path for src in ctx.files.srcs]), 263 ]), 264 ) 265 266 # Produce a source jar file for the native Java compilation in the java_extract_kzip rule. 267 # Note: we can't use java_common.pack_sources because our input is a directory. 268 srcjar = ctx.actions.declare_file(ctx.label.name + ".srcjar") 269 args = ctx.actions.args() 270 args.add_all(["--output", srcjar]) 271 args.add_all(["--resources", out], map_each = _filter_java_sources, expand_directories = True) 272 ctx.actions.run( 273 outputs = [srcjar], 274 inputs = [out], 275 executable = ctx.executable._singlejar, 276 arguments = [args], 277 ) 278 279 return [ 280 DefaultInfo(files = depset([out, srcjar])), 281 KytheGeneratedSourcesInfo(dir = out, srcjar = srcjar), 282 ] 283 284 _generate_java_proto = rule( 285 attrs = { 286 "srcs": attr.label_list( 287 mandatory = True, 288 allow_files = True, 289 providers = [JavaInfo], 290 ), 291 "_protoc": attr.label( 292 default = Label("@com_google_protobuf//:protoc"), 293 executable = True, 294 cfg = "exec", 295 ), 296 "_singlejar": attr.label( 297 default = Label("@rules_java//toolchains:singlejar"), 298 executable = True, 299 cfg = "exec", 300 ), 301 }, 302 implementation = _generate_java_proto_impl, 303 ) 304 305 def java_proto_verifier_test( 306 name, 307 srcs, 308 size = "small", 309 proto_libs = [], 310 proto_srcs = [], 311 tags = [], 312 java_extractor_opts = _default_java_extractor_opts, 313 verifier_opts = ["--ignore_dups"], 314 vnames_config = None, 315 visibility = None): 316 """Verify cross-language references between Java and Proto. 317 318 Args: 319 name: Name of the test. 320 size: Size of the test. 321 tags: Test target tags. 322 visibility: Visibility of the test target. 323 srcs: The compilation's Java source files; each file's verifier goals will be checked 324 proto_libs: The proto_library targets containing proto_srcs 325 proto_srcs: The compilation's proto source files; each file's verifier goals will be checked 326 verifier_opts: List of options passed to the verifier tool 327 vnames_config: Optional path to a VName configuration file 328 329 Returns: the label of the test. 330 """ 331 proto_kzip = _invoke( 332 proto_extract_kzip, 333 name = name + "_proto_kzip", 334 srcs = proto_libs, 335 tags = tags, 336 visibility = visibility, 337 vnames_config = vnames_config, 338 ) 339 proto_entries = _invoke( 340 index_compilation, 341 name = name + "_proto_entries", 342 testonly = True, 343 indexer = "//kythe/cxx/indexer/proto:indexer", 344 opts = ["--index_file"], 345 tags = tags, 346 visibility = visibility, 347 deps = [proto_kzip], 348 ) 349 350 # TODO(justinbuchanan): use java_proto_library instead of manually invoking protoc 351 _generate_java_proto( 352 name = name + "_gensrc", 353 srcs = proto_srcs, 354 ) 355 356 kzip = _invoke( 357 java_extract_kzip, 358 name = name + "_java_kzip", 359 srcs = srcs + [":" + name + "_gensrc"], 360 opts = java_extractor_opts, 361 tags = tags, 362 visibility = visibility, 363 vnames_config = vnames_config, 364 deps = [ 365 "@com_google_protobuf//:protobuf_java", 366 "@maven//:org_apache_tomcat_tomcat_annotations_api", 367 ], 368 ) 369 370 entries = _invoke( 371 index_compilation, 372 name = name + "_java_entries", 373 testonly = True, 374 indexer = "//kythe/java/com/google/devtools/kythe/analyzers/java:indexer", 375 opts = ["--verbose"], 376 tags = tags, 377 visibility = visibility, 378 deps = [kzip], 379 ) 380 return _invoke( 381 verifier_test, 382 name = name, 383 size = size, 384 srcs = [entries, proto_entries], 385 deps = [entries, proto_entries], 386 opts = verifier_opts, 387 tags = tags, 388 visibility = visibility, 389 )