208 lines
5.2 KiB
Go
208 lines
5.2 KiB
Go
package ux
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"time"
|
||
)
|
||
|
||
// ProgressReporter handles progress reporting for long operations
|
||
type ProgressReporter struct {
|
||
writer io.Writer
|
||
verbose bool
|
||
startTime time.Time
|
||
steps []ProgressStep
|
||
current int
|
||
}
|
||
|
||
// ProgressStep represents a step in a long operation
|
||
type ProgressStep struct {
|
||
Name string
|
||
Description string
|
||
Duration time.Duration
|
||
Status StepStatus
|
||
}
|
||
|
||
// StepStatus represents the status of a progress step
|
||
type StepStatus string
|
||
|
||
const (
|
||
StepStatusPending StepStatus = "pending"
|
||
StepStatusRunning StepStatus = "running"
|
||
StepStatusCompleted StepStatus = "completed"
|
||
StepStatusFailed StepStatus = "failed"
|
||
StepStatusSkipped StepStatus = "skipped"
|
||
)
|
||
|
||
// NewProgressReporter creates a new progress reporter
|
||
func NewProgressReporter(writer io.Writer, verbose bool) *ProgressReporter {
|
||
return &ProgressReporter{
|
||
writer: writer,
|
||
verbose: verbose,
|
||
startTime: time.Now(),
|
||
steps: make([]ProgressStep, 0),
|
||
current: -1,
|
||
}
|
||
}
|
||
|
||
// AddStep adds a new step to the progress reporter
|
||
func (p *ProgressReporter) AddStep(name, description string) {
|
||
p.steps = append(p.steps, ProgressStep{
|
||
Name: name,
|
||
Description: description,
|
||
Status: StepStatusPending,
|
||
})
|
||
}
|
||
|
||
// StartStep marks the current step as running
|
||
func (p *ProgressReporter) StartStep(stepIndex int) {
|
||
if stepIndex < 0 || stepIndex >= len(p.steps) {
|
||
return
|
||
}
|
||
|
||
p.current = stepIndex
|
||
p.steps[stepIndex].Status = StepStatusRunning
|
||
|
||
if p.verbose {
|
||
fmt.Fprintf(p.writer, "🔄 Starting: %s\n", p.steps[stepIndex].Description)
|
||
} else {
|
||
fmt.Fprintf(p.writer, "🔄 %s... ", p.steps[stepIndex].Name)
|
||
}
|
||
}
|
||
|
||
// CompleteStep marks the current step as completed
|
||
func (p *ProgressReporter) CompleteStep(stepIndex int) {
|
||
if stepIndex < 0 || stepIndex >= len(p.steps) {
|
||
return
|
||
}
|
||
|
||
p.steps[stepIndex].Status = StepStatusCompleted
|
||
p.steps[stepIndex].Duration = time.Since(p.startTime)
|
||
|
||
if p.verbose {
|
||
fmt.Fprintf(p.writer, "✅ Completed: %s (took %v)\n",
|
||
p.steps[stepIndex].Description, p.steps[stepIndex].Duration)
|
||
} else {
|
||
fmt.Fprintf(p.writer, "✅\n")
|
||
}
|
||
}
|
||
|
||
// FailStep marks the current step as failed
|
||
func (p *ProgressReporter) FailStep(stepIndex int, err error) {
|
||
if stepIndex < 0 || stepIndex >= len(p.steps) {
|
||
return
|
||
}
|
||
|
||
p.steps[stepIndex].Status = StepStatusFailed
|
||
p.steps[stepIndex].Duration = time.Since(p.startTime)
|
||
|
||
if p.verbose {
|
||
fmt.Fprintf(p.writer, "❌ Failed: %s (took %v) - %v\n",
|
||
p.steps[stepIndex].Description, p.steps[stepIndex].Duration, err)
|
||
} else {
|
||
fmt.Fprintf(p.writer, "❌ (%v)\n", err)
|
||
}
|
||
}
|
||
|
||
// SkipStep marks the current step as skipped
|
||
func (p *ProgressReporter) SkipStep(stepIndex int, reason string) {
|
||
if stepIndex < 0 || stepIndex >= len(p.steps) {
|
||
return
|
||
}
|
||
|
||
p.steps[stepIndex].Status = StepStatusSkipped
|
||
|
||
if p.verbose {
|
||
fmt.Fprintf(p.writer, "⏭️ Skipped: %s - %s\n",
|
||
p.steps[stepIndex].Description, reason)
|
||
} else {
|
||
fmt.Fprintf(p.writer, "⏭️ (%s)\n", reason)
|
||
}
|
||
}
|
||
|
||
// PrintSummary prints a summary of all steps
|
||
func (p *ProgressReporter) PrintSummary() {
|
||
totalDuration := time.Since(p.startTime)
|
||
|
||
fmt.Fprintf(p.writer, "\n📊 Build Summary:\n")
|
||
fmt.Fprintf(p.writer, " Total time: %v\n", totalDuration)
|
||
fmt.Fprintf(p.writer, " Steps completed: %d/%d\n",
|
||
p.getCompletedCount(), len(p.steps))
|
||
|
||
if p.verbose {
|
||
fmt.Fprintf(p.writer, "\n📋 Step Details:\n")
|
||
for i, step := range p.steps {
|
||
status := getStatusEmoji(step.Status)
|
||
fmt.Fprintf(p.writer, " %d. %s %s", i+1, status, step.Name)
|
||
if step.Duration > 0 {
|
||
fmt.Fprintf(p.writer, " (%v)", step.Duration)
|
||
}
|
||
fmt.Fprintf(p.writer, "\n")
|
||
}
|
||
}
|
||
}
|
||
|
||
// getCompletedCount returns the number of completed steps
|
||
func (p *ProgressReporter) getCompletedCount() int {
|
||
count := 0
|
||
for _, step := range p.steps {
|
||
if step.Status == StepStatusCompleted {
|
||
count++
|
||
}
|
||
}
|
||
return count
|
||
}
|
||
|
||
// getStatusEmoji returns an emoji for the step status
|
||
func getStatusEmoji(status StepStatus) string {
|
||
switch status {
|
||
case StepStatusPending:
|
||
return "⏳"
|
||
case StepStatusRunning:
|
||
return "🔄"
|
||
case StepStatusCompleted:
|
||
return "✅"
|
||
case StepStatusFailed:
|
||
return "❌"
|
||
case StepStatusSkipped:
|
||
return "⏭️"
|
||
default:
|
||
return "❓"
|
||
}
|
||
}
|
||
|
||
// Simple progress indicators for quick operations
|
||
|
||
// PrintProgress prints a simple progress indicator
|
||
func PrintProgress(writer io.Writer, message string) {
|
||
fmt.Fprintf(writer, "🔄 %s...\n", message)
|
||
}
|
||
|
||
// PrintSuccess prints a success message
|
||
func PrintSuccess(writer io.Writer, message string) {
|
||
fmt.Fprintf(writer, "✅ %s\n", message)
|
||
}
|
||
|
||
// PrintWarning prints a warning message
|
||
func PrintWarning(writer io.Writer, message string) {
|
||
fmt.Fprintf(writer, "⚠️ %s\n", message)
|
||
}
|
||
|
||
// PrintInfo prints an info message
|
||
func PrintInfo(writer io.Writer, message string) {
|
||
fmt.Fprintf(writer, "ℹ️ %s\n", message)
|
||
}
|
||
|
||
// PrintError prints an error message
|
||
func PrintError(writer io.Writer, message string) {
|
||
fmt.Fprintf(writer, "❌ %s\n", message)
|
||
}
|
||
|
||
// PrintStep prints a step message with optional details
|
||
func PrintStep(writer io.Writer, step, message string, verbose bool) {
|
||
if verbose {
|
||
fmt.Fprintf(writer, "🔄 [%s] %s\n", step, message)
|
||
} else {
|
||
fmt.Fprintf(writer, "🔄 %s\n", message)
|
||
}
|
||
}
|