diff --git a/checker/checker.go b/checker/checker.go index 8f9a39905..ecd2ed626 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -639,6 +639,11 @@ func (c *Checker) OrphanedPacks() backend.IDs { return c.orphanedPacks } +// CountPacks returns the number of packs in the repository. +func (c *Checker) CountPacks() uint64 { + return uint64(len(c.packs)) +} + // checkPack reads a pack and checks the integrity of all blobs. func checkPack(r *repository.Repository, id backend.ID) error { debug.Log("Checker.checkPack", "checking pack %v", id.Str()) @@ -690,9 +695,12 @@ func checkPack(r *repository.Repository, id backend.ID) error { } // ReadData loads all data from the repository and checks the integrity. -func (c *Checker) ReadData(errChan chan<- error, done <-chan struct{}) { +func (c *Checker) ReadData(p *restic.Progress, errChan chan<- error, done <-chan struct{}) { defer close(errChan) + p.Start() + defer p.Done() + worker := func(wg *sync.WaitGroup, in <-chan backend.ID) { defer wg.Done() for { @@ -709,6 +717,7 @@ func (c *Checker) ReadData(errChan chan<- error, done <-chan struct{}) { } err := checkPack(c.repo, id) + p.Report(restic.Stat{Blobs: 1}) if err == nil { continue } diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index 4712ba004..8c59c2ffe 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -4,7 +4,11 @@ import ( "errors" "fmt" "os" + "time" + "golang.org/x/crypto/ssh/terminal" + + "github.com/restic/restic" "github.com/restic/restic/checker" ) @@ -29,6 +33,37 @@ func (cmd CmdCheck) Usage() string { return "[check-options]" } +func (cmd CmdCheck) newReadProgress(todo restic.Stat) *restic.Progress { + if !cmd.global.ShowProgress() { + return nil + } + + readProgress := restic.NewProgress(time.Second) + + readProgress.OnUpdate = func(s restic.Stat, d time.Duration, ticker bool) { + status := fmt.Sprintf("[%s] %s %d / %d items", + formatDuration(d), + formatPercent(s.Blobs, todo.Blobs), + s.Blobs, todo.Blobs) + + w, _, err := terminal.GetSize(int(os.Stdout.Fd())) + if err == nil { + if len(status) > w { + max := w - len(status) - 4 + status = status[:max] + "... " + } + } + + fmt.Printf("\x1b[2K%s\r", status) + } + + readProgress.OnDone = func(s restic.Stat, d time.Duration, ticker bool) { + fmt.Printf("\nduration: %s\n", formatDuration(d)) + } + + return readProgress +} + func (cmd CmdCheck) Execute(args []string) error { if len(args) != 0 { return errors.New("check has no arguments") @@ -110,11 +145,12 @@ func (cmd CmdCheck) Execute(args []string) error { } if cmd.ReadData { - cmd.global.Verbosef("reading all data\n") + cmd.global.Verbosef("Read all data\n") + p := cmd.newReadProgress(restic.Stat{Blobs: chkr.CountPacks()}) errChan := make(chan error) - go chkr.ReadData(errChan, done) + go chkr.ReadData(p, errChan, done) for err := range errChan { errorsFound = true