forked from TrueCloudLab/restic
restore/ui: refactor for extensibility
This commit is contained in:
parent
6a4ae9d6b1
commit
64b7b6b975
6 changed files with 57 additions and 53 deletions
|
@ -20,31 +20,31 @@ func (t *jsonPrinter) print(status interface{}) {
|
|||
t.terminal.Print(ui.ToJSONString(status))
|
||||
}
|
||||
|
||||
func (t *jsonPrinter) Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
||||
func (t *jsonPrinter) Update(p State, duration time.Duration) {
|
||||
status := statusUpdate{
|
||||
MessageType: "status",
|
||||
SecondsElapsed: uint64(duration / time.Second),
|
||||
TotalFiles: filesTotal,
|
||||
FilesRestored: filesFinished,
|
||||
TotalBytes: allBytesTotal,
|
||||
BytesRestored: allBytesWritten,
|
||||
TotalFiles: p.FilesTotal,
|
||||
FilesRestored: p.FilesFinished,
|
||||
TotalBytes: p.AllBytesTotal,
|
||||
BytesRestored: p.AllBytesWritten,
|
||||
}
|
||||
|
||||
if allBytesTotal > 0 {
|
||||
status.PercentDone = float64(allBytesWritten) / float64(allBytesTotal)
|
||||
if p.AllBytesTotal > 0 {
|
||||
status.PercentDone = float64(p.AllBytesWritten) / float64(p.AllBytesTotal)
|
||||
}
|
||||
|
||||
t.print(status)
|
||||
}
|
||||
|
||||
func (t *jsonPrinter) Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
||||
func (t *jsonPrinter) Finish(p State, duration time.Duration) {
|
||||
status := summaryOutput{
|
||||
MessageType: "summary",
|
||||
SecondsElapsed: uint64(duration / time.Second),
|
||||
TotalFiles: filesTotal,
|
||||
FilesRestored: filesFinished,
|
||||
TotalBytes: allBytesTotal,
|
||||
BytesRestored: allBytesWritten,
|
||||
TotalFiles: p.FilesTotal,
|
||||
FilesRestored: p.FilesFinished,
|
||||
TotalBytes: p.AllBytesTotal,
|
||||
BytesRestored: p.AllBytesWritten,
|
||||
}
|
||||
t.print(status)
|
||||
}
|
||||
|
|
|
@ -10,20 +10,20 @@ import (
|
|||
func TestJSONPrintUpdate(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewJSONProgress(term)
|
||||
printer.Update(3, 11, 29, 47, 5*time.Second)
|
||||
printer.Update(State{3, 11, 29, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"{\"message_type\":\"status\",\"seconds_elapsed\":5,\"percent_done\":0.6170212765957447,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.output)
|
||||
}
|
||||
|
||||
func TestJSONPrintSummaryOnSuccess(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewJSONProgress(term)
|
||||
printer.Finish(11, 11, 47, 47, 5*time.Second)
|
||||
printer.Finish(State{11, 11, 47, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":11,\"total_bytes\":47,\"bytes_restored\":47}\n"}, term.output)
|
||||
}
|
||||
|
||||
func TestJSONPrintSummaryOnErrors(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewJSONProgress(term)
|
||||
printer.Finish(3, 11, 29, 47, 5*time.Second)
|
||||
printer.Finish(State{3, 11, 29, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"{\"message_type\":\"summary\",\"seconds_elapsed\":5,\"total_files\":11,\"files_restored\":3,\"total_bytes\":47,\"bytes_restored\":29}\n"}, term.output)
|
||||
}
|
||||
|
|
|
@ -7,15 +7,19 @@ import (
|
|||
"github.com/restic/restic/internal/ui/progress"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
FilesFinished uint64
|
||||
FilesTotal uint64
|
||||
AllBytesWritten uint64
|
||||
AllBytesTotal uint64
|
||||
}
|
||||
|
||||
type Progress struct {
|
||||
updater progress.Updater
|
||||
m sync.Mutex
|
||||
|
||||
progressInfoMap map[string]progressInfoEntry
|
||||
filesFinished uint64
|
||||
filesTotal uint64
|
||||
allBytesWritten uint64
|
||||
allBytesTotal uint64
|
||||
s State
|
||||
started time.Time
|
||||
|
||||
printer ProgressPrinter
|
||||
|
@ -32,8 +36,8 @@ type term interface {
|
|||
}
|
||||
|
||||
type ProgressPrinter interface {
|
||||
Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration)
|
||||
Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration)
|
||||
Update(progress State, duration time.Duration)
|
||||
Finish(progress State, duration time.Duration)
|
||||
}
|
||||
|
||||
func NewProgress(printer ProgressPrinter, interval time.Duration) *Progress {
|
||||
|
@ -51,9 +55,9 @@ func (p *Progress) update(runtime time.Duration, final bool) {
|
|||
defer p.m.Unlock()
|
||||
|
||||
if !final {
|
||||
p.printer.Update(p.filesFinished, p.filesTotal, p.allBytesWritten, p.allBytesTotal, runtime)
|
||||
p.printer.Update(p.s, runtime)
|
||||
} else {
|
||||
p.printer.Finish(p.filesFinished, p.filesTotal, p.allBytesWritten, p.allBytesTotal, runtime)
|
||||
p.printer.Finish(p.s, runtime)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,8 +70,8 @@ func (p *Progress) AddFile(size uint64) {
|
|||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
|
||||
p.filesTotal++
|
||||
p.allBytesTotal += size
|
||||
p.s.FilesTotal++
|
||||
p.s.AllBytesTotal += size
|
||||
}
|
||||
|
||||
// AddProgress accumulates the number of bytes written for a file
|
||||
|
@ -86,10 +90,10 @@ func (p *Progress) AddProgress(name string, bytesWrittenPortion uint64, bytesTot
|
|||
entry.bytesWritten += bytesWrittenPortion
|
||||
p.progressInfoMap[name] = entry
|
||||
|
||||
p.allBytesWritten += bytesWrittenPortion
|
||||
p.s.AllBytesWritten += bytesWrittenPortion
|
||||
if entry.bytesWritten == entry.bytesTotal {
|
||||
delete(p.progressInfoMap, name)
|
||||
p.filesFinished++
|
||||
p.s.FilesFinished++
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
type printerTraceEntry struct {
|
||||
filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64
|
||||
progress State
|
||||
|
||||
duration time.Duration
|
||||
isFinished bool
|
||||
|
@ -22,11 +22,11 @@ type mockPrinter struct {
|
|||
|
||||
const mockFinishDuration = 42 * time.Second
|
||||
|
||||
func (p *mockPrinter) Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
||||
p.trace = append(p.trace, printerTraceEntry{filesFinished, filesTotal, allBytesWritten, allBytesTotal, duration, false})
|
||||
func (p *mockPrinter) Update(progress State, duration time.Duration) {
|
||||
p.trace = append(p.trace, printerTraceEntry{progress, duration, false})
|
||||
}
|
||||
func (p *mockPrinter) Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, _ time.Duration) {
|
||||
p.trace = append(p.trace, printerTraceEntry{filesFinished, filesTotal, allBytesWritten, allBytesTotal, mockFinishDuration, true})
|
||||
func (p *mockPrinter) Finish(progress State, _ time.Duration) {
|
||||
p.trace = append(p.trace, printerTraceEntry{progress, mockFinishDuration, true})
|
||||
}
|
||||
|
||||
func testProgress(fn func(progress *Progress) bool) printerTrace {
|
||||
|
@ -45,7 +45,7 @@ func TestNew(t *testing.T) {
|
|||
return false
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{0, 0, 0, 0, 0, false},
|
||||
printerTraceEntry{State{0, 0, 0, 0}, 0, false},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ func TestAddFile(t *testing.T) {
|
|||
return false
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{0, 1, 0, fileSize, 0, false},
|
||||
printerTraceEntry{State{0, 1, 0, fileSize}, 0, false},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ func TestFirstProgressOnAFile(t *testing.T) {
|
|||
return false
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{0, 1, expectedBytesWritten, expectedBytesTotal, 0, false},
|
||||
printerTraceEntry{State{0, 1, expectedBytesWritten, expectedBytesTotal}, 0, false},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ func TestLastProgressOnAFile(t *testing.T) {
|
|||
return false
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{1, 1, fileSize, fileSize, 0, false},
|
||||
printerTraceEntry{State{1, 1, fileSize, fileSize}, 0, false},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ func TestLastProgressOnLastFile(t *testing.T) {
|
|||
return false
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{2, 2, 50 + fileSize, 50 + fileSize, 0, false},
|
||||
printerTraceEntry{State{2, 2, 50 + fileSize, 50 + fileSize}, 0, false},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ func TestSummaryOnSuccess(t *testing.T) {
|
|||
return true
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{2, 2, 50 + fileSize, 50 + fileSize, mockFinishDuration, true},
|
||||
printerTraceEntry{State{2, 2, 50 + fileSize, 50 + fileSize}, mockFinishDuration, true},
|
||||
}, result)
|
||||
}
|
||||
|
||||
|
@ -132,6 +132,6 @@ func TestSummaryOnErrors(t *testing.T) {
|
|||
return true
|
||||
})
|
||||
test.Equals(t, printerTrace{
|
||||
printerTraceEntry{1, 2, 50 + fileSize/2, 50 + fileSize, mockFinishDuration, true},
|
||||
printerTraceEntry{State{1, 2, 50 + fileSize/2, 50 + fileSize}, mockFinishDuration, true},
|
||||
}, result)
|
||||
}
|
||||
|
|
|
@ -17,30 +17,30 @@ func NewTextProgress(terminal term) ProgressPrinter {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *textPrinter) Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
||||
func (t *textPrinter) Update(p State, duration time.Duration) {
|
||||
timeLeft := ui.FormatDuration(duration)
|
||||
formattedAllBytesWritten := ui.FormatBytes(allBytesWritten)
|
||||
formattedAllBytesTotal := ui.FormatBytes(allBytesTotal)
|
||||
allPercent := ui.FormatPercent(allBytesWritten, allBytesTotal)
|
||||
formattedAllBytesWritten := ui.FormatBytes(p.AllBytesWritten)
|
||||
formattedAllBytesTotal := ui.FormatBytes(p.AllBytesTotal)
|
||||
allPercent := ui.FormatPercent(p.AllBytesWritten, p.AllBytesTotal)
|
||||
progress := fmt.Sprintf("[%s] %s %v files/dirs %s, total %v files/dirs %v",
|
||||
timeLeft, allPercent, filesFinished, formattedAllBytesWritten, filesTotal, formattedAllBytesTotal)
|
||||
timeLeft, allPercent, p.FilesFinished, formattedAllBytesWritten, p.FilesTotal, formattedAllBytesTotal)
|
||||
|
||||
t.terminal.SetStatus([]string{progress})
|
||||
}
|
||||
|
||||
func (t *textPrinter) Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) {
|
||||
func (t *textPrinter) Finish(p State, duration time.Duration) {
|
||||
t.terminal.SetStatus([]string{})
|
||||
|
||||
timeLeft := ui.FormatDuration(duration)
|
||||
formattedAllBytesTotal := ui.FormatBytes(allBytesTotal)
|
||||
formattedAllBytesTotal := ui.FormatBytes(p.AllBytesTotal)
|
||||
|
||||
var summary string
|
||||
if filesFinished == filesTotal && allBytesWritten == allBytesTotal {
|
||||
summary = fmt.Sprintf("Summary: Restored %d files/dirs (%s) in %s", filesTotal, formattedAllBytesTotal, timeLeft)
|
||||
if p.FilesFinished == p.FilesTotal && p.AllBytesWritten == p.AllBytesTotal {
|
||||
summary = fmt.Sprintf("Summary: Restored %d files/dirs (%s) in %s", p.FilesTotal, formattedAllBytesTotal, timeLeft)
|
||||
} else {
|
||||
formattedAllBytesWritten := ui.FormatBytes(allBytesWritten)
|
||||
formattedAllBytesWritten := ui.FormatBytes(p.AllBytesWritten)
|
||||
summary = fmt.Sprintf("Summary: Restored %d / %d files/dirs (%s / %s) in %s",
|
||||
filesFinished, filesTotal, formattedAllBytesWritten, formattedAllBytesTotal, timeLeft)
|
||||
p.FilesFinished, p.FilesTotal, formattedAllBytesWritten, formattedAllBytesTotal, timeLeft)
|
||||
}
|
||||
|
||||
t.terminal.Print(summary)
|
||||
|
|
|
@ -22,20 +22,20 @@ func (m *mockTerm) SetStatus(lines []string) {
|
|||
func TestPrintUpdate(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewTextProgress(term)
|
||||
printer.Update(3, 11, 29, 47, 5*time.Second)
|
||||
printer.Update(State{3, 11, 29, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"[0:05] 61.70% 3 files/dirs 29 B, total 11 files/dirs 47 B"}, term.output)
|
||||
}
|
||||
|
||||
func TestPrintSummaryOnSuccess(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewTextProgress(term)
|
||||
printer.Finish(11, 11, 47, 47, 5*time.Second)
|
||||
printer.Finish(State{11, 11, 47, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"Summary: Restored 11 files/dirs (47 B) in 0:05"}, term.output)
|
||||
}
|
||||
|
||||
func TestPrintSummaryOnErrors(t *testing.T) {
|
||||
term := &mockTerm{}
|
||||
printer := NewTextProgress(term)
|
||||
printer.Finish(3, 11, 29, 47, 5*time.Second)
|
||||
printer.Finish(State{3, 11, 29, 47}, 5*time.Second)
|
||||
test.Equals(t, []string{"Summary: Restored 3 / 11 files/dirs (29 B / 47 B) in 0:05"}, term.output)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue