internal/cmd/generate-types: add outfile flag

Add an outfile flag that specifies that the contents of
the provided file should generated to stdout.
When using this mode, it only generates one file at a time
and does not modify any files on disk.

Change-Id: I80ba1764a7f0ceb180b8b54f4197dd57fec86434
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/263625
Trust: Joe Tsai <joetsai@digital-static.net>
Reviewed-by: Patrik Nyblom <pnyb@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/cmd/generate-types/main.go b/internal/cmd/generate-types/main.go
index d37bc82..c525067 100644
--- a/internal/cmd/generate-types/main.go
+++ b/internal/cmd/generate-types/main.go
@@ -24,19 +24,23 @@
 
 var (
 	run      bool
+	outfile  string
 	repoRoot string
 )
 
 func main() {
 	flag.BoolVar(&run, "execute", false, "Write generated files to destination.")
+	flag.StringVar(&outfile, "outfile", "", "Write this specific file to stdout.")
 	flag.Parse()
 
 	// Determine repository root path.
-	out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
-	check(err)
-	repoRoot = strings.TrimSpace(string(out))
+	if outfile == "" {
+		out, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
+		check(err)
+		repoRoot = strings.TrimSpace(string(out))
+		chdirRoot()
+	}
 
-	chdirRoot()
 	writeSource("internal/filedesc/desc_list_gen.go", generateDescListTypes())
 	writeSource("internal/impl/codec_gen.go", generateImplCodec())
 	writeSource("internal/impl/message_reflect_gen.go", generateImplMessage())
@@ -235,6 +239,13 @@
 		b = []byte(s)
 	}
 
+	if outfile != "" {
+		if outfile == file {
+			os.Stdout.Write(b)
+		}
+		return
+	}
+
 	absFile := filepath.Join(repoRoot, file)
 	if run {
 		prev, _ := ioutil.ReadFile(absFile)