Merge "Highlight build failures in soong output" into main

This commit is contained in:
Treehugger Robot
2024-07-18 20:13:15 +00:00
committed by Gerrit Code Review
3 changed files with 28 additions and 17 deletions

View File

@@ -23,26 +23,28 @@ import (
) )
type formatter struct { type formatter struct {
format string colorize bool
quiet bool format string
start time.Time quiet bool
start time.Time
} }
// newFormatter returns a formatter for formatting output to // newFormatter returns a formatter for formatting output to
// the terminal in a format similar to Ninja. // the terminal in a format similar to Ninja.
// format takes nearly all the same options as NINJA_STATUS. // format takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported. // %c is currently unsupported.
func newFormatter(format string, quiet bool) formatter { func newFormatter(colorize bool, format string, quiet bool) formatter {
return formatter{ return formatter{
format: format, colorize: colorize,
quiet: quiet, format: format,
start: time.Now(), quiet: quiet,
start: time.Now(),
} }
} }
func (s formatter) message(level status.MsgLevel, message string) string { func (s formatter) message(level status.MsgLevel, message string) string {
if level >= status.ErrorLvl { if level >= status.ErrorLvl {
return fmt.Sprintf("FAILED: %s", message) return fmt.Sprintf("%s %s", s.failedString(), message)
} else if level > status.StatusLvl { } else if level > status.StatusLvl {
return fmt.Sprintf("%s%s", level.Prefix(), message) return fmt.Sprintf("%s%s", level.Prefix(), message)
} else if level == status.StatusLvl { } else if level == status.StatusLvl {
@@ -127,9 +129,9 @@ func (s formatter) result(result status.ActionResult) string {
if result.Error != nil { if result.Error != nil {
targets := strings.Join(result.Outputs, " ") targets := strings.Join(result.Outputs, " ")
if s.quiet || result.Command == "" { if s.quiet || result.Command == "" {
ret = fmt.Sprintf("FAILED: %s\n%s", targets, result.Output) ret = fmt.Sprintf("%s %s\n%s", s.failedString(), targets, result.Output)
} else { } else {
ret = fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output) ret = fmt.Sprintf("%s %s\n%s\n%s", s.failedString(), targets, result.Command, result.Output)
} }
} else if result.Output != "" { } else if result.Output != "" {
ret = result.Output ret = result.Output
@@ -141,3 +143,11 @@ func (s formatter) result(result status.ActionResult) string {
return ret return ret
} }
func (s formatter) failedString() string {
failed := "FAILED:"
if s.colorize {
failed = ansi.red() + ansi.bold() + failed + ansi.regular()
}
return failed
}

View File

@@ -27,9 +27,10 @@ import (
// statusFormat takes nearly all the same options as NINJA_STATUS. // statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported. // %c is currently unsupported.
func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput { func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild) canUseSmartFormatting := !forceSimpleOutput && isSmartTerminal(w)
formatter := newFormatter(canUseSmartFormatting, statusFormat, quietBuild)
if !forceSimpleOutput && isSmartTerminal(w) { if canUseSmartFormatting {
return NewSmartStatusOutput(w, formatter) return NewSmartStatusOutput(w, formatter)
} else { } else {
return NewSimpleStatusOutput(w, formatter, forceKeepANSI) return NewSimpleStatusOutput(w, formatter, forceKeepANSI)

View File

@@ -58,7 +58,7 @@ func TestStatusOutput(t *testing.T) {
{ {
name: "action with error", name: "action with error",
calls: actionsWithError, calls: actionsWithError,
smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n", smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n", simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
}, },
{ {
@@ -70,7 +70,7 @@ func TestStatusOutput(t *testing.T) {
{ {
name: "messages", name: "messages",
calls: actionsWithMessages, calls: actionsWithMessages,
smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n", smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\n\x1b[31m\x1b[1mFAILED:\x1b[0m error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n", simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
}, },
{ {
@@ -362,7 +362,7 @@ func TestSmartStatusHideAfterFailure(t *testing.T) {
stat.Flush() stat.Flush()
w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n" w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n"
if g := smart.String(); g != w { if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g) t.Errorf("want:\n%q\ngot:\n%q", w, g)
@@ -407,7 +407,7 @@ func TestSmartStatusHideAfterFailurePlural(t *testing.T) {
stat.Flush() stat.Flush()
w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n" w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n"
if g := smart.String(); g != w { if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g) t.Errorf("want:\n%q\ngot:\n%q", w, g)
@@ -445,7 +445,7 @@ func TestSmartStatusDontHideErrorAfterFailure(t *testing.T) {
stat.Flush() stat.Flush()
w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nFAILED: \nOutput2\n" w := "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n\x1b[31m\x1b[1mFAILED:\x1b[0m \nOutput2\n"
if g := smart.String(); g != w { if g := smart.String(); g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g) t.Errorf("want:\n%q\ngot:\n%q", w, g)