Skip to content

Commit 7eee93b

Browse files
committed
stop progress UI during build to prevent interference with buildkit Display
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 795a1c9 commit 7eee93b

File tree

8 files changed

+83
-62
lines changed

8 files changed

+83
-62
lines changed

pkg/compose/build.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
226226
if err != nil {
227227
return err
228228
}
229-
s.events.On(progress.BuildingEvent("Image " + buildOptions.Tags[0]))
229+
s.events.On(progress.BuildingEvent(buildOptions.Tags[0]))
230230

231231
trace.SpanFromContext(ctx).SetAttributes(attribute.String("builder", "buildkit"))
232232
digest, err := s.doBuildBuildkit(ctx, name, buildOptions, w, nodes)
@@ -256,7 +256,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
256256
service := project.Services[names[i]]
257257
imageRef := api.GetImageNameOrDefault(service, project.Name)
258258
imageIDs[imageRef] = imageDigest
259-
s.events.On(progress.BuiltEvent("Image " + imageRef))
259+
s.events.On(progress.BuiltEvent(imageRef))
260260
}
261261
}
262262
return imageIDs, err

pkg/compose/build_bake.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
226226
}
227227

228228
image := api.GetImageNameOrDefault(service, project.Name)
229+
s.events.On(progress.BuildingEvent(image))
230+
229231
expectedImages[serviceName] = image
230232

231233
pull := service.Build.Pull || options.Pull
@@ -426,7 +428,7 @@ func (s *composeService) doBuildBake(ctx context.Context, project *types.Project
426428
return nil, fmt.Errorf("build result not found in Bake metadata for service %s", name)
427429
}
428430
results[image] = built.Digest
429-
s.events.On(progress.BuiltEvent("Image " + image))
431+
s.events.On(progress.BuiltEvent(image))
430432
}
431433
return results, nil
432434
}

pkg/compose/build_classic.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
184184

185185
ctx, cancel := context.WithCancel(ctx)
186186
defer cancel()
187-
s.events.On(progress2.BuildingEvent("Image " + imageName))
187+
s.events.On(progress2.BuildingEvent(imageName))
188188
response, err := s.apiClient().ImageBuild(ctx, body, buildOpts)
189189
if err != nil {
190190
return "", err
@@ -213,7 +213,7 @@ func (s *composeService) doBuildClassic(ctx context.Context, project *types.Proj
213213
}
214214
return "", err
215215
}
216-
s.events.On(progress2.BuiltEvent("Image " + imageName))
216+
s.events.On(progress2.BuiltEvent(imageName))
217217
return imageID, nil
218218
}
219219

pkg/compose/model.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,18 @@ func (m *modelAPI) PullModel(ctx context.Context, model types.ModelConfig, quiet
145145
events.On(progress.ErrorMessageEvent(model.Name, err.Error()))
146146
}
147147
events.On(progress.Event{
148-
ID: model.Name,
149-
Status: progress.Working,
150-
Text: "Pulled",
148+
ID: model.Name,
149+
Status: progress.Working,
150+
StatusText: "Pulled",
151151
})
152152
return err
153153
}
154154

