# Copyright 2026 The Bazel 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.
"""Definition of the java_single_jar rule."""

load("//java/common:java_common.bzl", "java_common")
load("//java/common:java_info.bzl", "JavaInfo")
load("//java/common:java_semantics.bzl", "semantics")
load("//java/common/rules/impl:java_helper.bzl", "helper")

# copybara: default visibility

def _single_jar_inputs(deps, deploy_env):
    transitive_inputs = []
    for dep in 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 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])
    return inputs

def _bazel_java_single_jar_impl(ctx):
    inputs = _single_jar_inputs(ctx.attr.deps, ctx.attr.deploy_env)

    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.output)
    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 and ctx.attr.stamp == 1:
        fail("Enabling stamping has not effect with exclude_build_data enabled")

    build_info_files = []
    if ctx.attr.exclude_build_data:
        args.add("--exclude_build_data")
    else:
        build_info_files = helper.get_build_info(ctx, ctx.attr.stamp)
        args.add_all(build_info_files, before_each = "--build_info_file")
    if ctx.attr.multi_release:
        args.add("--multi_release")

    if ctx.attr.exclude_pattern:
        args.add("--exclude_pattern", ctx.attr.exclude_pattern)

    ctx.actions.run(
        inputs = depset(build_info_files, transitive = [inputs]),
        outputs = [ctx.outputs.output],
        arguments = [args],
        progress_message = "Merging into %s" % ctx.outputs.output.short_path,
        mnemonic = "JavaSingleJar",
        executable = ctx.executable._singlejar,
        use_default_shell_env = True,
    )

    files = depset([ctx.outputs.output])
    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

bazel_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 <code>META-INF/manifest.mf</code> 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."""),
        "exclude_pattern": attr.string(default = "", doc = """
            A regex pattern of files to exclude from the jar.
        """),
        "_singlejar": attr.label(
            default = Label("//toolchains:singlejar"),
            cfg = "exec",
            allow_single_file = True,
            executable = True,
        ),
        "output": attr.output(),
        "stamp": attr.int(
            doc = """
              Whether to embed extra Bazel build information into the build_data.properties file:
                * `stamp = 1`: Always embed Bazel build information, even in `--nostamp` builds.
                * `stamp = 0`: Embed Bazel build information with constant values, even in `--stamp` builds.
                * `stamp = -1`: Embedding of Bazel build information is controlled by the `--[no]stamp` flag.

                Note: whether the output contains the build_data.properties file is controlled
                 by the `exclude_build_data` attribute.
                """,
            default = 0,
            values = [-1, 0, 1],
        ),
        "_build_info_translator": attr.label(default = semantics.BUILD_INFO_TRANSLATOR_LABEL),
    },
    implementation = _bazel_java_single_jar_impl,
    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.
""",
)
