Singlejar accepts a custom "Created-By" field as a runtime parameter

RELNOTES: Singlejar accepts runtime Created-By field
PiperOrigin-RevId: 455621799
Change-Id: Ie6d548b186a137e5b81d7c819f3f6f411956a9f7
diff --git a/src/tools/singlejar/options.cc b/src/tools/singlejar/options.cc
index 9fa4386..18d8537 100644
--- a/src/tools/singlejar/options.cc
+++ b/src/tools/singlejar/options.cc
@@ -58,7 +58,8 @@
       tokens->MatchAndSet("--multi_release", &multi_release) ||
       tokens->MatchAndSet("--hermetic_java_home", &hermetic_java_home) ||
       tokens->MatchAndSet("--add_exports", &add_exports) ||
-      tokens->MatchAndSet("--add_opens", &add_opens)) {
+      tokens->MatchAndSet("--add_opens", &add_opens) ||
+      tokens->MatchAndSet("--output_jar_creator", &output_jar_creator)) {
     return true;
   } else if (tokens->MatchAndSet("--build_info_file", &optarg)) {
     build_info_files.push_back(optarg);
diff --git a/src/tools/singlejar/options.h b/src/tools/singlejar/options.h
index 997dc7a..298772d 100644
--- a/src/tools/singlejar/options.h
+++ b/src/tools/singlejar/options.h
@@ -24,7 +24,8 @@
 class Options {
  public:
   Options()
-      : exclude_build_data(false),
+      : output_jar_creator("singlejar"),
+        exclude_build_data(false),
         force_compression(false),
         normalize_timestamps(false),
         add_missing_directories(false),
@@ -42,6 +43,7 @@
   void ParseCommandLine(int argc, const char *const argv[]);
 
   std::string output_jar;
+  std::string output_jar_creator;
   std::string main_class;
   std::string java_launcher;
   std::string cds_archive;
diff --git a/src/tools/singlejar/options_test.cc b/src/tools/singlejar/options_test.cc
index bd9b314..975ec46 100644
--- a/src/tools/singlejar/options_test.cc
+++ b/src/tools/singlejar/options_test.cc
@@ -158,3 +158,18 @@
   EXPECT_EQ(0UL, options.classpath_resources.size());
   EXPECT_EQ(1UL, options.include_prefixes.size());
 }
+
+TEST(OptionTest, CustomCreatedBy) {
+  const char *args[] = {"--output", "output_file", "--output_jar_creator",
+                        "CustomCreatedBy 123.456"};
+  Options options;
+  options.ParseCommandLine(arraysize(args), args);
+  EXPECT_EQ("CustomCreatedBy 123.456", options.output_jar_creator);
+}
+
+TEST(OptionTest, DefaultCreatedBy) {
+  const char *args[] = {"--output", "output_file"};
+  Options options;
+  options.ParseCommandLine(arraysize(args), args);
+  EXPECT_EQ("singlejar", options.output_jar_creator);
+}
diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc
index 0bfd1a0..397669c 100644
--- a/src/tools/singlejar/output_jar.cc
+++ b/src/tools/singlejar/output_jar.cc
@@ -72,8 +72,6 @@
   known_members_.emplace(manifest_.filename(), EntryInfo{&manifest_});
   known_members_.emplace(protobuf_meta_handler_.filename(),
                          EntryInfo{&protobuf_meta_handler_});
-  manifest_.AppendLine("Manifest-Version: 1.0");
-  manifest_.AppendLine("Created-By: singlejar");
 }
 
 static std::string Basename(const std::string &path) {
@@ -99,6 +97,10 @@
                            EntryInfo{&build_properties_});
   }
 
+  // Populate the manifest file.
+  manifest_.AppendLine("Manifest-Version: 1.0");
+  manifest_.AppendLine("Created-By: " + options_->output_jar_creator);
+
   // TODO(b/28294322): do we need to resolve the path to be absolute or
   // canonical?
   build_properties_.AddProperty("build.target", options_->output_jar.c_str());
diff --git a/src/tools/singlejar/output_jar.h b/src/tools/singlejar/output_jar.h
index d867488..e7f1f73 100644
--- a/src/tools/singlejar/output_jar.h
+++ b/src/tools/singlejar/output_jar.h
@@ -108,7 +108,6 @@
   // Write bytes to the output file, return true on success.
   bool WriteBytes(const void *buffer, size_t count);
 
-
   Options *options_;
   struct EntryInfo {
     EntryInfo(Combiner *combiner, int index = -1)
diff --git a/src/tools/singlejar/output_jar_simple_test.cc b/src/tools/singlejar/output_jar_simple_test.cc
index d689b71..7da857c 100644
--- a/src/tools/singlejar/output_jar_simple_test.cc
+++ b/src/tools/singlejar/output_jar_simple_test.cc
@@ -394,6 +394,19 @@
       manifest);
 }
 
+// --output_jar_creator option
+TEST_F(OutputJarSimpleTest, CreatedByFieldTest) {
+  string out_path = OutputFilePath("out.jar");
+  CreateOutput(out_path,
+               {"--output_jar_creator", "SingleJarTestValue 123.456"});
+  string manifest = GetEntryContents(out_path, "META-INF/MANIFEST.MF");
+  EXPECT_EQ(
+      "Manifest-Version: 1.0\r\n"
+      "Created-By: SingleJarTestValue 123.456\r\n"
+      "\r\n",
+      manifest);
+}
+
 // --deploy_manifest_lines option.
 TEST_F(OutputJarSimpleTest, DeployManifestLines) {
   string out_path = OutputFilePath("out.jar");