feat: add progress bar to restore operation
Add an interactive progress bar (using schollz/progressbar) to the file restore loop, matching the existing pattern in verify. Shows bytes restored with ETA when output is a terminal, falls back to structured log progress every 100 files otherwise. Fixes #20
This commit is contained in:
parent
d8a51804d2
commit
82a93c4be6
@ -115,6 +115,30 @@ func (v *Vaultik) Restore(opts *RestoreOptions) error {
|
|||||||
}
|
}
|
||||||
defer func() { _ = blobCache.Close() }()
|
defer func() { _ = blobCache.Close() }()
|
||||||
|
|
||||||
|
// Calculate total bytes for progress bar
|
||||||
|
var totalBytesExpected int64
|
||||||
|
for _, file := range files {
|
||||||
|
totalBytesExpected += file.Size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create progress bar if output is a terminal
|
||||||
|
var bar *progressbar.ProgressBar
|
||||||
|
if isTerminal() {
|
||||||
|
bar = progressbar.NewOptions64(
|
||||||
|
totalBytesExpected,
|
||||||
|
progressbar.OptionSetDescription("Restoring"),
|
||||||
|
progressbar.OptionSetWriter(v.Stderr),
|
||||||
|
progressbar.OptionShowBytes(true),
|
||||||
|
progressbar.OptionShowCount(),
|
||||||
|
progressbar.OptionSetWidth(40),
|
||||||
|
progressbar.OptionThrottle(100*time.Millisecond),
|
||||||
|
progressbar.OptionOnCompletion(func() {
|
||||||
|
v.printfStderr("\n")
|
||||||
|
}),
|
||||||
|
progressbar.OptionSetRenderBlankState(true),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
for i, file := range files {
|
for i, file := range files {
|
||||||
if v.ctx.Err() != nil {
|
if v.ctx.Err() != nil {
|
||||||
return v.ctx.Err()
|
return v.ctx.Err()
|
||||||
@ -124,11 +148,19 @@ func (v *Vaultik) Restore(opts *RestoreOptions) error {
|
|||||||
log.Error("Failed to restore file", "path", file.Path, "error", err)
|
log.Error("Failed to restore file", "path", file.Path, "error", err)
|
||||||
result.FilesFailed++
|
result.FilesFailed++
|
||||||
result.FailedFiles = append(result.FailedFiles, file.Path.String())
|
result.FailedFiles = append(result.FailedFiles, file.Path.String())
|
||||||
// Continue with other files
|
// Update progress bar even on failure
|
||||||
|
if bar != nil {
|
||||||
|
_ = bar.Add64(file.Size)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Progress logging
|
// Update progress bar
|
||||||
|
if bar != nil {
|
||||||
|
_ = bar.Add64(file.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress logging (for non-terminal or structured logs)
|
||||||
if (i+1)%100 == 0 || i+1 == len(files) {
|
if (i+1)%100 == 0 || i+1 == len(files) {
|
||||||
log.Info("Restore progress",
|
log.Info("Restore progress",
|
||||||
"files", fmt.Sprintf("%d/%d", i+1, len(files)),
|
"files", fmt.Sprintf("%d/%d", i+1, len(files)),
|
||||||
@ -137,6 +169,10 @@ func (v *Vaultik) Restore(opts *RestoreOptions) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bar != nil {
|
||||||
|
_ = bar.Finish()
|
||||||
|
}
|
||||||
|
|
||||||
result.Duration = time.Since(startTime)
|
result.Duration = time.Since(startTime)
|
||||||
|
|
||||||
log.Info("Restore complete",
|
log.Info("Restore complete",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user