Relax the requirement that the cobalt registry output not be empty.

The new Cobalt private registry is currently empty, so the built proto
output for it is expectedly empty.

Bug: 3767
Change-Id: I6c50a995b2f32c64625f9912a009a43ffdcea218
diff --git a/metrics_registry.gni b/metrics_registry.gni
index 7da7f4e..0706464 100644
--- a/metrics_registry.gni
+++ b/metrics_registry.gni
@@ -18,6 +18,7 @@
 #   generate_rust: (default: false) Should we generate a rust crate.
 #   v1_project: (default: true) Is this a v1 project.
 #   directories: (default: [//third_party/cobalt_config]) The directories to parse.
+#   allow_empty_output: (default: false) Should we allow the output file to be empty.
 #
 # Note: Other args are forwarded to dart_library when generate_dart is true.
 #
@@ -133,6 +134,12 @@
     cobalt_config_dirs = [ "//third_party/cobalt_config" ]
   }
 
+  if (defined(invoker.allow_empty_output)) {
+    allow_empty_output = invoker.allow_empty_output
+  } else {
+    allow_empty_output = false
+  }
+
   out_format = ""
   generated_files = []
   if (generate_binarypb) {
@@ -228,6 +235,10 @@
       }
     }
 
+    if (allow_empty_output) {
+      args += [ "-allow_empty_output" ]
+    }
+
     if (defined(customer_id)) {
       args += [
         "-customer_id",
diff --git a/src/bin/config_parser/src/source_generator/writer.go b/src/bin/config_parser/src/source_generator/writer.go
index 111990d..ef5e6c8 100644
--- a/src/bin/config_parser/src/source_generator/writer.go
+++ b/src/bin/config_parser/src/source_generator/writer.go
@@ -14,17 +14,18 @@
 )
 
 var (
-	addFileSuffix = flag.Bool("add_file_suffix", false, "Append the out_format to the out_file, even if there is only one out_format specified")
-	outFile       = flag.String("output_file", "", "File to which the serialized config should be written. Defaults to stdout. When multiple output formats are specified, it will append the format to the filename")
-	outFilename   = flag.String("out_filename", "", "The base name to use for writing files. Should not be used with output_file.")
-	outDir        = flag.String("out_dir", "", "The directory into which files should be written.")
-	outFormat     = flag.String("out_format", "bin", "Specifies the output formats (separated by ' '). Supports 'bin' (serialized proto), 'b64' (serialized proto to base 64), 'cpp' (a C++ file containing a variable with a base64-encoded serialized proto.) 'dart' (a Dart library), 'json' (a JSON object), and 'rust' (a rust crate)")
-	forTesting    = flag.Bool("for_testing", false, "Generates a constant for each report ID. Report names should be unique in the registry.")
-	namespace     = flag.String("namespace", "", "When using the 'cpp', 'rust', or 'go' output format, this will specify the period-separated namespace within which the config variable must be placed (this will be transformed into an underscore-separated package name for go).")
-	goPackageName = flag.String("go_package", "", "When using the 'go' output format, this will specify the package for generated code.")
-	dartOutDir    = flag.String("dart_out_dir", "", "The directory to write dart files to (if different from out_dir)")
-	varName       = flag.String("var_name", "config", "When using the 'cpp' or 'dart' output format, this will specify the variable name to be used in the output.")
-	checkOnly     = flag.Bool("check_only", false, "Only check that the configuration is valid.")
+	addFileSuffix    = flag.Bool("add_file_suffix", false, "Append the out_format to the out_file, even if there is only one out_format specified")
+	outFile          = flag.String("output_file", "", "File to which the serialized config should be written. Defaults to stdout. When multiple output formats are specified, it will append the format to the filename")
+	outFilename      = flag.String("out_filename", "", "The base name to use for writing files. Should not be used with output_file.")
+	outDir           = flag.String("out_dir", "", "The directory into which files should be written.")
+	outFormat        = flag.String("out_format", "bin", "Specifies the output formats (separated by ' '). Supports 'bin' (serialized proto), 'b64' (serialized proto to base 64), 'cpp' (a C++ file containing a variable with a base64-encoded serialized proto.) 'dart' (a Dart library), 'json' (a JSON object), and 'rust' (a rust crate)")
+	forTesting       = flag.Bool("for_testing", false, "Generates a constant for each report ID. Report names should be unique in the registry.")
+	namespace        = flag.String("namespace", "", "When using the 'cpp', 'rust', or 'go' output format, this will specify the period-separated namespace within which the config variable must be placed (this will be transformed into an underscore-separated package name for go).")
+	goPackageName    = flag.String("go_package", "", "When using the 'go' output format, this will specify the package for generated code.")
+	dartOutDir       = flag.String("dart_out_dir", "", "The directory to write dart files to (if different from out_dir)")
+	varName          = flag.String("var_name", "config", "When using the 'cpp' or 'dart' output format, this will specify the variable name to be used in the output.")
+	checkOnly        = flag.Bool("check_only", false, "Only check that the configuration is valid.")
+	allowEmptyOutput = flag.Bool("allow_empty_output", false, "Relax the requirement that the cobalt registry output not be empty.")
 )
 
 // checkFlags verifies that the specified flags are compatible with each other.
@@ -95,11 +96,11 @@
 		}
 
 		// Check that the output file is not empty.
-		if len(configBytes) == 0 {
+		if !*allowEmptyOutput && len(configBytes) == 0 {
 			return fmt.Errorf("Output file is empty.")
 		}
 
-		// If no errors have occured yet and checkOnly was set, we don't need to write anything.
+		// If no errors have occurred yet and checkOnly was set, we don't need to write anything.
 		if *checkOnly {
 			continue
 		}
diff --git a/src/logger/BUILD.gn b/src/logger/BUILD.gn
index 7920e39..55dc3e2 100644
--- a/src/logger/BUILD.gn
+++ b/src/logger/BUILD.gn
@@ -383,6 +383,7 @@
   public_deps = [
     ":project_context",
     "$cobalt_root/src/pb",
+    "test_registries:empty_test_registry",
     "test_registries:multiple_project_context_test_registry_directories",
     "test_registries:project_context_test_registry",
     "//third_party/abseil-cpp/absl/strings",
diff --git a/src/logger/test_registries/BUILD.gn b/src/logger/test_registries/BUILD.gn
index 6213847..5bf186b 100644
--- a/src/logger/test_registries/BUILD.gn
+++ b/src/logger/test_registries/BUILD.gn
@@ -121,3 +121,15 @@
   generate_binarypb = false
   generate_cc = true
 }
+
+metrics_registry("empty_test_registry") {
+  global = true
+  allow_empty_output = true
+  skip_validation = true
+  for_testing = true
+  directories = [ "empty_test_registry" ]
+  namespace = "cobalt.logger"
+  var_name = "cobalt_registry_base64"
+
+  generate_binarypb = true
+}
diff --git a/src/logger/test_registries/empty_test_registry/projects.yaml b/src/logger/test_registries/empty_test_registry/projects.yaml
new file mode 100644
index 0000000..8344094
--- /dev/null
+++ b/src/logger/test_registries/empty_test_registry/projects.yaml
@@ -0,0 +1,4 @@
+- customer_name: CustomerE
+  customer_id: 9876
+
+  projects: