Add build progress in Soong UI
Soong UI generates a proto file named build_progress.pb in $(OUT_DIR)
output directory that contains build action numbers (how many are executing,
finished and total) during the course of a build. This is for external
systems that invokes the Platform Build Systems and would like to know
the completion status.
Bug: b/150401146
Test: Wrote a bash script that continuously read the
build_progress.pb file and computed the build completed percentage
while building the aosp_arm-eng target. Compared the percentage between
the Soong output console and the one reported by the bash script.
Change-Id: I7c7347bc8e41958093892d8e2731c4f4169937dd
diff --git a/ui/status/log.go b/ui/status/log.go
index d407248..4e27641 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -20,12 +20,14 @@
"fmt"
"io"
"io/ioutil"
+ "os"
"strings"
"github.com/golang/protobuf/proto"
"android/soong/ui/logger"
"android/soong/ui/status/build_error_proto"
+ "android/soong/ui/status/build_progress_proto"
)
type verboseLog struct {
@@ -198,3 +200,75 @@
func (e *errorProtoLog) Write(p []byte) (int, error) {
return 0, errors.New("not supported")
}
+
+type buildProgressLog struct {
+ filename string
+ log logger.Logger
+ failedActions uint64
+}
+
+func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
+ return &buildProgressLog{
+ filename: filename,
+ log: log,
+ failedActions: 0,
+ }
+}
+
+func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
+ if result.Error != nil {
+ b.failedActions++
+ }
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) Flush() {
+ //Not required.
+}
+
+func (b *buildProgressLog) Message(level MsgLevel, message string) {
+ // Not required.
+}
+
+func (b *buildProgressLog) Write(p []byte) (int, error) {
+ return 0, errors.New("not supported")
+}
+
+func (b *buildProgressLog) updateCounters(counts Counts) {
+ err := writeToFile(
+ &soong_build_progress_proto.BuildProgress{
+ CurrentActions: proto.Uint64(uint64(counts.RunningActions)),
+ FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
+ TotalActions: proto.Uint64(uint64(counts.TotalActions)),
+ FailedActions: proto.Uint64(b.failedActions),
+ },
+ b.filename,
+ )
+ if err != nil {
+ b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
+ }
+}
+
+func writeToFile(pb proto.Message, outputPath string) (err error) {
+ data, err := proto.Marshal(pb)
+ if err != nil {
+ return err
+ }
+
+ tempPath := outputPath + ".tmp"
+ err = ioutil.WriteFile(tempPath, []byte(data), 0644)
+ if err != nil {
+ return err
+ }
+
+ err = os.Rename(tempPath, outputPath)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}