Opensource java_single_jar in rules_java PiperOrigin-RevId: 565664709 Change-Id: Id6d082ebfd28af9db53aff8700d697cb4ae21426
diff --git a/java/BUILD b/java/BUILD index 8e07ca3..9e6bd30 100644 --- a/java/BUILD +++ b/java/BUILD
@@ -16,3 +16,9 @@ visibility = ["//visibility:public"], deps = ["//java/private"], ) + +bzl_library( + name = "java_single_jar", + srcs = ["java_single_jar.bzl"], + visibility = ["//visibility:public"], +)
diff --git a/java/java_single_jar.bzl b/java/java_single_jar.bzl new file mode 100644 index 0000000..6632c62 --- /dev/null +++ b/java/java_single_jar.bzl
@@ -0,0 +1,117 @@ +""" Definition of _java_single_jar. """ + +def _java_single_jar(ctx): + transitive_inputs = [] + for dep in ctx.attr.deps: + if JavaInfo in dep: + info = dep[JavaInfo] + transitive_inputs.append(info.transitive_runtime_jars) + if hasattr(info, "compilation_info"): + compilation_info = info.compilation_info + if hasattr(compilation_info, "runtime_classpath"): + transitive_inputs.append(compilation_info.runtime_classpath) + else: + files = [] + for f in dep[DefaultInfo].files.to_list(): + if not f.extension == "jar": + fail("unexpected file type in java_single_jar.deps: %s" % f.path) + files.append(f) + transitive_inputs.append(depset(files)) + inputs = depset(transitive = transitive_inputs) + + args = ctx.actions.args() + args.add_all("--sources", inputs) + args.use_param_file("@%s") + args.set_param_file_format("multiline") + args.add("--output", ctx.outputs.jar) + args.add("--normalize") + + # Deal with limitation of singlejar flags: tool's default behavior is + # "no", but you get that behavior only by absence of compression flags. + if ctx.attr.compress == "preserve": + args.add("--dont_change_compression") + elif ctx.attr.compress == "yes": + args.add("--compression") + elif ctx.attr.compress == "no": + pass + else: + fail("\"compress\" attribute (%s) must be: yes, no, preserve." % ctx.attr.compress) + + if ctx.attr.exclude_build_data: + args.add("--exclude_build_data") + if ctx.attr.multi_release: + args.add("--multi_release") + + ctx.actions.run( + inputs = inputs, + outputs = [ctx.outputs.jar], + arguments = [args], + progress_message = "Merging into %s" % ctx.outputs.jar.short_path, + mnemonic = "JavaSingleJar", + executable = ctx.executable._singlejar, + ) + + files = depset([ctx.outputs.jar]) + providers = [DefaultInfo( + files = files, + runfiles = ctx.runfiles(transitive_files = files), + )] + if hasattr(java_common, "JavaRuntimeClasspathInfo"): + providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = inputs)) + return providers + +java_single_jar = rule( + attrs = { + "deps": attr.label_list( + providers = [JavaInfo], + allow_files = True, + doc = """ + The Java targets (including java_import and java_library) to collect + transitive dependencies from. Runtime dependencies are collected via + deps, exports, and runtime_deps. Resources are also collected. + Native cc_library or java_wrap_cc dependencies are not.""", + ), + "compress": attr.string(default = "preserve", doc = """ + Whether to always deflate ("yes"), always store ("no"), or pass + through unmodified ("preserve"). The default is "preserve", and is the + most efficient option -- no extra work is done to inflate or deflate."""), + "exclude_build_data": attr.bool(default = True, doc = """ + Whether to omit the build-data.properties file generated + by default."""), + "multi_release": attr.bool(default = True, doc = """Whether to enable Multi-Release output jars."""), + "_singlejar": attr.label( + default = Label("//tools/jdk:singlejar"), + cfg = "exec", + allow_single_file = True, + executable = True, + ), + }, + outputs = { + "jar": "%{name}.jar", + }, + implementation = _java_single_jar, + doc = """ +Collects Java dependencies and jar files into a single jar + +`java_single_jar` collects Java dependencies and jar files into a single jar. +This is similar to java_binary with everything related to executables disabled, +and provides an alternative to the java_binary "deploy jar hack". + +## Example + +```skylark +load("//tools/build_defs/java_single_jar:java_single_jar.bzl", "java_single_jar") + +java_single_jar( + name = "my_single_jar", + deps = [ + "//java/com/google/foo", + "//java/com/google/bar", + ], +) +``` + +Outputs: + {name}.jar: A single jar containing all of the inputs. +""", +)