""" Definition of _java_single_jar. """ load("//java/common:java_common.bzl", "java_common") load("//java/common:java_info.bzl", "JavaInfo") 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) if hasattr(java_common, "JavaRuntimeClasspathInfo"): deploy_env_jars = depset(transitive = [ dep[java_common.JavaRuntimeClasspathInfo].runtime_classpath for dep in ctx.attr.deploy_env ]) excluded_jars = {jar: None for jar in deploy_env_jars.to_list()} if excluded_jars: inputs = depset([jar for jar in inputs.to_list() if jar not in excluded_jars]) args = ctx.actions.args() args.add_all("--sources", inputs) args.use_param_file("@%s") args.set_param_file_format("multiline") args.add_all("--deploy_manifest_lines", ctx.attr.deploy_manifest_lines) 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( 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.""", ), "deploy_manifest_lines": attr.string_list(doc = """ A list of lines to add to the META-INF/manifest.mf file."""), "deploy_env": attr.label_list( providers = [java_common.JavaRuntimeClasspathInfo] if hasattr(java_common, "JavaRuntimeClasspathInfo") else [], allow_files = False, doc = """ A list of `java_binary` or `java_single_jar` targets which represent the deployment environment for this binary. Set this attribute when building a plugin which will be loaded by another `java_binary`. `deploy_env` dependencies are excluded from the jar built by this rule.""", ), "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("//toolchains: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. """, )