Move generated_file() writes to dedicated function.

This simply moves NinjaGeneratedFileTargetWriter::GenerateFile()
to its own helper function in a new source file. The new
implementation simply returns false on error instead of
calling g_scheduler->FailWithError().

This is a preparation CL for a fix for the associated bug
that will delay the writing of generate_file() targets that
have `collect_validations_metadata = true`.

Bug: 566346002
Change-Id: I588a3cce0ba6252c65e650a04cb813d885f7295a
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/27083
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/build/gen.py b/build/gen.py
index d9c4b1f..4f9cd32 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -863,6 +863,7 @@
               'src/gn/functions_target.cc',
               'src/gn/general_tool.cc',
               'src/gn/generated_file_target_generator.cc',
+              'src/gn/generated_file_writer.cc',
               'src/gn/group_target_generator.cc',
               'src/gn/header_checker.cc',
               'src/gn/import_manager.cc',
diff --git a/src/gn/generated_file_writer.cc b/src/gn/generated_file_writer.cc
new file mode 100644
index 0000000..5de819e
--- /dev/null
+++ b/src/gn/generated_file_writer.cc
@@ -0,0 +1,64 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "generated_file_writer.h"
+
+#include <ostream>
+#include <vector>
+
+#include "base/logging.h"
+#include "gn/err.h"
+#include "gn/output_conversion.h"
+#include "gn/source_file.h"
+#include "gn/string_output_buffer.h"
+#include "gn/target.h"
+#include "gn/trace.h"
+#include "gn/value.h"
+
+bool WriteGeneratedFileToDisk(const Target* target, Err* err) {
+  const Settings* settings = target->settings();
+
+  std::vector<SourceFile> outputs_as_sources;
+  target->action_values().GetOutputsAsSourceFiles(target, &outputs_as_sources);
+  CHECK(outputs_as_sources.size() == 1);
+
+  base::FilePath output =
+      settings->build_settings()->GetFullPath(outputs_as_sources[0]);
+  ScopedTrace trace(TraceItem::TRACE_FILE_WRITE_GENERATED,
+                    outputs_as_sources[0].value());
+  trace.SetToolchain(target->settings()->toolchain_label());
+
+  // If this is a metadata target, populate the write value with the appropriate
+  // data.
+  Value contents;
+  if (target->contents().type() == Value::NONE) {
+    // Origin is set to the outputs location, so that errors with this value
+    // get flagged on the right target.
+    CHECK(target->action_values().outputs().list().size() == 1U);
+    contents = Value(target->action_values().outputs().list()[0].origin(),
+                     Value::LIST);
+    TargetSet targets_walked;
+    ScopedTrace metadata_walk_trace(TraceItem::TRACE_WALK_METADATA,
+                                    target->label());
+    metadata_walk_trace.SetToolchain(target->settings()->toolchain_label());
+    if (!target->GetMetadata(target->data_keys(), target->walk_keys(),
+                             target->rebase(), /*deps_only = */ true,
+                             &contents.list_value(), &targets_walked, err)) {
+      return false;
+    }
+  } else {
+    contents = target->contents();
+  }
+
+  // Compute output.
+  StringOutputBuffer storage;
+  std::ostream out(&storage);
+  ConvertValueToOutput(settings, contents, target->output_conversion(), out,
+                       err);
+
+  if (err->has_error()) {
+    return false;
+  }
+  return storage.WriteToFileIfChanged(output, err);
+}
diff --git a/src/gn/generated_file_writer.h b/src/gn/generated_file_writer.h
new file mode 100644
index 0000000..833ed97
--- /dev/null
+++ b/src/gn/generated_file_writer.h
@@ -0,0 +1,14 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_GENERATED_FILE_WRITER_H_
+#define TOOLS_GN_GENERATED_FILE_WRITER_H_
+
+class Err;
+class Target;
+
+// Write the content of a given generated_file() target to disk.
+bool WriteGeneratedFileToDisk(const Target* target, Err* err);
+
+#endif  // TOOLS_GN_GENERATED_FILE_WRITER_H_
diff --git a/src/gn/ninja_generated_file_target_writer.cc b/src/gn/ninja_generated_file_target_writer.cc
index 6de8207..09aa271 100644
--- a/src/gn/ninja_generated_file_target_writer.cc
+++ b/src/gn/ninja_generated_file_target_writer.cc
@@ -4,6 +4,7 @@
 
 #include "gn/ninja_generated_file_target_writer.h"
 