155155
func (m *modelAPI) ConfigureModel(ctx context.Context, config types.ModelConfig, events progress.EventProcessor) error {
156156
events.On(progress.Event{
157-
ID: config.Name,
158-
Status: progress.Working,
159-
Text: "Configuring",
157+
ID: config.Name,
158+
Status: progress.Working,
159+
StatusText: "Configuring",
160160
})
161161
// configure [--context-size=<n>] MODEL [-- <runtime-flags...>]
162162
args := []string{"configure"}

pkg/compose/pull.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,7 @@ func getUnwrappedErrorMessage(err error) string {
174174

175175
func (s *composeService) pullServiceImage(ctx context.Context, service types.ServiceConfig, quietPull bool, defaultPlatform string) (string, error) {
176176
resource := "Image " + service.Image
177-
s.events.On(progress.Event{
178-
ID: resource,
179-
Status: progress.Working,
180-
Text: "Pulling",
181-
})
177+
s.events.On(progress.PullingEvent(service.Image))
182178
ref, err := reference.ParseNormalizedNamed(service.Image)
183179
if err != nil {
184180
return "", err
@@ -246,11 +242,7 @@ func (s *composeService) pullServiceImage(ctx context.Context, service types.Ser
246242
toPullProgressEvent(resource, jm, s.events)
247243
}
248244
}
249-
s.events.On(progress.Event{
250-
ID: resource,
251-
Status: progress.Done,
252-
Text: "Pulled",
253-
})
245+
s.events.On(progress.PulledEvent(service.Image))
254246

255247
inspected, err := s.apiClient().ImageInspect(ctx, service.Image)
256248
if err != nil {

pkg/e2e/compose_run_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ func TestLocalComposeRun(t *testing.T) {
188188

189189
res = c.RunDockerComposeCmd(t, "-f", "./fixtures/run-test/pull.yaml", "run", "--pull", "always", "backend")
190190
assert.Assert(t, strings.Contains(res.Combined(), "Image nginx Pulling"), res.Combined())
191-
assert.Assert(t, strings.Contains(res.Combined(), "Image nginx Pulled"), res.Combined())
191+
assert.Assert(t, strings.Contains(res.Combined(), "Image nginx Pulled"), res.Combined())
192192
})
193193

194194
t.Run("compose run --env-from-file", func(t *testing.T) {

pkg/progress/event.go

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ const (
3232
Error
3333
)
3434

35+
const (
36+
StatusError = "Error"
37+
StatusCreating = "Creating"
38+
StatusStarting = "Starting"
39+
StatusStarted = "Started"
40+
StatusWaiting = "Waiting"
41+
StatusHealthy = "Healthy"
42+
StatusExited = "Exited"
43+
StatusRestarting = "Restarting"
44+
StatusRestarted = "Restarted"
45+
StatusRunning = "Running"
46+
StatusCreated = "Created"
47+
StatusStopping = "Stopping"
48+
StatusStopped = "Stopped"
49+
StatusKilling = "Killing"
50+
StatusKilled = "Killed"
51+
StatusRemoving = "Removing"
52+
StatusRemoved = "Removed"
53+
StatusBuilding = "Building"
54+
StatusBuilt = "Built"
55+
StatusPulling = "Pulling"
56+
StatusPulled = "Pulled"
57+
)
58+
3559
// Event represents a progress event.
3660
type Event struct {
3761
ID string
@@ -51,97 +75,107 @@ func ErrorMessageEvent(id string, msg string) Event {
5175

5276
// ErrorEvent creates a new Error Event
5377
func ErrorEvent(id string) Event {
54-
return NewEvent(id, Error, "Error")
78+
return NewEvent(id, Error, StatusError)
5579
}
5680

5781
// CreatingEvent creates a new Create in progress Event
5882
func CreatingEvent(id string) Event {
59-
return NewEvent(id, Working, "Creating")
83+
return NewEvent(id, Working, StatusCreating)
6084
}
6185

6286
// StartingEvent creates a new Starting in progress Event
6387
func StartingEvent(id string) Event {
64-
return NewEvent(id, Working, "Starting")
88+
return NewEvent(id, Working, StatusStarting)
6589
}
6690

6791
// StartedEvent creates a new Started in progress Event
6892
func StartedEvent(id string) Event {
69-
return NewEvent(id, Done, "Started")
93+
return NewEvent(id, Done, StatusStarted)
7094
}
7195

7296
// Waiting creates a new waiting event
7397
func Waiting(id string) Event {
74-
return NewEvent(id, Working, "Waiting")
98+
return NewEvent(id, Working, StatusWaiting)
7599
}
76100

77101
// Healthy creates a new healthy event
78102
func Healthy(id string) Event {
79-
return NewEvent(id, Done, "Healthy")
103+
return NewEvent(id, Done, StatusHealthy)
80104
}
81105

82106
// Exited creates a new exited event
83107
func Exited(id string) Event {
84-
return NewEvent(id, Done, "Exited")
108+
return NewEvent(id, Done, StatusExited)
85109
}
86110

87111
// RestartingEvent creates a new Restarting in progress Event
88112
func RestartingEvent(id string) Event {
89-
return NewEvent(id, Working, "Restarting")
113+
return NewEvent(id, Working, StatusRestarting)
90114
}
91115

92116
// RestartedEvent creates a new Restarted in progress Event
93117
func RestartedEvent(id string) Event {
94-
return NewEvent(id, Done, "Restarted")
118+
return NewEvent(id, Done, StatusRestarted)
95119
}
96120

97121
// RunningEvent creates a new Running in progress Event
98122
func RunningEvent(id string) Event {
99-
return NewEvent(id, Done, "Running")
123+
return NewEvent(id, Done, StatusRunning)
100124
}
101125

102126
// CreatedEvent creates a new Created (done) Event
103127
func CreatedEvent(id string) Event {
104-
return NewEvent(id, Done, "Created")
128+
return NewEvent(id, Done, StatusCreated)
105129
}
106130

107131
// StoppingEvent creates a new Stopping in progress Event
108132
func StoppingEvent(id string) Event {
109-
return NewEvent(id, Working, "Stopping")
133+
return NewEvent(id, Working, StatusStopping)
110134
}
111135

112136
// StoppedEvent creates a new Stopping in progress Event
113137
func StoppedEvent(id string) Event {
114-
return NewEvent(id, Done, "Stopped")
138+
return NewEvent(id, Done, StatusStopped)
115139
}
116140

117141
// KillingEvent creates a new Killing in progress Event
118142
func KillingEvent(id string) Event {
119-
return NewEvent(id, Working, "Killing")
143+
return NewEvent(id, Working, StatusKilling)
120144
}
121145

122146
// KilledEvent creates a new Killed in progress Event
123147
func KilledEvent(id string) Event {
124-
return NewEvent(id, Done, "Killed")
148+
return NewEvent(id, Done, StatusKilled)
125149
}
126150

127151
// RemovingEvent creates a new Removing in progress Event
128152
func RemovingEvent(id string) Event {
129-
return NewEvent(id, Working, "Removing")
153+
return NewEvent(id, Working, StatusRemoving)
130154
}
131155

132156
// RemovedEvent creates a new removed (done) Event
133157
func RemovedEvent(id string) Event {
134-
return NewEvent(id, Done, "Removed")
158+
return NewEvent(id, Done, StatusRemoved)
135159
}
136160

137161
// BuildingEvent creates a new Building in progress Event
138162
func BuildingEvent(id string) Event {
139-
return NewEvent(id, Working, "Building")
163+
return NewEvent("Image "+id, Working, StatusBuilding)
140164
}
141165

142166
// BuiltEvent creates a new built (done) Event
143167
func BuiltEvent(id string) Event {
144-
return NewEvent(id, Done, "Built")
168+
return NewEvent("Image "+id, Done, StatusBuilt)
169+
}
170+
171+
// PullingEvent creates a new pulling (in progress) Event
172+
func PullingEvent(id string) Event {
173+
return NewEvent("Image "+id, Working, StatusPulling)
174+
}
175+
176+
// PulledEvent creates a new pulled (done) Event
177+
func PulledEvent(id string) Event {
178+
return NewEvent("Image "+id, Done, StatusPulled)
145179
}
146180

147181
// SkippedEvent creates a new Skipped Event

pkg/progress/tty.go

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"context"
2121
"fmt"
2222
"io"
23-
"slices"
2423
"strings"
2524
"sync"
2625
"time"
@@ -38,7 +37,6 @@ func NewTTYWriter(out io.Writer) EventProcessor {
3837
return &ttyWriter{
3938
out: out,
4039
tasks: map[string]task{},
41-
ids: []string{},
4240
done: make(chan bool),
4341
mtx: &sync.Mutex{},
4442
}
@@ -47,7 +45,6 @@ func NewTTYWriter(out io.Writer) EventProcessor {
4745
type ttyWriter struct {
4846
out io.Writer
4947
tasks map[string]task
50-
ids []string
5148
repeated bool
5249
numLines int
5350
done chan bool
@@ -122,11 +119,14 @@ func (w *ttyWriter) On(events ...Event) {
122119
}
123120

124121
func (w *ttyWriter) event(e Event) {
125-
if !slices.Contains(w.ids, e.ID) {
126-
w.ids = append(w.ids, e.ID)
122+
// Suspend print while a build is in progress, to avoid collision with buildkit Display
123+
if e.StatusText == StatusBuilding {
124+
w.ticker.Stop()
125+
} else {
126+
w.ticker.Reset(100 * time.Millisecond)
127127
}
128-
if _, ok := w.tasks[e.ID]; ok {
129-
last := w.tasks[e.ID]
128+
129+
if last, ok := w.tasks[e.ID]; ok {
130130
switch e.Status {
131131
case Done, Error, Warning:
132132
if last.status != e.Status {
@@ -194,10 +194,10 @@ func (w *ttyWriter) printEvent(e Event) {
194194
_, _ = fmt.Fprintf(w.out, "%s %s %s\n", e.ID, e.Text, color(e.StatusText))
195195
}
196196

197-
func (w *ttyWriter) print() { //nolint:gocyclo
197+
func (w *ttyWriter) print() {
198198
w.mtx.Lock()
199199
defer w.mtx.Unlock()
200-
if len(w.ids) == 0 {
200+
if len(w.tasks) == 0 {
201201
return
202202
}
203203
terminalWidth := goterm.Width()
@@ -218,14 +218,10 @@ func (w *ttyWriter) print() { //nolint:gocyclo
218218
}()
219219

220220
firstLine := fmt.Sprintf("[+] %s %d/%d", w.operation, numDone(w.tasks), len(w.tasks))
221-
if w.numLines != 0 && numDone(w.tasks) == w.numLines {
222-
firstLine = DoneColor(firstLine)
223-
}
224221
_, _ = fmt.Fprintln(w.out, firstLine)
225222

226223
var statusPadding int
227-
for _, v := range w.ids {
228-
t := w.tasks[v]
224+
for _, t := range w.tasks {
229225
l := len(fmt.Sprintf("%s %s", t.ID, t.text))
230226
if statusPadding < l {
231227
statusPadding = l
@@ -235,20 +231,18 @@ func (w *ttyWriter) print() { //nolint:gocyclo
235231
}
236232
}
237233

238-
if len(w.ids) > goterm.Height()-2 {
234+
if len(w.tasks) > goterm.Height()-2 {
239235
w.skipChildEvents = true
240236
}
241237
numLines := 0
242-
for _, v := range w.ids {
243-
t := w.tasks[v]
238+
for _, t := range w.tasks {
244239
if t.parentID != "" {
245240
continue
246241
}
247242
line := w.lineText(t, "", terminalWidth, statusPadding, w.dryRun)
248243
_, _ = fmt.Fprint(w.out, line)
249244
numLines++
250-
for _, v := range w.ids {
251-
t := w.tasks[v]
245+
for _, t := range w.tasks {
252246
if t.parentID == t.ID {
253247
if w.skipChildEvents {
254248
continue
@@ -292,8 +286,7 @@ func (w *ttyWriter) lineText(t task, pad string, terminalWidth, statusPadding in
292286

293287
// only show the aggregated progress while the root operation is in-progress
294288
if parent := t; parent.status == Working {
295-
for _, v := range w.ids {
296-
child := w.tasks[v]
289+
for _, child := range w.tasks {
297290
if child.parentID == parent.ID {
298291
if child.status == Working && child.total == 0 {
299292
// we don't have totals available for all the child events

0 commit comments

Comments
 (0)