aboutsummaryrefslogtreecommitdiffstats
path: root/ui/terminal/format.go
diff options
context:
space:
mode:
Diffstat (limited to 'ui/terminal/format.go')
-rw-r--r--ui/terminal/format.go123
1 files changed, 123 insertions, 0 deletions
diff --git a/ui/terminal/format.go b/ui/terminal/format.go
new file mode 100644
index 00000000..4205bdc2
--- /dev/null
+++ b/ui/terminal/format.go
@@ -0,0 +1,123 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package terminal
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "android/soong/ui/status"
+)
+
+type formatter struct {
+ format string
+ quiet bool
+ start time.Time
+}
+
+// newFormatter returns a formatter for formatting output to
+// the terminal in a format similar to Ninja.
+// format takes nearly all the same options as NINJA_STATUS.
+// %c is currently unsupported.
+func newFormatter(format string, quiet bool) formatter {
+ return formatter{
+ format: format,
+ quiet: quiet,
+ start: time.Now(),
+ }
+}
+
+func (s formatter) message(level status.MsgLevel, message string) string {
+ if level >= status.ErrorLvl {
+ return fmt.Sprintf("FAILED: %s", message)
+ } else if level > status.StatusLvl {
+ return fmt.Sprintf("%s%s", level.Prefix(), message)
+ } else if level == status.StatusLvl {
+ return message
+ }
+ return ""
+}
+
+func (s formatter) progress(counts status.Counts) string {
+ if s.format == "" {
+ return fmt.Sprintf("[%3d%% %d/%d] ", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
+ }
+
+ buf := &strings.Builder{}
+ for i := 0; i < len(s.format); i++ {
+ c := s.format[i]
+ if c != '%' {
+ buf.WriteByte(c)
+ continue
+ }
+
+ i = i + 1
+ if i == len(s.format) {
+ buf.WriteByte(c)
+ break
+ }
+
+ c = s.format[i]
+ switch c {
+ case '%':
+ buf.WriteByte(c)
+ case 's':
+ fmt.Fprintf(buf, "%d", counts.StartedActions)
+ case 't':
+ fmt.Fprintf(buf, "%d", counts.TotalActions)
+ case 'r':
+ fmt.Fprintf(buf, "%d", counts.RunningActions)
+ case 'u':
+ fmt.Fprintf(buf, "%d", counts.TotalActions-counts.StartedActions)
+ case 'f':
+ fmt.Fprintf(buf, "%d", counts.FinishedActions)
+ case 'o':
+ fmt.Fprintf(buf, "%.1f", float64(counts.FinishedActions)/time.Since(s.start).Seconds())
+ case 'c':
+ // TODO: implement?
+ buf.WriteRune('?')
+ case 'p':
+ fmt.Fprintf(buf, "%3d%%", 100*counts.FinishedActions/counts.TotalActions)
+ case 'e':
+ fmt.Fprintf(buf, "%.3f", time.Since(s.start).Seconds())
+ default:
+ buf.WriteString("unknown placeholder '")
+ buf.WriteByte(c)
+ buf.WriteString("'")
+ }
+ }
+ return buf.String()
+}
+
+func (s formatter) result(result status.ActionResult) string {
+ var ret string
+ if result.Error != nil {
+ targets := strings.Join(result.Outputs, " ")
+ if s.quiet || result.Command == "" {
+ ret = fmt.Sprintf("FAILED: %s\n%s", targets, result.Output)
+ } else {
+ ret = fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output)
+ }
+ } else if result.Output != "" {
+ ret = result.Output
+ }
+
+ if len(ret) > 0 && ret[len(ret)-1] != '\n' {
+ ret += "\n"
+ }
+
+ return ret
+}