Skip to content

Commit 24ff098

Browse files
committed
compact TUI to monitor layers download progress
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 593c426 commit 24ff098

File tree

7 files changed

+209
-75
lines changed

7 files changed

+209
-75
lines changed

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ require (
8686
github.com/json-iterator/go v1.1.12 // indirect
8787
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
8888
github.com/klauspost/compress v1.15.12 // indirect
89-
github.com/mattn/go-colorable v0.1.12 // indirect
90-
github.com/mattn/go-isatty v0.0.16 // indirect
89+
github.com/mattn/go-colorable v0.1.13 // indirect
90+
github.com/mattn/go-isatty v0.0.17 // indirect
9191
github.com/mattn/go-runewidth v0.0.14 // indirect
9292
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
9393
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
@@ -132,7 +132,7 @@ require (
132132
golang.org/x/crypto v0.2.0 // indirect
133133
golang.org/x/net v0.4.0 // indirect
134134
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
135-
golang.org/x/sys v0.4.0 // indirect
135+
golang.org/x/sys v0.5.0 // indirect
136136
golang.org/x/term v0.3.0 // indirect
137137
golang.org/x/text v0.6.0 // indirect
138138
golang.org/x/time v0.1.0 // indirect

go.sum

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,12 @@ github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
516516
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
517517
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
518518
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
519-
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
520-
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
519+
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
520+
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
521521
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
522-
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
523-
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
524522
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
523+
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
524+
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
525525
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
526526
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
527527
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
@@ -1001,7 +1001,6 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
10011001
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10021002
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10031003
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1004-
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10051004
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10061005
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10071006
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1021,8 +1020,8 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc
10211020
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10221021
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10231022
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1024-
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
1025-
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1023+
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
1024+
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
10261025
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
10271026
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
10281027
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

pkg/compose/pull.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,23 +336,53 @@ func isServiceImageToBuild(service types.ServiceConfig, services []types.Service
336336
return false
337337
}
338338

339+
const (
340+
PreparingPhase = "Preparing"
341+
WaitingPhase = "Waiting"
342+
PullingFsPhase = "Pulling fs layer"
343+
DownloadingPhase = "Downloading"
344+
DownloadCompletePhase = "Download complete"
345+
ExtractingPhase = "Extracting"
346+
VerifyingChecksumPhase = "Verifying Checksum"
347+
AlreadyExistsPhase = "Already exists"
348+
PullCompletePhase = "Pull complete"
349+
)
350+
339351
func toPullProgressEvent(parent string, jm jsonmessage.JSONMessage, w progress.Writer) {
340352
if jm.ID == "" || jm.Progress == nil {
341353
return
342354
}
343355

344356
var (
345-
text string
346-
status = progress.Working
357+
text string
358+
total int64
359+
percent int
360+
current int64
361+
status = progress.Working
347362
)
348363

349364
text = jm.Progress.String()
350365

351-
if jm.Status == "Pull complete" ||
352-
jm.Status == "Already exists" ||
353-
strings.Contains(jm.Status, "Image is up to date") ||
366+
switch jm.Status {
367+
case PreparingPhase, WaitingPhase, PullingFsPhase:
368+
percent = 0
369+
case DownloadingPhase, ExtractingPhase, VerifyingChecksumPhase:
370+
if jm.Progress != nil {
371+
current = jm.Progress.Current
372+
total = jm.Progress.Total
373+
if jm.Progress.Total > 0 {
374+
percent = int(jm.Progress.Current * 100 / jm.Progress.Total)
375+
}
376+
}
377+
case DownloadCompletePhase, AlreadyExistsPhase, PullCompletePhase:
378+
status = progress.Done
379+
percent = 100
380+
}
381+
382+
if strings.Contains(jm.Status, "Image is up to date") ||
354383
strings.Contains(jm.Status, "Downloaded newer image") {
355384
status = progress.Done
385+
percent = 100
356386
}
357387

358388
if jm.Error != nil {
@@ -363,6 +393,9 @@ func toPullProgressEvent(parent string, jm jsonmessage.JSONMessage, w progress.W
363393
w.Event(progress.Event{
364394
ID: jm.ID,
365395
ParentID: parent,
396+
Current: current,
397+
Total: total,
398+
Percent: percent,
366399
Text: jm.Status,
367400
Status: status,
368401
StatusText: text,

pkg/compose/push.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,23 +139,38 @@ func toPushProgressEvent(prefix string, jm jsonmessage.JSONMessage, w progress.W
139139
return
140140
}
141141
var (
142-
text string
143-
status = progress.Working
142+
text string
143+
status = progress.Working
144+
total int64
145+
current int64
146+
percent int
144147
)
145-
if jm.Status == "Pull complete" || jm.Status == "Already exists" {
148+
if jm.Status == "Pushed" || jm.Status == "Already exists" {
146149
status = progress.Done
150+
percent = 100
147151
}
148152
if jm.Error != nil {
149153
status = progress.Error
150154
text = jm.Error.Message
151155
}
152156
if jm.Progress != nil {
153157
text = jm.Progress.String()
158+
if jm.Progress.Total != 0 {
159+
current = jm.Progress.Current
160+
total = jm.Progress.Total
161+
if jm.Progress.Total > 0 {
162+
percent = int(jm.Progress.Current * 100 / jm.Progress.Total)
163+
}
164+
}
154165
}
166+
155167
w.Event(progress.Event{
156168
ID: fmt.Sprintf("Pushing %s: %s", prefix, jm.ID),
157169
Text: jm.Status,
158170
Status: status,
171+
Current: current,
172+
Total: total,
173+
Percent: percent,
159174
StatusText: text,
160175
})
161176
}

pkg/progress/event.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,37 @@
1616

1717
package progress
1818

19-
import "time"
19+
import (
20+
"time"
21+
22+
"github.com/morikuni/aec"
23+
)
2024

2125
// EventStatus indicates the status of an action
2226
type EventStatus int
2327

28+
func (s EventStatus) color() aec.ANSI {
29+
switch s {
30+
case Done:
31+
return aec.GreenF
32+
case Warning:
33+
return aec.YellowF.With(aec.Bold)
34+
case Error:
35+
return aec.RedF.With(aec.Bold)
36+
default:
37+
return aec.DefaultF
38+
}
39+
}
40+
2441
const (
2542
// Working means that the current task is working
2643
Working EventStatus = iota
2744
// Done means that the current task is done
2845
Done
29-
// Error means that the current task has errored
30-
Error
3146
// Warning means that the current task has warning
3247
Warning
48+
// Error means that the current task has errored
49+
Error
3350
)
3451

3552
// Event represents a progress event.
@@ -39,7 +56,10 @@ type Event struct {
3956
Text string
4057
Status EventStatus
4158
StatusText string
59+
Current int64
60+
Percent int
4261

62+
Total int64
4363
startTime time.Time
4464
endTime time.Time
4565
spinner *spinner
@@ -148,3 +168,22 @@ func (e *Event) stop() {
148168
e.endTime = time.Now()
149169
e.spinner.Stop()
150170
}
171+
172+
var (
173+
spinnerDone = aec.Apply("✔", aec.GreenF)
174+
spinnerWarning = aec.Apply("!", aec.YellowF)
175+
spinnerError = aec.Apply("✘", aec.RedF)
176+
)
177+
178+
func (e *Event) Spinner() any {
179+
switch e.Status {
180+
case Done:
181+
return spinnerDone
182+
case Warning:
183+
return spinnerWarning
184+
case Error:
185+
return spinnerError
186+
default:
187+
return e.spinner.String()
188+
}
189+
}

0 commit comments

Comments
 (0)