Only display the message if there were locks to be removed

`restic unlock` now only shows `successfully removed locks` if there were locks to be removed.
In addition, it also reports the number of the removed lock files.
This commit is contained in:
Miles Liu 2022-09-18 18:40:19 +08:00
parent b48766d7b8
commit 1acbda18f8
No known key found for this signature in database
GPG Key ID: 4DB9B32F9B24A7A9
4 changed files with 39 additions and 10 deletions

View File

@ -0,0 +1,7 @@
Enhancement: Only display the message if there were locks to be removed
`restic unlock` now only shows `successfully removed locks` if there were locks to be removed.
In addition, it also reports the number of the removed lock files.
https://github.com/restic/restic/issues/3929
https://github.com/restic/restic/pull/3935

View File

@ -46,11 +46,13 @@ func runUnlock(opts UnlockOptions, gopts GlobalOptions) error {
fn = restic.RemoveAllLocks fn = restic.RemoveAllLocks
} }
err = fn(gopts.ctx, repo) processed, err := fn(gopts.ctx, repo)
if err != nil { if err != nil {
return err return err
} }
Verbosef("successfully removed locks\n") if processed > 0 {
Verbosef("successfully removed %d locks\n", processed)
}
return nil return nil
} }

View File

@ -264,8 +264,9 @@ func LoadLock(ctx context.Context, repo Repository, id ID) (*Lock, error) {
} }
// RemoveStaleLocks deletes all locks detected as stale from the repository. // RemoveStaleLocks deletes all locks detected as stale from the repository.
func RemoveStaleLocks(ctx context.Context, repo Repository) error { func RemoveStaleLocks(ctx context.Context, repo Repository) (uint, error) {
return ForAllLocks(ctx, repo, nil, func(id ID, lock *Lock, err error) error { var processed uint
err := ForAllLocks(ctx, repo, nil, func(id ID, lock *Lock, err error) error {
if err != nil { if err != nil {
// ignore locks that cannot be loaded // ignore locks that cannot be loaded
debug.Log("ignore lock %v: %v", id, err) debug.Log("ignore lock %v: %v", id, err)
@ -273,18 +274,29 @@ func RemoveStaleLocks(ctx context.Context, repo Repository) error {
} }
if lock.Stale() { if lock.Stale() {
return repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()}) err = repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()})
if err == nil {
processed++
}
return err
} }
return nil return nil
}) })
return processed, err
} }
// RemoveAllLocks removes all locks forcefully. // RemoveAllLocks removes all locks forcefully.
func RemoveAllLocks(ctx context.Context, repo Repository) error { func RemoveAllLocks(ctx context.Context, repo Repository) (uint, error) {
return repo.List(ctx, LockFile, func(id ID, size int64) error { var processed uint
return repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()}) err := repo.List(ctx, LockFile, func(id ID, size int64) error {
err := repo.Backend().Remove(ctx, Handle{Type: LockFile, Name: id.String()})
if err == nil {
processed++
}
return err
}) })
return processed, err
} }
// ForAllLocks reads all locks in parallel and calls the given callback. // ForAllLocks reads all locks in parallel and calls the given callback.

View File

@ -184,7 +184,8 @@ func TestLockWithStaleLock(t *testing.T) {
id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000) id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000)
rtest.OK(t, err) rtest.OK(t, err)
rtest.OK(t, restic.RemoveStaleLocks(context.TODO(), repo)) processed, err := restic.RemoveStaleLocks(context.TODO(), repo)
rtest.OK(t, err)
rtest.Assert(t, lockExists(repo, t, id1) == false, rtest.Assert(t, lockExists(repo, t, id1) == false,
"stale lock still exists after RemoveStaleLocks was called") "stale lock still exists after RemoveStaleLocks was called")
@ -192,6 +193,9 @@ func TestLockWithStaleLock(t *testing.T) {
"non-stale lock was removed by RemoveStaleLocks") "non-stale lock was removed by RemoveStaleLocks")
rtest.Assert(t, lockExists(repo, t, id3) == false, rtest.Assert(t, lockExists(repo, t, id3) == false,
"stale lock still exists after RemoveStaleLocks was called") "stale lock still exists after RemoveStaleLocks was called")
rtest.Assert(t, processed == 2,
"number of locks removed does not match: expected %d, got %d",
2, processed)
rtest.OK(t, removeLock(repo, id2)) rtest.OK(t, removeLock(repo, id2))
} }
@ -209,7 +213,8 @@ func TestRemoveAllLocks(t *testing.T) {
id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000) id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000)
rtest.OK(t, err) rtest.OK(t, err)
rtest.OK(t, restic.RemoveAllLocks(context.TODO(), repo)) processed, err := restic.RemoveAllLocks(context.TODO(), repo)
rtest.OK(t, err)
rtest.Assert(t, lockExists(repo, t, id1) == false, rtest.Assert(t, lockExists(repo, t, id1) == false,
"lock still exists after RemoveAllLocks was called") "lock still exists after RemoveAllLocks was called")
@ -217,6 +222,9 @@ func TestRemoveAllLocks(t *testing.T) {
"lock still exists after RemoveAllLocks was called") "lock still exists after RemoveAllLocks was called")
rtest.Assert(t, lockExists(repo, t, id3) == false, rtest.Assert(t, lockExists(repo, t, id3) == false,
"lock still exists after RemoveAllLocks was called") "lock still exists after RemoveAllLocks was called")
rtest.Assert(t, processed == 3,
"number of locks removed does not match: expected %d, got %d",
3, processed)
} }
func TestLockRefresh(t *testing.T) { func TestLockRefresh(t *testing.T) {