Update pkg_war.bzl to match the version in Gerrit core

In addition to the adaptations done, the support for the old package
structure, i.e. directory structures started with `gerrit-` and not
`java/`, has been removed.

Change-Id: I229760ea46acab33dd97148f1bb2a9040322436b
diff --git a/tools/pkg_war.bzl b/tools/pkg_war.bzl
index eaffc9b..0691ec2 100644
--- a/tools/pkg_war.bzl
+++ b/tools/pkg_war.bzl
@@ -1,4 +1,4 @@
-# Copyright (C) 2017 The Android Open Source Project
+# Copyright (C) 2016 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,27 +13,81 @@
 # limitations under the License.
 
 # War packaging.
+
 load("@rules_java//java:defs.bzl", "JavaInfo")
 
+jar_filetype = [".jar"]
+
+# Special prefix added by rules_jvm_external.jvm_import() to stamped jars
+# https://github.com/bazel-contrib/rules_jvm_external/blob/6.9/private/rules/jvm_import.bzl#L32
+PROCESSED_PREFIX = "processed_"
+
+def war_jar_name(f):
+    """Return the jar file name as it will appear inside the WAR."""
+    raw = f.basename
+    if raw.startswith(PROCESSED_PREFIX):
+        raw = raw[len(PROCESSED_PREFIX):]
+
+    sp = f.short_path
+
+    # Rename ONLY caffeine's "guava" artifact (not Google Guava)
+    # Matches: .../com/github/ben-manes/caffeine/guava/<ver>/processed_guava-<ver>.jar
+    if "/com/github/ben-manes/caffeine/guava/" in sp and raw.startswith("guava-") and raw.endswith(".jar"):
+        raw = "caffeine-" + raw  # -> caffeine-guava-<ver>.jar
+
+    # Keep existing Gerrit naming rules
+    if sp.startswith("gerrit-"):
+        raw = sp.split("/")[0] + "-" + raw
+    elif sp.startswith("java/"):
+        raw = sp[5:].replace("/", "_")
+
+    return raw
+
+def normalize_jar_id(jar_name):
+    """Version-agnostic jar identity used for allowlists/inventories."""
+    n = jar_name
+    if n.endswith(".jar"):
+        n = n[:-4]
+    i = n.rfind("-")
+
+    # Strip trailing "-<version-ish>" where the suffix begins with a digit.
+    if i > 0 and n[i + 1:i + 2].isdigit():
+        n = n[:i]
+    return n
+
+def should_skip_packaged_jar(ctx, jar_name):
+    """jar_name must be the post-processed name (war_jar_name output)."""
+    for pfx in ctx.attr.exclude_jar_prefixes:
+        if jar_name.startswith(pfx):
+            return True
+    return False
+
+def is_third_party_jar_id(ctx, jar_id):
+    """Return True if jar_id should be tracked in third-party allowlists."""
+    if jar_id in ctx.attr.exclude_third_party_jar:
+        return False
+    for pfx in ctx.attr.exclude_third_party_jar_prefix:
+        if jar_id.startswith(pfx):
+            return False
+    return True
+
 def _add_context(in_file, output):
-    input_path = in_file.path
     return [
-        "unzip -qd %s %s" % (output, input_path),
+        "unzip -qd %s %s" % (output, in_file.path),
     ]
 
-def _add_file(name, in_file, output):
-    output_path = output
-    input_path = in_file.path
-    short_path = in_file.short_path
-    n = in_file.basename
+def _add_jar_file(in_file, output):
+    raw = war_jar_name(in_file)
+    output_path = output + raw
 
-    if n != "web.xml" and short_path.startswith("%s-" % name):
-        n = short_path.split("/")[0] + "-" + n
+    return _add_file(in_file.path, output_path)
 
-    output_path = output_path + n
+def _add_web_xml_file(in_file, output):
+    return _add_file(in_file.path, output + in_file.basename)
 
+def _add_file(in_file, output):
     return [
-        "test -L %s || ln -s $(pwd)/%s %s" % (output_path, input_path, output_path),
+        "test -L %s || ln -s $(pwd)/%s %s" % (output, in_file, output),
     ]
 
 def _make_war(input_dir, output):
@@ -41,7 +95,7 @@
         "root=$(pwd)",
         "cd %s" % input_dir,
         "find . -exec touch -t 198001010000 '{}' ';' 2> /dev/null",
-        "zip -9qr ${root}/%s ." % (output.path),
+        "zip -X -9qr ${root}/%s ." % (output.path),
     ])
 
 def _war_impl(ctx):
@@ -49,12 +103,25 @@
     build_output = war.path + ".build_output"
     inputs = []
 
+    # Metadata we expose for checks/tools.
+    jar_entries = []
+    jar_ids = []
+
+    # Create war layout
     cmd = [
         "set -e;rm -rf " + build_output,
         "mkdir -p " + build_output,
         "mkdir -p %s/WEB-INF/lib" % build_output,
+        "mkdir -p %s/WEB-INF/pgm-lib" % build_output,
     ]
 
