xref: /aosp_15_r20/external/bazelbuild-rules_java/java/java_single_jar.bzl (revision abe8e1b943c923005d847f1e3cf6637de4ed1a1f)
1""" Definition of _java_single_jar. """
2
3load("//java/common:java_common.bzl", "java_common")
4load("//java/common:java_info.bzl", "JavaInfo")
5
6def _java_single_jar(ctx):
7    transitive_inputs = []
8    for dep in ctx.attr.deps:
9        if JavaInfo in dep:
10            info = dep[JavaInfo]
11            transitive_inputs.append(info.transitive_runtime_jars)
12            if hasattr(info, "compilation_info"):
13                compilation_info = info.compilation_info
14                if hasattr(compilation_info, "runtime_classpath"):
15                    transitive_inputs.append(compilation_info.runtime_classpath)
16        else:
17            files = []
18            for f in dep[DefaultInfo].files.to_list():
19                if not f.extension == "jar":
20                    fail("unexpected file type in java_single_jar.deps: %s" % f.path)
21                files.append(f)
22            transitive_inputs.append(depset(files))
23    inputs = depset(transitive = transitive_inputs)
24
25    if hasattr(java_common, "JavaRuntimeClasspathInfo"):
26        deploy_env_jars = depset(transitive = [
27            dep[java_common.JavaRuntimeClasspathInfo].runtime_classpath
28            for dep in ctx.attr.deploy_env
29        ])
30        excluded_jars = {jar: None for jar in deploy_env_jars.to_list()}
31        if excluded_jars:
32            inputs = depset([jar for jar in inputs.to_list() if jar not in excluded_jars])
33
34    args = ctx.actions.args()
35    args.add_all("--sources", inputs)
36    args.use_param_file("@%s")
37    args.set_param_file_format("multiline")
38    args.add_all("--deploy_manifest_lines", ctx.attr.deploy_manifest_lines)
39    args.add("--output", ctx.outputs.jar)
40    args.add("--normalize")
41
42    # Deal with limitation of singlejar flags: tool's default behavior is
43    # "no", but you get that behavior only by absence of compression flags.
44    if ctx.attr.compress == "preserve":
45        args.add("--dont_change_compression")
46    elif ctx.attr.compress == "yes":
47        args.add("--compression")
48    elif ctx.attr.compress == "no":
49        pass
50    else:
51        fail("\"compress\" attribute (%s) must be: yes, no, preserve." % ctx.attr.compress)
52
53    if ctx.attr.exclude_build_data:
54        args.add("--exclude_build_data")
55    if ctx.attr.multi_release:
56        args.add("--multi_release")
57
58    ctx.actions.run(
59        inputs = inputs,
60        outputs = [ctx.outputs.jar],
61        arguments = [args],
62        progress_message = "Merging into %s" % ctx.outputs.jar.short_path,
63        mnemonic = "JavaSingleJar",
64        executable = ctx.executable._singlejar,
65    )
66
67    files = depset([ctx.outputs.jar])
68    providers = [DefaultInfo(
69        files = files,
70        runfiles = ctx.runfiles(transitive_files = files),
71    )]
72    if hasattr(java_common, "JavaRuntimeClasspathInfo"):
73        providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = inputs))
74    return providers
75
76java_single_jar = rule(
77    attrs = {
78        "deps": attr.label_list(
79            allow_files = True,
80            doc = """
81                The Java targets (including java_import and java_library) to collect
82                transitive dependencies from. Runtime dependencies are collected via
83                deps, exports, and runtime_deps. Resources are also collected.
84                Native cc_library or java_wrap_cc dependencies are not.""",
85        ),
86        "deploy_manifest_lines": attr.string_list(doc = """
87          A list of lines to add to the <code>META-INF/manifest.mf</code> file."""),
88        "deploy_env": attr.label_list(
89            providers = [java_common.JavaRuntimeClasspathInfo] if hasattr(java_common, "JavaRuntimeClasspathInfo") else [],
90            allow_files = False,
91            doc = """
92            A list of `java_binary` or `java_single_jar` targets which represent
93            the deployment environment for this binary.
94
95            Set this attribute when building a plugin which will be loaded by another
96            `java_binary`.
97
98            `deploy_env` dependencies are excluded from the jar built by this rule.""",
99        ),
100        "compress": attr.string(default = "preserve", doc = """
101            Whether to always deflate ("yes"), always store ("no"), or pass
102            through unmodified ("preserve"). The default is "preserve", and is the
103            most efficient option -- no extra work is done to inflate or deflate."""),
104        "exclude_build_data": attr.bool(default = True, doc = """
105            Whether to omit the build-data.properties file generated
106            by default."""),
107        "multi_release": attr.bool(default = True, doc = """Whether to enable Multi-Release output jars."""),
108        "_singlejar": attr.label(
109            default = Label("//toolchains:singlejar"),
110            cfg = "exec",
111            allow_single_file = True,
112            executable = True,
113        ),
114    },
115    outputs = {
116        "jar": "%{name}.jar",
117    },
118    implementation = _java_single_jar,
119    doc = """
120Collects Java dependencies and jar files into a single jar
121
122`java_single_jar` collects Java dependencies and jar files into a single jar.
123This is similar to java_binary with everything related to executables disabled,
124and provides an alternative to the java_binary "deploy jar hack".
125
126## Example
127
128```skylark
129load("//tools/build_defs/java_single_jar:java_single_jar.bzl", "java_single_jar")
130
131java_single_jar(
132    name = "my_single_jar",
133    deps = [
134        "//java/com/google/foo",
135        "//java/com/google/bar",
136    ],
137)
138```
139
140Outputs:
141  {name}.jar: A single jar containing all of the inputs.
142""",
143)
144