+#include "gn/generated_file_writer.h"
 #include "gn/output_conversion.h"
 #include "gn/output_file.h"
 #include "gn/scheduler.h"
@@ -22,7 +23,10 @@
 
 void NinjaGeneratedFileTargetWriter::Run() {
   // Write the file.
-  GenerateFile();
+  Err err;
+  if (!WriteGeneratedFileToDisk(target_, &err)) {
+    g_scheduler->FailWithError(err);
+  }
 
   // A generated_file target should generate a phony target with dependencies
   // on each of the deps and data_deps in the target. The actual collection is
@@ -49,59 +53,3 @@
 
   WriteStampOrPhonyForTarget(output_files, data_output_files);
 }
-
-void NinjaGeneratedFileTargetWriter::GenerateFile() {
-  Err err;
-
-  std::vector<SourceFile> outputs_as_sources;
-  target_->action_values().GetOutputsAsSourceFiles(target_,
-                                                   &outputs_as_sources);
-  CHECK(outputs_as_sources.size() == 1);
-
-  base::FilePath output =
-      settings_->build_settings()->GetFullPath(outputs_as_sources[0]);
-  ScopedTrace trace(TraceItem::TRACE_FILE_WRITE_GENERATED,
-                    outputs_as_sources[0].value());
-  trace.SetToolchain(target_->settings()->toolchain_label());
-
-  // If this is a metadata target, populate the write value with the appropriate
-  // data.
-  Value contents;
-  if (target_->contents().type() == Value::NONE) {
-    // Origin is set to the outputs location, so that errors with this value
-    // get flagged on the right target.
-    CHECK(target_->action_values().outputs().list().size() == 1U);
-    contents = Value(target_->action_values().outputs().list()[0].origin(),
-                     Value::LIST);
-    TargetSet targets_walked;
-    ScopedTrace metadata_walk_trace(TraceItem::TRACE_WALK_METADATA,
-                                    target_->label());
-    trace.SetToolchain(target_->settings()->toolchain_label());
-    if (!target_->GetMetadata(target_->data_keys(), target_->walk_keys(),
-                              target_->rebase(), /*deps_only = */ true,
-                              &contents.list_value(), &targets_walked, &err)) {
-      g_scheduler->FailWithError(err);
-      return;
-    }
-  } else {
-    contents = target_->contents();
-  }
-
-  // Compute output.
-  StringOutputBuffer storage;
-  std::ostream out(&storage);
-  ConvertValueToOutput(settings_, contents, target_->output_conversion(), out,
-                       &err);
-
-  if (err.has_error()) {
-    g_scheduler->FailWithError(err);
-    return;
-  }
-
-  storage.WriteToFileIfChanged(output, &err);
-
-  if (err.has_error()) {
-    g_scheduler->FailWithError(err);
-    return;
-  }
-}
diff --git a/src/gn/ninja_generated_file_target_writer.h b/src/gn/ninja_generated_file_target_writer.h
index 3103388..d39f5fd 100644
--- a/src/gn/ninja_generated_file_target_writer.h
+++ b/src/gn/ninja_generated_file_target_writer.h
@@ -16,8 +16,6 @@
   void Run() override;
 
  private:
-  void GenerateFile();
-
   NinjaGeneratedFileTargetWriter(const NinjaGeneratedFileTargetWriter&) =
       delete;
   NinjaGeneratedFileTargetWriter& operator=(