Skip to content

copy: Add text-based progress output for non-TTY environments (skopeo#658)#2966

Closed
oshe-gi wants to merge 1 commit intocontainers:mainfrom
oshe-gi:658-text-progress-for-non-tty
Closed

copy: Add text-based progress output for non-TTY environments (skopeo#658)#2966
oshe-gi wants to merge 1 commit intocontainers:mainfrom
oshe-gi:658-text-progress-for-non-tty

Conversation

@oshe-gi
Copy link

@oshe-gi oshe-gi commented Feb 18, 2026

Relates-to: containers/skopeo#658

Problem

When copying images in non-TTY environments (CI/CD pipelines, redirected output, piped commands), the visual mpb progress bars are discarded via io.Discard, leaving users with no visibility into transfer progress. This makes it difficult to:

  • Detect stalled transfers in CI/CD pipelines
  • Monitor progress of long-running copies
  • Distinguish between a slow transfer and a hung process

Currently, only a single "Copying blob..." message is printed via printCopyInfo() when non-TTY, with no subsequent progress updates.

Solution

This change automatically enables text-based progress output for non-TTY environments by leveraging the existing Options.Progress channel mechanism.

Design decisions

  1. Automatic for non-TTY: When output is not a TTY and the caller hasn't already provided a buffered Progress channel, we automatically set up text-based progress output. No opt-in flag needed.

  2. Aggregate progress instead of per-blob: Rather than printing a line for each blob (which would be verbose for multi-layer images), we track total bytes across all blobs and print a single aggregate progress line. This keeps CI logs clean while still providing visibility.

  3. Reuse existing Progress channel: The progressReader in blob.go already sends ProgressEventNewArtifact, ProgressEventRead, and ProgressEventDone events. We simply consume these events and format them as text output.

  4. Buffered channel: We create a buffered channel to prevent blocking senders during parallel blob downloads. Callers who need custom consumption should provide a properly buffered channel.

  5. Sensible interval defaults: If ProgressInterval is not set, we default to 500ms. If the caller sets a larger interval, we respect that. The interval is clamped to a minimum of 500ms to prevent log spam.

Output example

Progress: 13.1 MiB / 52.3 MiB
Progress: 26.2 MiB / 52.3 MiB
Progress: 52.3 MiB / 52.3 MiB

Files changed

  • copy/progress_nontty.go - New file with nonTTYProgressWriter and setupNonTTYProgressWriter
  • copy/progress_nontty_test.go - Table-driven tests for writer and setup logic
  • copy/copy.go - Call setupNonTTYProgressWriter in non-TTY mode

Testing

Build and unit tests:

go build ./copy/...  #
go test ./copy/...   # ✓ all existing tests pass

Manual testing with skopeo (pipe to cat to force non-TTY):

go run ./cmd/skopeo \
  --policy ./default-policy.json \
  --override-os linux \
  --override-arch amd64 \
  copy \
  docker://docker.io/library/alpine:latest \
  dir:/tmp/alpine-copy 2>&1 | cat

Signed-off-by: Oleksandr Shestopal ar.shestopal@gmail.com

When copying images in non-TTY environments (CI/CD pipelines, redirected
output, piped commands), the visual mpb progress bars are discarded,
leaving users with no visibility into transfer progress. This makes it
difficult to detect stalled transfers or monitor long-running copies.

This change adds a nonTTYProgressWriter that consumes progress events
from the existing Progress channel and prints periodic aggregate progress
lines suitable for log output:

    Progress: 13.1 MiB / 52.3 MiB
    Progress: 26.2 MiB / 52.3 MiB
    Progress: 52.3 MiB / 52.3 MiB

The feature is enabled when, output is not a TTY, we check if option.Progress is set,
otherwise create a new buffered channel for progress events.

Note: Unbuffered channels are replaced with buffered ones to prevent
blocking during parallel blob downloads. Callers who need custom
consumption should provide a properly buffered channel.

Relates-to: containers/skopeo#658
Signed-off-by: Oleksandr Shestopal <ar.shestopal-oshegithub@gmail.com>
@github-actions
Copy link

This repository has been migrated to https://github.com/containers/container-libs. Please open your PR there.

@github-actions github-actions bot closed this Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants