1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
package restore
import (
"sync"
"time"
"github.com/restic/restic/internal/ui/progress"
)
type State struct {
FilesFinished uint64
FilesTotal uint64
FilesSkipped uint64
FilesDeleted uint64
AllBytesWritten uint64
AllBytesTotal uint64
AllBytesSkipped uint64
}
type Progress struct {
updater progress.Updater
m sync.Mutex
progressInfoMap map[string]progressInfoEntry
s State
started time.Time
printer ProgressPrinter
}
type progressInfoEntry struct {
bytesWritten uint64
bytesTotal uint64
}
type ProgressPrinter interface {
Update(progress State, duration time.Duration)
Error(item string, err error) error
CompleteItem(action ItemAction, item string, size uint64)
Finish(progress State, duration time.Duration)
}
type ItemAction string
// Constants for the different CompleteItem actions.
const (
ActionDirRestored ItemAction = "dir restored"
ActionFileRestored ItemAction = "file restored"
ActionFileUpdated ItemAction = "file updated"
ActionFileUnchanged ItemAction = "file unchanged"
ActionOtherRestored ItemAction = "other restored"
ActionDeleted ItemAction = "deleted"
)
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.s, runtime)
} else {
p.printer.Finish(p.s, runtime)
}
}
// AddFile starts tracking a new file with the given size
func (p *Progress) AddFile(size uint64) {
if p == nil {
return
}
p.m.Lock()
defer p.m.Unlock()
p.s.FilesTotal++
p.s.AllBytesTotal += size
}
// AddProgress accumulates the number of bytes written for a file
func (p *Progress) AddProgress(name string, action ItemAction, bytesWrittenPortion uint64, bytesTotal uint64) {
if p == nil {
return
}
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.s.AllBytesWritten += bytesWrittenPortion
if entry.bytesWritten == entry.bytesTotal {
delete(p.progressInfoMap, name)
p.s.FilesFinished++
p.printer.CompleteItem(action, name, bytesTotal)
}
}
func (p *Progress) AddSkippedFile(name string, size uint64) {
if p == nil {
return
}
p.m.Lock()
defer p.m.Unlock()
p.s.FilesSkipped++
p.s.AllBytesSkipped += size
p.printer.CompleteItem(ActionFileUnchanged, name, size)
}
func (p *Progress) ReportDeletion(name string) {
if p == nil {
return
}
p.s.FilesDeleted++
p.m.Lock()
defer p.m.Unlock()
p.printer.CompleteItem(ActionDeleted, name, 0)
}
func (p *Progress) Error(item string, err error) error {
if p == nil {
return nil
}
p.m.Lock()
defer p.m.Unlock()
return p.printer.Error(item, err)
}
func (p *Progress) Finish() {
p.updater.Done()
}
|