[fint] Add automatic_gen behavior

If automatic_gen is set and build.ninja exists in the build directory,
do not run `gn gen`. This will save time on some incremental builds.

Bug: 81011
Change-Id: I74521ff995feadc2dff6fbab86c8c81f247bd73e
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/559842
Commit-Queue: Anthony Fandrianto <atyfto@google.com>
Reviewed-by: Oliver Newman <olivernewman@google.com>
diff --git a/tools/integration/fint/proto/static.desc.pb b/tools/integration/fint/proto/static.desc.pb
index 39fec83..d7d8cd6 100644
--- a/tools/integration/fint/proto/static.desc.pb
+++ b/tools/integration/fint/proto/static.desc.pb
Binary files differ
diff --git a/tools/integration/fint/proto/static.pb.go b/tools/integration/fint/proto/static.pb.go
index 38de021..9ecc002 100644
--- a/tools/integration/fint/proto/static.pb.go
+++ b/tools/integration/fint/proto/static.pb.go
@@ -213,6 +213,9 @@
 	EnableRbe bool `protobuf:"varint,31,opt,name=enable_rbe,json=enableRbe,proto3" json:"enable_rbe,omitempty"`
 	// Whether we're performing an incremental build.
 	Incremental bool `protobuf:"varint,32,opt,name=incremental,proto3" json:"incremental,omitempty"`
+	// Whether to let Ninja determine when to run gn gen instead of
+	// unconditionally running it.
+	AutomaticGen bool `protobuf:"varint,33,opt,name=automatic_gen,json=automaticGen,proto3" json:"automatic_gen,omitempty"`
 }
 
 func (x *Static) Reset() {
@@ -471,11 +474,18 @@
 	return false
 }
 
+func (x *Static) GetAutomaticGen() bool {
+	if x != nil {
+		return x.AutomaticGen
+	}
+	return false
+}
+
 var File_static_proto protoreflect.FileDescriptor
 
 var file_static_proto_rawDesc = []byte{
 	0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04,
-	0x66, 0x69, 0x6e, 0x74, 0x22, 0xf4, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12,
+	0x66, 0x69, 0x6e, 0x74, 0x22, 0x99, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12,
 	0x31, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
 	0x0e, 0x32, 0x15, 0x2e, 0x66, 0x69, 0x6e, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x2e,
 	0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x52, 0x08, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69,
@@ -555,18 +565,20 @@
 	0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
 	0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x62, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x63,
 	0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0x20, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b,
-	0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x22, 0x3c, 0x0a, 0x08, 0x4f,
-	0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4f, 0x50, 0x54, 0x49, 0x4d,
-	0x49, 0x5a, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10,
-	0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07,
-	0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x02, 0x22, 0x30, 0x0a, 0x04, 0x41, 0x72, 0x63,
-	0x68, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
-	0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34,
-	0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x36, 0x34, 0x10, 0x02, 0x42, 0x35, 0x5a, 0x33, 0x67,
-	0x6f, 0x2e, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x64, 0x65, 0x76, 0x2f, 0x66, 0x75,
-	0x63, 0x68, 0x73, 0x69, 0x61, 0x2f, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65,
-	0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x69, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x61,
+	0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x5f, 0x67, 0x65, 0x6e, 0x18, 0x21, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x47, 0x65, 0x6e,
+	0x22, 0x3c, 0x0a, 0x08, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x14,
+	0x4f, 0x50, 0x54, 0x49, 0x4d, 0x49, 0x5a, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
+	0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10,
+	0x01, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x10, 0x02, 0x22, 0x30,
+	0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x52, 0x43, 0x48, 0x5f, 0x55,
+	0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05,
+	0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x36, 0x34, 0x10, 0x02,
+	0x42, 0x35, 0x5a, 0x33, 0x67, 0x6f, 0x2e, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x64,
+	0x65, 0x76, 0x2f, 0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2f, 0x74, 0x6f, 0x6f, 0x6c, 0x73,
+	0x2f, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x69, 0x6e,
+	0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/tools/integration/fint/proto/static.proto b/tools/integration/fint/proto/static.proto
index 9bc3091..dde6ee4 100644
--- a/tools/integration/fint/proto/static.proto
+++ b/tools/integration/fint/proto/static.proto
@@ -138,4 +138,8 @@
 
   // Whether we're performing an incremental build.
   bool incremental = 32;
+
+  // Whether to let Ninja determine when to run gn gen instead of
+  // unconditionally running it.
+  bool automatic_gen = 33;
 }
diff --git a/tools/integration/fint/set.go b/tools/integration/fint/set.go
index 7ba35014..cfd5970 100644
--- a/tools/integration/fint/set.go
+++ b/tools/integration/fint/set.go
@@ -82,11 +82,28 @@
 	if contextSpec.ArtifactDir != "" {
 		artifacts.GnTracePath = filepath.Join(contextSpec.ArtifactDir, "gn_trace.json")
 	}
-	genStdout, err := runGen(ctx, runner, staticSpec, contextSpec, platform, artifacts.GnTracePath, genArgs)
-	if err != nil {
-		artifacts.FailureSummary = genStdout
-		return artifacts, err
+
+	var skipGen bool
+	if staticSpec.AutomaticGen {
+		// If the build directory is already seeded, let ninja (when run by
+		//`fint build`) determine whether or not to run `gn gen`. It may not be
+		// necessary for some incremental builds, and skipping it saves time.
+		exists, err := osmisc.FileExists(filepath.Join(contextSpec.BuildDir, "build.ninja"))
+		if err != nil {
+			return nil, fmt.Errorf("failed to check if build.ninja exists: %w", err)
+		}
+		if exists {
+			skipGen = true
+		}
 	}
+	if !skipGen {
+		genStdout, err := runGen(ctx, runner, staticSpec, contextSpec, platform, artifacts.GnTracePath, genArgs)
+		if err != nil {
+			artifacts.FailureSummary = genStdout
+			return artifacts, err
+		}
+	}
+
 	// Only run build graph analysis if the result will be emitted via
 	// artifacts, and if we actually care about checking the result.
 	if contextSpec.ArtifactDir != "" && staticSpec.SkipIfUnaffected {