Deduplicate `Multi-Release` manifest entries

to prevent duplicate entries if set in both input jars and
`--deploy_manifest_lines`.

PiperOrigin-RevId: 370267467
diff --git a/src/tools/singlejar/combiners.cc b/src/tools/singlejar/combiners.cc
index 4b9e080..7b27ca8 100644
--- a/src/tools/singlejar/combiners.cc
+++ b/src/tools/singlejar/combiners.cc
@@ -185,6 +185,17 @@
 static const char *MULTI_RELEASE = "Multi-Release: true";
 static const size_t MULTI_RELEASE_LENGTH = strlen(MULTI_RELEASE);
 
+void ManifestCombiner::AppendLine(const std::string &line) {
+  if (line.find(MULTI_RELEASE, 0, MULTI_RELEASE_LENGTH) != std::string::npos) {
+    multi_release_ = true;
+    return;
+  }
+  concatenator_->Append(line);
+  if (line[line.size() - 1] != '\n') {
+    concatenator_->Append("\r\n");
+  }
+}
+
 bool ManifestCombiner::Merge(const CDH *cdh, const LH *lh) {
   TransientBytes bytes_;
   if (Z_NO_COMPRESSION == lh->compression_method()) {
@@ -221,8 +232,8 @@
 
 void *ManifestCombiner::OutputEntry(bool compress) {
   if (multi_release_) {
-    Append(MULTI_RELEASE);
+    concatenator_->Append(MULTI_RELEASE);
   }
-  Append("\r\n");
-  return Concatenator::OutputEntry(compress);
+  concatenator_->Append("\r\n");
+  return concatenator_->OutputEntry(compress);
 }
diff --git a/src/tools/singlejar/combiners.h b/src/tools/singlejar/combiners.h
index a1ad78f..a8e372e 100644
--- a/src/tools/singlejar/combiners.h
+++ b/src/tools/singlejar/combiners.h
@@ -137,17 +137,25 @@
 };
 
 // Combines the contents of the multiple manifests.
-class ManifestCombiner : public Concatenator {
+class ManifestCombiner : public Combiner {
  public:
   ManifestCombiner(const std::string &filename)
-      : Concatenator(filename), multi_release_(false) {}
+      : filename_(filename), multi_release_(false) {
+    concatenator_.reset(new Concatenator(filename_, false));
+  }
   ~ManifestCombiner() override;
 
-  void *OutputEntry(bool compress) override;
+  void AppendLine(const std::string &line);
 
   bool Merge(const CDH *cdh, const LH *lh) override;
 
+  void *OutputEntry(bool compress) override;
+
+  const std::string filename() const { return filename_; }
+
  private:
+  std::unique_ptr<Concatenator> concatenator_;
+  const std::string filename_;
   bool multi_release_;
   std::unique_ptr<Inflater> inflater_;
 };
diff --git a/src/tools/singlejar/combiners_test.cc b/src/tools/singlejar/combiners_test.cc
index ddbf8e2..737250a 100644
--- a/src/tools/singlejar/combiners_test.cc
+++ b/src/tools/singlejar/combiners_test.cc
@@ -272,6 +272,10 @@
     }
   }
 
+  // check that Multi-Release is de-duped, e.g. if present both in deps and
+  // deploy_manifest_lines
+  manifest_combiner.AppendLine("Multi-Release: true");
+
   // Create output, verify Local Header contents.
   LH *entry = reinterpret_cast<LH *>(manifest_combiner.OutputEntry(true));
   EXPECT_TRUE(entry->is());
diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc
index f71c9e4..87949a1 100644
--- a/src/tools/singlejar/output_jar.cc
+++ b/src/tools/singlejar/output_jar.cc
@@ -72,9 +72,8 @@
   known_members_.emplace(manifest_.filename(), EntryInfo{&manifest_});
   known_members_.emplace(protobuf_meta_handler_.filename(),
                          EntryInfo{&protobuf_meta_handler_});
-  manifest_.Append(
-      "Manifest-Version: 1.0\r\n"
-      "Created-By: singlejar\r\n");
+  manifest_.AppendLine("Manifest-Version: 1.0");
+  manifest_.AppendLine("Created-By: singlejar");
 }
 
 static std::string Basename(const std::string &path) {
@@ -127,9 +126,7 @@
 
   if (!options_->main_class.empty()) {
     build_properties_.AddProperty("main.class", options_->main_class);
-    manifest_.Append("Main-Class: ");
-    manifest_.Append(options_->main_class);
-    manifest_.Append("\r\n");
+    manifest_.AppendLine("Main-Class: " + options_->main_class);
   }
 
   // Copy CDS archive file (.jsa) if it is set.
@@ -139,10 +136,7 @@
 
   for (auto &manifest_line : options_->manifest_lines) {
     if (!manifest_line.empty()) {
-      manifest_.Append(manifest_line);
-      if (manifest_line[manifest_line.size() - 1] != '\n') {
-        manifest_.Append("\r\n");
-      }
+      manifest_.AppendLine(manifest_line);
     }
   }
 
@@ -1052,8 +1046,7 @@
   snprintf( cds_manifest_attr, sizeof(cds_manifest_attr),
     "Jsa-Offset: %ld", (long)aligned_offset); // NOLINT(runtime/int,
                                               // google-runtime-int)
-  manifest_.Append(cds_manifest_attr);
-  manifest_.Append("\r\n");
+  manifest_.AppendLine(cds_manifest_attr);
 
   // Add to build_properties
   build_properties_.AddProperty("cds.archive",