• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tensorchord / envd / 17369334958

01 Sep 2025 06:18AM UTC coverage: 42.467% (-0.3%) from 42.811%
17369334958

Pull #2037

github

web-flow
chore(deps): bump the all-dependencies group with 9 updates

Bumps the all-dependencies group with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [github.com/containers/image/v5](https://github.com/containers/image) | `5.36.0` | `5.36.1` |
| [github.com/docker/cli](https://github.com/docker/cli) | `28.3.2+incompatible` | `28.3.3+incompatible` |
| [github.com/docker/docker](https://github.com/docker/docker) | `28.3.2+incompatible` | `28.3.3+incompatible` |
| [github.com/docker/go-connections](https://github.com/docker/go-connections) | `0.5.0` | `0.6.0` |
| [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) | `2.23.4` | `2.25.2` |
| [github.com/onsi/gomega](https://github.com/onsi/gomega) | `1.38.0` | `1.38.2` |
| [github.com/stretchr/testify](https://github.com/stretchr/testify) | `1.10.0` | `1.11.1` |
| [golang.org/x/crypto](https://github.com/golang/crypto) | `0.40.0` | `0.41.0` |
| [golang.org/x/term](https://github.com/golang/term) | `0.33.0` | `0.34.0` |


Updates `github.com/containers/image/v5` from 5.36.0 to 5.36.1
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.36.0...v5.36.1)

Updates `github.com/docker/cli` from 28.3.2+incompatible to 28.3.3+incompatible
- [Commits](https://github.com/docker/cli/compare/v28.3.2...v28.3.3)

Updates `github.com/docker/docker` from 28.3.2+incompatible to 28.3.3+incompatible
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v28.3.2...v28.3.3)

Updates `github.com/docker/go-connections` from 0.5.0 to 0.6.0
- [Commits](https://github.com/docker/go-connections/compare/v0.5.0...v0.6.0)

Updates `github.com/onsi/ginkgo/v2` from 2.23.4 to 2.25.2
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.23.4...v2.25.2)

Updates `github.co... (continued)
Pull Request #2037: chore(deps): bump the all-dependencies group with 9 updates

5181 of 12200 relevant lines covered (42.47%)

163.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.17
/pkg/progress/progressui/printer.go
1
// Copyright 2023 The envd Authors
2
// Copyright 2023 The buildkit Authors
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
//      http://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15

16
package progressui
17

18
import (
19
        "container/ring"
20
        "context"
21
        "fmt"
22
        "io"
23
        "os"
24
        "sort"
25
        "strings"
26
        "time"
27

28
        "github.com/opencontainers/go-digest"
29
        "github.com/tonistiigi/units"
30
)
31

32
const antiFlicker = 5 * time.Second
33
const maxDelay = 10 * time.Second
34
const minTimeDelta = 5 * time.Second
35
const minProgressDelta = 0.05 // %
36

37
const logsBufferSize = 10
38

39
type lastStatus struct {
40
        Current   int64
41
        Timestamp time.Time
42
}
43

44
type textMux struct {
45
        w         io.Writer
46
        current   digest.Digest
47
        last      map[string]lastStatus
48
        notFirst  bool
49
        nextIndex int
50
}
51

52
func (p *textMux) printVtx(t *trace, dgst digest.Digest) {
1,913✔
53
        if p.last == nil {
1,940✔
54
                p.last = make(map[string]lastStatus)
27✔
55
        }
27✔
56

57
        v, ok := t.byDigest[dgst]
1,913✔
58
        if !ok {
1,913✔
59
                return
×
60
        }
×
61

62
        if v.index == 0 {
2,829✔
63
                p.nextIndex++
916✔
64
                v.index = p.nextIndex
916✔
65
        }
916✔
66

67
        if dgst != p.current {
2,900✔
68
                if p.current != "" {
1,023✔
69
                        old := t.byDigest[p.current]
36✔
70
                        if old.logsPartial {
37✔
71
                                fmt.Fprintln(p.w, "")
1✔
72
                        }
1✔
73
                        old.logsOffset = 0
36✔
74
                        old.count = 0
36✔
75
                        fmt.Fprintf(p.w, "#%d ...\n", old.index)
36✔
76
                }
77

78
                if p.notFirst {
1,947✔
79
                        fmt.Fprintln(p.w, "")
960✔
80
                } else {
987✔
81
                        p.notFirst = true
27✔
82
                }
27✔
83

84
                if os.Getenv("PROGRESS_NO_TRUNC") == "0" {
987✔
85
                        fmt.Fprintf(p.w, "#%d %s\n", v.index, limitString(v.Name, 72))
×
86
                } else {
987✔
87
                        fmt.Fprintf(p.w, "#%d %s\n", v.index, v.Name)
987✔
88
                }
987✔
89
        }
90

91
        if len(v.events) != 0 {
1,913✔
92
                v.logsOffset = 0
×
93
        }
×
94
        for _, ev := range v.events {
1,913✔
95
                fmt.Fprintf(p.w, "#%d %s\n", v.index, ev)
×
96
        }
×
97
        v.events = v.events[:0]
1,913✔
98

1,913✔
99
        isOpenStatus := false // remote cache loading can currently produce status updates without active vertex
1,913✔
100
        for _, s := range v.statuses {
2,966✔
101
                if _, ok := v.statusUpdates[s.ID]; ok {
1,505✔
102
                        doPrint := true
452✔
103

452✔
104
                        if last, ok := p.last[s.ID]; ok && s.Completed == nil {
513✔
105
                                var progressDelta float64
61✔
106
                                if s.Total > 0 {
74✔
107
                                        progressDelta = float64(s.Current-last.Current) / float64(s.Total)
13✔
108
                                }
13✔
109
                                timeDelta := s.Timestamp.Sub(last.Timestamp)
61✔
110
                                if progressDelta < minProgressDelta && timeDelta < minTimeDelta {
114✔
111
                                        doPrint = false
53✔
112
                                }
53✔
113
                        }
114

115
                        if !doPrint {
505✔
116
                                continue
53✔
117
                        }
118

119
                        p.last[s.ID] = lastStatus{
399✔
120
                                Timestamp: s.Timestamp,
399✔
121
                                Current:   s.Current,
399✔
122
                        }
399✔
123

399✔
124
                        var bytes string
399✔
125
                        if s.Total != 0 {
503✔
126
                                bytes = fmt.Sprintf(" %.2f / %.2f", units.Bytes(s.Current), units.Bytes(s.Total))
104✔
127
                        } else if s.Current != 0 {
419✔
128
                                bytes = fmt.Sprintf(" %.2f", units.Bytes(s.Current))
20✔
129
                        }
20✔
130
                        var tm string
399✔
131
                        endTime := s.Timestamp
399✔
132
                        if s.Completed != nil {
727✔
133
                                endTime = *s.Completed
328✔
134
                        }
328✔
135
                        if s.Started != nil {
798✔
136
                                diff := endTime.Sub(*s.Started).Seconds()
399✔
137
                                if diff > 0.01 {
615✔
138
                                        tm = fmt.Sprintf(" %.1fs", diff)
216✔
139
                                }
216✔
140
                        }
141
                        if s.Completed != nil {
727✔
142
                                tm += " done"
328✔
143
                        } else {
399✔
144
                                isOpenStatus = true
71✔
145
                        }
71✔
146
                        fmt.Fprintf(p.w, "#%d %s%s%s\n", v.index, s.ID, bytes, tm)
399✔
147
                }
148
        }
149
        v.statusUpdates = map[string]struct{}{}
1,913✔
150

1,913✔
151
        for _, w := range v.warnings[v.warningIdx:] {
1,913✔
152
                fmt.Fprintf(p.w, "#%d WARN: %s\n", v.index, w.Short)
×
153
                v.warningIdx++
×
154
        }
×
155

156
        for i, l := range v.logs {
10,642✔
157
                if i == 0 {
9,470✔
158
                        l = l[v.logsOffset:]
741✔
159
                }
741✔
160
                fmt.Fprintf(p.w, "%s", l)
8,729✔
161
                if i != len(v.logs)-1 || !v.logsPartial {
17,112✔
162
                        fmt.Fprintln(p.w, "")
8,383✔
163
                }
8,383✔
164
                if v.logsBuffer == nil {
8,778✔
165
                        v.logsBuffer = ring.New(logsBufferSize)
49✔
166
                }
49✔
167
                v.logsBuffer.Value = l
8,729✔
168
                if !v.logsPartial {
12,826✔
169
                        v.logsBuffer = v.logsBuffer.Next()
4,097✔
170
                }
4,097✔
171
        }
172

173
        if len(v.logs) > 0 {
2,654✔
174
                if v.logsPartial {
1,087✔
175
                        v.logs = v.logs[len(v.logs)-1:]
346✔
176
                        v.logsOffset = len(v.logs[0])
346✔
177
                } else {
741✔
178
                        v.logs = nil
395✔
179
                        v.logsOffset = 0
395✔
180
                }
395✔
181
        }
182

183
        p.current = dgst
1,913✔
184
        if v.isCompleted() && !isOpenStatus {
2,864✔
185
                p.current = ""
951✔
186
                v.count = 0
951✔
187

951✔
188
                if v.Error != "" {
951✔
189
                        if v.logsPartial {
×
190
                                fmt.Fprintln(p.w, "")
×
191
                        }
×
192
                        if strings.HasSuffix(v.Error, context.Canceled.Error()) {
×
193
                                fmt.Fprintf(p.w, "#%d CANCELED\n", v.index)
×
194
                        } else {
×
195
                                fmt.Fprintf(p.w, "#%d ERROR: %s\n", v.index, v.Error)
×
196
                        }
×
197
                } else if v.Cached {
1,445✔
198
                        fmt.Fprintf(p.w, "#%d CACHED\n", v.index)
494✔
199
                } else {
951✔
200
                        tm := ""
457✔
201
                        var ivals []interval
457✔
202
                        for _, ival := range v.intervals {
976✔
203
                                ivals = append(ivals, ival)
519✔
204
                        }
519✔
205
                        ivals = mergeIntervals(ivals)
457✔
206
                        if len(ivals) > 0 {
914✔
207
                                var dt float64
457✔
208
                                for _, ival := range ivals {
976✔
209
                                        dt += ival.duration().Seconds()
519✔
210
                                }
519✔
211
                                tm = fmt.Sprintf(" %.1fs", dt)
457✔
212
                        }
213
                        fmt.Fprintf(p.w, "#%d DONE%s\n", v.index, tm)
457✔
214
                }
215
        }
216

217
        delete(t.updates, dgst)
1,913✔
218
}
219

220
func sortCompleted(t *trace, m map[digest.Digest]struct{}) []digest.Digest {
3,323✔
221
        out := make([]digest.Digest, 0, len(m))
3,323✔
222
        for k := range m {
4,274✔
223
                out = append(out, k)
951✔
224
        }
951✔
225
        sort.Slice(out, func(i, j int) bool {
4,906✔
226
                vtxi := t.byDigest[out[i]]
1,583✔
227
                vtxj := t.byDigest[out[j]]
1,583✔
228
                return vtxi.mostRecentInterval().stop.Before(*vtxj.mostRecentInterval().stop)
1,583✔
229
        })
1,583✔
230
        return out
3,323✔
231
}
232

233
func (p *textMux) print(t *trace) {
3,323✔
234
        completed := map[digest.Digest]struct{}{}
3,323✔
235
        rest := map[digest.Digest]struct{}{}
3,323✔
236

3,323✔
237
        for dgst := range t.updates {
5,443✔
238
                v, ok := t.byDigest[dgst]
2,120✔
239
                if !ok {
2,120✔
240
                        continue
×
241
                }
242
                if v.ProgressGroup != nil || v.hidden {
2,120✔
243
                        // skip vtxs in a group (they are merged into a single vtx) and hidden ones
×
244
                        continue
×
245
                }
246
                if v.isCompleted() {
3,071✔
247
                        completed[dgst] = struct{}{}
951✔
248
                } else {
2,120✔
249
                        rest[dgst] = struct{}{}
1,169✔
250
                }
1,169✔
251
        }
252

253
        current := p.current
3,323✔
254

3,323✔
255
        // items that have completed need to be printed first
3,323✔
256
        if _, ok := completed[current]; ok {
3,464✔
257
                p.printVtx(t, current)
141✔
258
        }
141✔
259

260
        for _, dgst := range sortCompleted(t, completed) {
4,274✔
261
                if dgst != current {
1,761✔
262
                        p.printVtx(t, dgst)
810✔
263
                }
810✔
264
        }
265

266
        if len(rest) == 0 {
5,616✔
267
                if current != "" {
4,564✔
268
                        if v := t.byDigest[current]; v.isStarted() && !v.isCompleted() {
4,481✔
269
                                return
2,210✔
270
                        }
2,210✔
271
                }
272
                // make any open vertex active
273
                for dgst, v := range t.byDigest {
2,637✔
274
                        if v.isStarted() && !v.isCompleted() && v.ProgressGroup == nil && !v.hidden {
2,558✔
275
                                p.printVtx(t, dgst)
4✔
276
                                return
4✔
277
                        }
4✔
278
                }
279
                return
79✔
280
        }
281

282
        // now print the active one
283
        if _, ok := rest[current]; ok {
1,825✔
284
                p.printVtx(t, current)
795✔
285
        }
795✔
286

287
        stats := map[digest.Digest]*vtxStat{}
1,030✔
288
        now := time.Now()
1,030✔
289
        sum := 0.0
1,030✔
290
        var max digest.Digest
1,030✔
291
        if current != "" {
1,977✔
292
                rest[current] = struct{}{}
947✔
293
        }
947✔
294
        for dgst := range rest {
2,351✔
295
                v, ok := t.byDigest[dgst]
1,321✔
296
                if !ok {
1,321✔
297
                        continue
×
298
                }
299
                if v.lastBlockTime == nil {
1,321✔
300
                        // shouldn't happen, but not worth crashing over
×
301
                        continue
×
302
                }
303
                tm := now.Sub(*v.lastBlockTime)
1,321✔
304
                speed := float64(v.count) / tm.Seconds()
1,321✔
305
                overLimit := tm > maxDelay && dgst != current
1,321✔
306
                stats[dgst] = &vtxStat{blockTime: tm, speed: speed, overLimit: overLimit}
1,321✔
307
                sum += speed
1,321✔
308
                if overLimit || max == "" || stats[max].speed < speed {
2,443✔
309
                        max = dgst
1,122✔
310
                }
1,122✔
311
        }
312
        for dgst := range stats {
2,351✔
313
                stats[dgst].share = stats[dgst].speed / sum
1,321✔
314
        }
1,321✔
315

316
        if _, ok := completed[current]; ok || current == "" {
1,193✔
317
                p.printVtx(t, max)
163✔
318
                return
163✔
319
        }
163✔
320

321
        // show items that were hidden
322
        for dgst := range rest {
1,918✔
323
                if stats[dgst].overLimit {
1,051✔
324
                        p.printVtx(t, dgst)
×
325
                        return
×
326
                }
×
327
        }
328

329
        // fair split between vertices
330
        if 1.0/(1.0-stats[current].share)*antiFlicker.Seconds() < stats[current].blockTime.Seconds() {
867✔
331
                p.printVtx(t, max)
×
332
                return
×
333
        }
×
334
}
335

336
type vtxStat struct {
337
        blockTime time.Duration
338
        speed     float64
339
        share     float64
340
        overLimit bool
341
}
342

343
func limitString(s string, l int) string {
×
344
        if len(s) > l {
×
345
                return s[:l] + "..."
×
346
        }
×
347
        return s
×
348
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc