diff --git a/util/progress/progressui/display.go b/util/progress/progressui/display.go index f7a5b49f5..2d4ccd153 100644 --- a/util/progress/progressui/display.go +++ b/util/progress/progressui/display.go @@ -155,7 +155,7 @@ type vertex struct { // Interval start time in unix nano -> interval. Using a map ensures // that updates for the same interval overwrite their previous updates. intervals map[int64]interval - mostRecentStart *time.Time + mergedIntervals []interval // whether the vertex should be hidden due to being in a progress group // that doesn't have any non-weak members that have started @@ -170,17 +170,23 @@ func (v *vertex) update(c int) { v.count += c } +func (v *vertex) mostRecentInterval() *interval { + if v.isStarted() { + ival := v.mergedIntervals[len(v.mergedIntervals)-1] + return &ival + } + return nil +} + func (v *vertex) isStarted() bool { - return len(v.intervals) > 0 + return len(v.mergedIntervals) > 0 } func (v *vertex) isCompleted() bool { - for _, ival := range v.intervals { - if ival.stop == nil { - return false - } + if ival := v.mostRecentInterval(); ival != nil { + return ival.stop != nil } - return true + return false } type vertexGroup struct { @@ -207,9 +213,6 @@ func (vg *vertexGroup) refresh() (changed, newlyStarted, newlyRevealed bool) { newlyStarted = true } vg.intervals[subVtx.Started.UnixNano()] = newInterval - if vg.mostRecentStart == nil || subVtx.Started.After(*vg.mostRecentStart) { - vg.mostRecentStart = subVtx.Started - } if !subVtx.ProgressGroup.Weak { vg.hidden = false @@ -240,6 +243,12 @@ func (vg *vertexGroup) refresh() (changed, newlyStarted, newlyRevealed bool) { newlyRevealed = true } + var ivals []interval + for _, ival := range vg.intervals { + ivals = append(ivals, ival) + } + vg.mergedIntervals = mergeIntervals(ivals) + return changed, newlyStarted, newlyRevealed } @@ -463,9 +472,11 @@ func (t *trace) update(s *client.SolveStatus, termWidth int) { start: v.Started, stop: v.Completed, } - if t.byDigest[v.Digest].mostRecentStart == nil || v.Started.After(*t.byDigest[v.Digest].mostRecentStart) { - t.byDigest[v.Digest].mostRecentStart = v.Started + var ivals []interval + for _, ival := range t.byDigest[v.Digest].intervals { + ivals = append(ivals, ival) } + t.byDigest[v.Digest].mergedIntervals = mergeIntervals(ivals) } t.byDigest[v.Digest].jobCached = false } @@ -474,7 +485,7 @@ func (t *trace) update(s *client.SolveStatus, termWidth int) { changed, newlyStarted, newlyRevealed := group.refresh() if newlyStarted { if t.localTimeDiff == 0 { - t.localTimeDiff = time.Since(*group.mostRecentStart) + t.localTimeDiff = time.Since(*group.mergedIntervals[0].start) } } if group.hidden { @@ -534,8 +545,8 @@ func (t *trace) update(s *client.SolveStatus, termWidth int) { v.logs[len(v.logs)-1] = append(v.logs[len(v.logs)-1], dt...) } else { ts := time.Duration(0) - if v.isStarted() { - ts = l.Timestamp.Sub(*v.mostRecentStart) + if ival := v.mostRecentInterval(); ival != nil { + ts = l.Timestamp.Sub(*ival.start) } prec := 1 sec := ts.Seconds() @@ -648,15 +659,14 @@ func (t *trace) displayInfo() (d displayInfo) { } for _, w := range v.warnings { msg := "WARN: " + string(w.Short) - mostRecentStart := v.mostRecentStart - var mostRecentStop *time.Time - if mostRecentStart != nil { - mostRecentStop = v.intervals[mostRecentStart.UnixNano()].stop + var mostRecentInterval interval + if ival := v.mostRecentInterval(); ival != nil { + mostRecentInterval = *ival } j := &job{ intervals: []interval{{ - start: addTime(mostRecentStart, t.localTimeDiff), - stop: addTime(mostRecentStop, t.localTimeDiff), + start: addTime(mostRecentInterval.start, t.localTimeDiff), + stop: addTime(mostRecentInterval.stop, t.localTimeDiff), }}, name: msg, isCanceled: true, diff --git a/util/progress/progressui/printer.go b/util/progress/progressui/printer.go index ac7c1fcfd..21b3cf12c 100644 --- a/util/progress/progressui/printer.go +++ b/util/progress/progressui/printer.go @@ -166,7 +166,7 @@ func (p *textMux) printVtx(t *trace, dgst digest.Digest) { } p.current = dgst - if v.Completed != nil && !isOpenStatus { + if v.isCompleted() && !isOpenStatus { p.current = "" v.count = 0 @@ -183,8 +183,17 @@ func (p *textMux) printVtx(t *trace, dgst digest.Digest) { fmt.Fprintf(p.w, "#%d CACHED\n", v.index) } else { tm := "" - if v.Started != nil { - tm = fmt.Sprintf(" %.1fs", v.Completed.Sub(*v.Started).Seconds()) + var ivals []interval + for _, ival := range v.intervals { + ivals = append(ivals, ival) + } + ivals = mergeIntervals(ivals) + if len(ivals) > 0 { + var dt float64 + for _, ival := range ivals { + dt += ival.duration().Seconds() + } + tm = fmt.Sprintf(" %.1fs", dt) } fmt.Fprintf(p.w, "#%d DONE%s\n", v.index, tm) } @@ -199,7 +208,9 @@ func sortCompleted(t *trace, m map[digest.Digest]struct{}) []digest.Digest { out = append(out, k) } sort.Slice(out, func(i, j int) bool { - return t.byDigest[out[i]].Completed.Before(*t.byDigest[out[j]].Completed) + vtxi := t.byDigest[out[i]] + vtxj := t.byDigest[out[j]] + return vtxi.mostRecentInterval().stop.Before(*vtxj.mostRecentInterval().stop) }) return out } @@ -213,7 +224,11 @@ func (p *textMux) print(t *trace) { if !ok { continue } - if v.Vertex.Completed != nil { + if v.ProgressGroup != nil || v.hidden { + // skip vtxs in a group (they are merged into a single vtx) and hidden ones + continue + } + if v.isCompleted() { completed[dgst] = struct{}{} } else { rest[dgst] = struct{}{} @@ -235,13 +250,13 @@ func (p *textMux) print(t *trace) { if len(rest) == 0 { if current != "" { - if v := t.byDigest[current]; v.Started != nil && v.Completed == nil { + if v := t.byDigest[current]; v.isStarted() && !v.isCompleted() { return } } // make any open vertex active for dgst, v := range t.byDigest { - if v.Started != nil && v.Completed == nil { + if v.isStarted() && !v.isCompleted() { p.printVtx(t, dgst) return }