Skip to content

Commit 4c5efd6

Browse files
committed
cli/command/container: fix buffer reuse when printing stats
Don't write lines back into the same buffer that's being read from when clearing lines; add a separate output buffer to construct the output, then write it to the CLI's output at once (to prevent terminal flicker). Relates to / introduced in cb2f95c. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 2cc9fe1 commit 4c5efd6

1 file changed

Lines changed: 12 additions & 8 deletions

File tree

cli/command/container/stats.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
291291
// Once formatted, it will be printed in one write to avoid screen flickering.
292292
var statsTextBuffer bytes.Buffer
293293

294+
// frameBuf holds the final terminal frame, including cursor movement and
295+
// line-clearing escape sequences, written in a single pass to avoid flicker.
296+
var frameBuf bytes.Buffer
297+
294298
statsCtx := formatter.Context{
295299
Output: &statsTextBuffer,
296300
Format: NewStatsFormat(format, daemonOSType),
@@ -319,30 +323,30 @@ func RunStats(ctx context.Context, dockerCLI command.Cli, options *StatsOptions)
319323
for {
320324
select {
321325
case <-ticker.C:
326+
statsTextBuffer.Reset()
327+
frameBuf.Reset()
322328
cStats.mu.RLock()
323329
ccStats := make([]StatsEntry, 0, len(cStats.cs))
324330
for _, c := range cStats.cs {
325331
ccStats = append(ccStats, c.GetStatistics())
326332
}
327333
cStats.mu.RUnlock()
328334

329-
// Start by moving the cursor to the top-left
330-
_, _ = fmt.Fprint(&statsTextBuffer, "\033[H")
331-
332335
if err := statsFormatWrite(statsCtx, ccStats, daemonOSType, !options.NoTrunc); err != nil {
333336
return err
334337
}
335338

339+
// Start by moving the cursor to the top-left
340+
_, _ = fmt.Fprint(&frameBuf, "\033[H")
341+
336342
for line := range strings.SplitSeq(statsTextBuffer.String(), "\n") {
337343
// In case the new text is shorter than the one we are writing over,
338344
// we'll append the "erase line" escape sequence to clear the remaining text.
339-
_, _ = fmt.Fprintln(&statsTextBuffer, line, "\033[K")
345+
_, _ = fmt.Fprintln(&frameBuf, line, "\033[K")
340346
}
341347
// We might have fewer containers than before, so let's clear the remaining text
342-
_, _ = fmt.Fprint(&statsTextBuffer, "\033[J")
343-
344-
_, _ = fmt.Fprint(dockerCLI.Out(), statsTextBuffer.String())
345-
statsTextBuffer.Reset()
348+
_, _ = fmt.Fprint(&frameBuf, "\033[J")
349+
_, _ = fmt.Fprint(dockerCLI.Out(), frameBuf.String())
346350

347351
if len(ccStats) == 0 && !showAll {
348352
return nil

0 commit comments

Comments
 (0)