Print ninja stdout live during the build

When running ninja stream stdout to the status writer.  This improves
the ninja -d explain behavior, and will also allow Soong to be put
into the ninja console pool letting it print timely output to the
console.

Bug:  80165685
Test: NINJA_ARGS="-d explain" m
Change-Id: I40f03fc01d837ad91d400eae378007a7ce807705
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 5c312bc..e435c53 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -15,7 +15,10 @@
 package build
 
 import (
+	"bufio"
+	"io"
 	"os/exec"
+	"strings"
 )
 
 // Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
@@ -139,3 +142,34 @@
 	st.Finish()
 	c.reportError(err)
 }
+
+// RunAndStreamOrFatal will run the command, while running print
+// any output, then handle any errors with a call to ctx.Fatal
+func (c *Cmd) RunAndStreamOrFatal() {
+	out, err := c.StdoutPipe()
+	if err != nil {
+		c.ctx.Fatal(err)
+	}
+	c.Stderr = c.Stdout
+
+	st := c.ctx.Status.StartTool()
+
+	c.StartOrFatal()
+
+	buf := bufio.NewReaderSize(out, 2*1024*1024)
+	for {
+		// Attempt to read whole lines, but write partial lines that are too long to fit in the buffer or hit EOF
+		line, err := buf.ReadString('\n')
+		if line != "" {
+			st.Print(strings.TrimSuffix(line, "\n"))
+		} else if err == io.EOF {
+			break
+		} else if err != nil {
+			c.ctx.Fatal(err)
+		}
+	}
+
+	err = c.Wait()
+	st.Finish()
+	c.reportError(err)
+}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 7994f3a..b41ac20 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -103,7 +103,7 @@
 	}()
 
 	ctx.Status.Status("Starting ninja...")
-	cmd.RunAndPrintOrFatal()
+	cmd.RunAndStreamOrFatal()
 }
 
 type statusChecker struct {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2ce1ac9..3388417 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -120,7 +120,7 @@
 			"--frontend_file", fifo,
 			"-f", filepath.Join(config.SoongOutDir(), file))
 		cmd.Sandbox = soongSandbox
-		cmd.RunAndPrintOrFatal()
+		cmd.RunAndStreamOrFatal()
 	}
 
 	ninja("minibootstrap", ".minibootstrap/build.ninja")