mirror of
https://github.com/restic/restic.git
synced 2024-12-29 11:16:31 +00:00
f875a8843d
Co-authored-by: Mark Herrmann <mark.herrmann@mailbox.org>
131 lines
3.5 KiB
Go
131 lines
3.5 KiB
Go
package restore
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/restic/restic/internal/ui"
|
|
"github.com/restic/restic/internal/ui/progress"
|
|
)
|
|
|
|
type Progress struct {
|
|
updater progress.Updater
|
|
m sync.Mutex
|
|
|
|
progressInfoMap map[string]progressInfoEntry
|
|
filesFinished uint64
|
|
filesTotal uint64
|
|
allBytesWritten uint64
|
|
allBytesTotal uint64
|
|
started time.Time
|
|
|
|
printer ProgressPrinter
|
|
}
|
|
|
|
type progressInfoEntry struct {
|
|
bytesWritten uint64
|
|
bytesTotal uint64
|
|
}
|
|
|
|
type ProgressPrinter interface {
|
|
Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration)
|
|
Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration)
|
|
}
|
|
|
|
func NewProgress(printer ProgressPrinter, interval time.Duration) *Progress {
|
|
p := &Progress{
|
|
progressInfoMap: make(map[string]progressInfoEntry),
|
|
started: time.Now(),
|
|
printer: printer,
|
|
}
|
|
p.updater = *progress.NewUpdater(interval, p.update)
|
|
return p
|
|
}
|
|
|
|
func (p *Progress) update(runtime time.Duration, final bool) {
|
|
p.m.Lock()
|
|
defer p.m.Unlock()
|
|
|
|
if !final {
|
|
p.printer.Update(p.filesFinished, p.filesTotal, p.allBytesWritten, p.allBytesTotal, runtime)
|
|
} else {
|
|
p.printer.Finish(p.filesFinished, p.filesTotal, p.allBytesWritten, p.allBytesTotal, runtime)
|
|
}
|
|
}
|
|
|
|
// AddFile starts tracking a new file with the given size
|
|
func (p *Progress) AddFile(size uint64) {
|
|
p.m.Lock()
|
|
defer p.m.Unlock()
|
|
|
|
p.filesTotal++
|
|
p.allBytesTotal += size
|
|
}
|
|
|
|
// AddProgress accumulates the number of bytes written for a file
|
|
func (p *Progress) AddProgress(name string, bytesWrittenPortion uint64, bytesTotal uint64) {
|
|
p.m.Lock()
|
|
defer p.m.Unlock()
|
|
|
|
entry, exists := p.progressInfoMap[name]
|
|
if !exists {
|
|
entry.bytesTotal = bytesTotal
|
|
}
|
|
entry.bytesWritten += bytesWrittenPortion
|
|
p.progressInfoMap[name] = entry
|
|
|
|
p.allBytesWritten += bytesWrittenPortion
|
|
if entry.bytesWritten == entry.bytesTotal {
|
|
delete(p.progressInfoMap, name)
|
|
p.filesFinished++
|
|
}
|
|
}
|
|
|
|
func (p *Progress) Finish() {
|
|
p.updater.Done()
|
|
}
|
|
|
|
type term interface {
|
|
Print(line string)
|
|
SetStatus(lines []string)
|
|
}
|
|
|
|
type textPrinter struct {
|
|
terminal term
|
|
}
|
|
|
|
func NewProgressPrinter(terminal term) ProgressPrinter {
|
|
return &textPrinter{
|
|
terminal: terminal,
|
|
}
|
|
}
|
|
|
|
func (t *textPrinter) Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
|
timeLeft := ui.FormatDuration(duration)
|
|
formattedAllBytesWritten := ui.FormatBytes(allBytesWritten)
|
|
formattedAllBytesTotal := ui.FormatBytes(allBytesTotal)
|
|
allPercent := ui.FormatPercent(allBytesWritten, allBytesTotal)
|
|
progress := fmt.Sprintf("[%s] %s %v files %s, total %v files %v",
|
|
timeLeft, allPercent, filesFinished, formattedAllBytesWritten, filesTotal, formattedAllBytesTotal)
|
|
|
|
t.terminal.SetStatus([]string{progress})
|
|
}
|
|
|
|
func (t *textPrinter) Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
|
t.terminal.SetStatus([]string{})
|
|
|
|
timeLeft := ui.FormatDuration(duration)
|
|
formattedAllBytesTotal := ui.FormatBytes(allBytesTotal)
|
|
|
|
var summary string
|
|
if filesFinished == filesTotal && allBytesWritten == allBytesTotal {
|
|
summary = fmt.Sprintf("Summary: Restored %d Files (%s) in %s", filesTotal, formattedAllBytesTotal, timeLeft)
|
|
} else {
|
|
formattedAllBytesWritten := ui.FormatBytes(allBytesWritten)
|
|
summary = fmt.Sprintf("Summary: Restored %d / %d Files (%s / %s) in %s",
|
|
filesFinished, filesTotal, formattedAllBytesWritten, formattedAllBytesTotal, timeLeft)
|
|
}
|
|
|
|
t.terminal.Print(summary)
|
|
}
|