+    # Add web.xml files
+    if ctx.attr.web_xml:
+        for web_xml in ctx.attr.web_xml.files.to_list():
+            inputs.append(web_xml)
+            cmd = cmd + _add_web_xml_file(web_xml, build_output + "/WEB-INF/")
+
+    # Add runtime libs
     transitive_libs = []
     for l in ctx.attr.libs:
         if JavaInfo in l:
@@ -62,16 +129,41 @@
         elif hasattr(l, "files"):
             transitive_libs.append(l.files)
 
-    transitive_lib_deps = depset(transitive = transitive_libs)
-    for dep in transitive_lib_deps.to_list():
-        cmd = cmd + _add_file(ctx.attr.name, dep, build_output + "/WEB-INF/lib/")
+    for dep in depset(transitive = transitive_libs).to_list():
+        packaged = war_jar_name(dep)
+        if should_skip_packaged_jar(ctx, packaged):
+            continue
+
+        cmd += _add_jar_file(dep, build_output + "/WEB-INF/lib/")
         inputs.append(dep)
 
-    if ctx.attr.web_xml:
-        for web_xml in ctx.attr.web_xml.files.to_list():
-            inputs.append(web_xml)
-            cmd = cmd + _add_file(ctx.attr.name, web_xml, build_output + "/WEB-INF/")
+        jar_entries.append("WEB-INF/lib/" + packaged)
 
+        jid = normalize_jar_id(packaged)
+        if is_third_party_jar_id(ctx,jid):
+            jar_ids.append(jid)
+
+    # Add pgm libs
+    transitive_pgmlibs = []
+    for l in ctx.attr.pgmlibs:
+        transitive_pgmlibs.append(l[JavaInfo].transitive_runtime_jars)
+
+    for dep in depset(transitive = transitive_pgmlibs).to_list():
+        packaged = war_jar_name(dep)
+        if should_skip_packaged_jar(ctx, packaged):
+            continue
+
+        if dep not in inputs:
+            cmd += _add_jar_file(dep, build_output + "/WEB-INF/pgm-lib/")
+            inputs.append(dep)
+
+            jar_entries.append("WEB-INF/pgm-lib/" + packaged)
+
+            jid = normalize_jar_id(packaged)
+            if is_third_party_jar_id(ctx, jid):
+                jar_ids.append(jid)
+
+    # Add context
     transitive_context_libs = []
     if ctx.attr.context:
         for jar in ctx.attr.context:
@@ -79,11 +171,25 @@
                 transitive_context_libs.append(jar[JavaInfo].transitive_runtime_jars)
             elif hasattr(jar, "files"):
                 transitive_context_libs.append(jar.files)
-    transitive_context_deps = depset(transitive = transitive_context_libs)
-    for dep in transitive_context_deps.to_list():
-        cmd = cmd + _add_context(dep, build_output)
+
+    for dep in depset(transitive = transitive_context_libs).to_list():
+        cmd += _add_context(dep, build_output)
         inputs.append(dep)
 
+    # Write deterministic manifests for checks.
+    #
+    # NOTE: The manifests are produced as independent actions.
+    # Bazel will only execute the actions needed for the requested output,
+    # so building *.war.entries.txt does not materialize the WAR.
+    ctx.actions.write(
+        output = ctx.outputs.jars,
+        content = "\n".join(sorted(depset(jar_ids).to_list())) + "\n",
+    )
+    ctx.actions.write(
+        output = ctx.outputs.entries,
+        content = "\n".join(sorted(jar_entries)) + "\n",
+    )
+
     # Add zip war
     cmd.append(_make_war(build_output, war))
 
@@ -95,16 +201,29 @@
         use_default_shell_env = True,
     )
 
+    return [
+        DefaultInfo(files = depset([war, ctx.outputs.jars, ctx.outputs.entries])),
+    ]
+
 # context: go to the root directory
 # libs: go to the WEB-INF/lib directory
+# pgmlibs: go to the WEB-INF/pgm-lib directory
 # web_xml: go to the WEB-INF directory
 _pkg_war = rule(
     attrs = {
         "context": attr.label_list(allow_files = True),
-        "libs": attr.label_list(allow_files = [".jar"]),
+        "libs": attr.label_list(allow_files = jar_filetype),
+        "pgmlibs": attr.label_list(allow_files = False),
         "web_xml": attr.label(allow_files = True),
+        "exclude_jar_prefixes": attr.string_list(),
+        "exclude_third_party_jar": attr.string_list(),
+        "exclude_third_party_jar_prefix": attr.string_list(),
     },
-    outputs = {"war": "%{name}.war"},
+    outputs = {
+        "war": "%{name}.war",
+        "jars": "%{name}.war.jars.txt",
+        "entries": "%{name}.war.entries.txt",
+    },
     implementation = _war_impl,
 )