The progress system provides user feedback for long-running operations through progress bars and spinners.
The internal/progress package provides:
The progress system uses a modular architecture with clear separation:
ProgressBar / Spinner
├── Configuration (ProgressConfig with functional options)
├── Calculation (percentage, speed, etc.)
├── Rendering (buildLine - format to string)
└── Output (terminalWriter - cross-platform I/O)
Benefits:
Displays a visual progress bar with percentage, bytes, and speed information.
Basic Usage:
// Create a progress bar
pb := progress.NewProgressBar(totalBytes, "Downloading file")
// Update progress
pb.Update(currentBytes)
// Finish (shows 100% and adds newline)
pb.Finish()
With Options:
// Minimal mode (percentage only)
pb := progress.NewProgressBar(total, "Downloading", progress.WithMinimal())
// Custom width
pb := progress.NewProgressBar(total, "Downloading", progress.WithWidth(80))
// Silent mode (no output)
pb := progress.NewProgressBar(total, "Downloading", progress.WithSilent())
// Multiple options
pb := progress.NewProgressBar(total, "Downloading",
progress.WithWidth(60),
progress.WithChars("=", "-"),
progress.WithSpeed(false),
)
Features:
\r)Animated spinner for operations without known progress.
Usage:
// Create and start spinner
spinner := progress.NewSpinner("Loading data")
spinner.Start()
// Do work...
time.Sleep(5 * time.Second)
// Stop (shows checkmark)
spinner.Stop()
With defer pattern:
spinner := progress.NewSpinner("Processing")
spinner.Start()
defer spinner.Stop()
// Do work... spinner automatically stops at end
Features:
Wraps an io.Writer to automatically update progress during write operations.
Usage:
file, _ := os.Create("output.dat")
defer file.Close()
pb := progress.NewProgressBar(totalBytes, "Writing")
pw := progress.NewProgressWriter(file, pb)
// Writes automatically update progress
io.Copy(pw, source)
pb.Finish()
Perfect for:
Reusable formatting utilities in internal/formatters:
// Format bytes
formatters.FormatBytes(1048576) // "1.0 MB"
// Format speed
formatters.FormatSpeed(10485760) // "10.0 MB/s"
// Format percentage
formatters.FormatPercentage(0.753) // "75.3%"
All options use the functional options pattern for flexibility:
| Option | Description | Example |
|---|---|---|
WithWidth(int) |
Set bar width in characters | WithWidth(80) |
WithUpdateThrottle(duration) |
Minimum time between updates | WithUpdateThrottle(50*time.Millisecond) |
WithSpeed(bool) |
Show/hide speed display | WithSpeed(false) |
WithBytes(bool) |
Show/hide byte counts | WithBytes(false) |
WithChars(filled, empty) |
Custom bar characters | WithChars("=", "-") |
WithSilent() |
Disable all output | WithSilent() |
WithMinimal() |
Show only percentage | WithMinimal() |
WithCustom(func) |
Custom configuration | WithCustom(func(c *ProgressConfig) {...}) |
golang.org/x/termWindows:
Unix/Linux/macOS:
\r) when stdout is a TTYThe terminalWriter component handles all cross-platform terminal output:
type terminalWriter struct {
output io.Writer
isStdout bool
lastLineLen int
}
Key features:
\n or \r)Progress updates are throttled to prevent performance issues:
WithUpdateThrottle()Current usage:
internal/downloader)
progressBar := progress.NewProgressBar(fileSize, "Downloading "+filename)
progressWriter := progress.NewProgressWriter(file, progressBar)
io.Copy(progressWriter, resp.Body)
progressBar.Finish()
cmd/gopher)
spinner := progress.NewSpinner("Uninstalling Go "+version)
spinner.Start()
manager.Uninstall(version)
spinner.Stop()
internal/installer)
spinner := progress.NewSpinner("Extracting archive")
spinner.Start()
defer spinner.Stop()
// extraction logic...
internal/installer)
spinner := progress.NewSpinner("Creating version metadata")
spinner.Start()
createMetadata(...)
spinner.Stop()
# Test all progress components
go test ./internal/progress/...
# Test formatters
go test ./internal/formatters/...
# Test progress bar
./build/gopher install 1.23.0
# Test spinners
./build/gopher uninstall 1.23.0
See docs/ROADMAP.md for planned features:
WithWidth(30) for narrower barWithMinimal() for percentage-onlychcp 65001 for UTF-8 supportLast Updated: October 15, 2025
Version: 1.0.0
Status: Production Ready