mirror of
https://github.com/restic/restic.git
synced 2026-08-14 01:23:18 +00:00
stats: refactor ui progress printer into ui/stats
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/restic/restic/internal/ui"
|
||||
"github.com/restic/restic/internal/ui/progress"
|
||||
)
|
||||
|
||||
// Progress reports progress for the stats command.
|
||||
type Progress struct {
|
||||
progress.Updater
|
||||
|
||||
term ui.Terminal
|
||||
m sync.Mutex
|
||||
snapshotCount uint64
|
||||
show bool
|
||||
|
||||
processedSnapshotCount uint64
|
||||
processedFileCount uint64
|
||||
processedBlobCount uint64
|
||||
processedSize uint64
|
||||
}
|
||||
|
||||
// NewProgress returns a new stats progress reporter.
|
||||
func NewProgress(term ui.Terminal, quiet, json bool, snapshotCount uint64) *Progress {
|
||||
p := newProgress(term, !json, snapshotCount)
|
||||
p.Updater = *progress.NewUpdater(
|
||||
progress.CalculateProgressInterval(!quiet, json, term.CanUpdateStatus()),
|
||||
p.printProgress,
|
||||
)
|
||||
return p
|
||||
}
|
||||
|
||||
func newProgress(term ui.Terminal, show bool, snapshotCount uint64) *Progress {
|
||||
return &Progress{
|
||||
term: term,
|
||||
snapshotCount: snapshotCount,
|
||||
show: show,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Progress) printProgress(runtime time.Duration, final bool) {
|
||||
if !p.show {
|
||||
return
|
||||
}
|
||||
p.m.Lock()
|
||||
|
||||
progressBase := p.processedSnapshotCount
|
||||
if progressBase > 0 && !final {
|
||||
progressBase--
|
||||
}
|
||||
|
||||
status := fmt.Sprintf("[%s] %s %d / %d snapshots", ui.FormatDuration(runtime), ui.FormatPercent(progressBase, p.snapshotCount), p.processedSnapshotCount, p.snapshotCount)
|
||||
|
||||
if p.processedFileCount > 0 {
|
||||
status += fmt.Sprintf(", %v files", p.processedFileCount)
|
||||
}
|
||||
|
||||
if p.processedBlobCount > 0 {
|
||||
status += fmt.Sprintf(", %d blobs", p.processedBlobCount)
|
||||
}
|
||||
|
||||
status += fmt.Sprintf(", %s", ui.FormatBytes(p.processedSize))
|
||||
p.m.Unlock()
|
||||
|
||||
if final {
|
||||
p.term.SetStatus(nil)
|
||||
p.term.Print(status)
|
||||
} else {
|
||||
p.term.SetStatus([]string{status})
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Progress) Update(fileCount uint64, blobCount uint64, size uint64) {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
|
||||
p.processedFileCount += fileCount
|
||||
p.processedBlobCount += blobCount
|
||||
p.processedSize += size
|
||||
}
|
||||
|
||||
func (p *Progress) ProcessSnapshot() {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
|
||||
p.processedSnapshotCount++
|
||||
p.processedFileCount = 0
|
||||
p.processedBlobCount = 0
|
||||
p.processedSize = 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
rtest "github.com/restic/restic/internal/test"
|
||||
"github.com/restic/restic/internal/ui"
|
||||
)
|
||||
|
||||
func TestStatsProgress(t *testing.T) {
|
||||
term := &ui.MockTerminal{}
|
||||
|
||||
progress := newProgress(term, true, 2)
|
||||
progress.printProgress(0*time.Second, false)
|
||||
rtest.Equals(t, []string{"[0:00] 0.00% 0 / 2 snapshots, 0 B"}, term.Output)
|
||||
|
||||
progress.ProcessSnapshot()
|
||||
progress.Update(1, 2, 3)
|
||||
progress.printProgress(5*time.Second, false)
|
||||
// Output differs from the previous one because the progress is based on the number of processed snapshots,
|
||||
// 1/2 snapshots means processing the snapshot 1 currently
|
||||
rtest.Equals(t, []string{"[0:05] 0.00% 1 / 2 snapshots, 1 files, 2 blobs, 3 B"}, term.Output)
|
||||
|
||||
progress.ProcessSnapshot()
|
||||
progress.printProgress(10*time.Second, false)
|
||||
rtest.Equals(t, []string{"[0:10] 50.00% 2 / 2 snapshots, 0 B"}, term.Output)
|
||||
|
||||
progress.Update(4, 5, 6)
|
||||
progress.printProgress(15*time.Second, false)
|
||||
rtest.Equals(t, []string{"[0:15] 50.00% 2 / 2 snapshots, 4 files, 5 blobs, 6 B"}, term.Output)
|
||||
|
||||
progress.printProgress(20*time.Second, true)
|
||||
rtest.Equals(t, []string{"[0:20] 100.00% 2 / 2 snapshots, 4 files, 5 blobs, 6 B"}, term.Output)
|
||||
}
|
||||
|
||||
func TestStatsProgressJSON(t *testing.T) {
|
||||
term := &ui.MockTerminal{}
|
||||
|
||||
progress := newProgress(term, false, 2)
|
||||
progress.printProgress(0*time.Second, false)
|
||||
// JSON output is not available yet, so just make sure to not break normal json output
|
||||
rtest.Equals(t, nil, term.Output)
|
||||
}
|
||||
Reference in New Issue
Block a user