convert repository locking to use termstatus

This commit is contained in:
Michael Eischer
2025-09-14 11:17:40 +02:00
parent 9d3efc2088
commit 109a211fbe
32 changed files with 86 additions and 53 deletions

View File

@@ -511,7 +511,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
msg.P("open repository")
}
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, opts.DryRun)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, opts.DryRun, msg)
if err != nil {
return err
}

View File

@@ -73,7 +73,7 @@ func runCat(ctx context.Context, gopts GlobalOptions, args []string, term *terms
return err
}
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -239,7 +239,7 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts GlobalOptions, args
if !gopts.NoLock {
printer.P("create exclusive lock for repository\n")
}
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return summary, err
}

View File

@@ -81,13 +81,13 @@ func runCopy(ctx context.Context, opts CopyOptions, gopts GlobalOptions, args []
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, srcRepo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, srcRepo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}
defer unlock()
ctx, dstRepo, unlock, err := openWithAppendLock(ctx, secondaryGopts, false)
ctx, dstRepo, unlock, err := openWithAppendLock(ctx, secondaryGopts, false, printer)
if err != nil {
return err
}

View File

@@ -194,7 +194,7 @@ func runDebugDump(ctx context.Context, gopts GlobalOptions, args []string, term
return errors.Fatal("type not specified")
}
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}
@@ -465,7 +465,7 @@ func runDebugExamine(ctx context.Context, gopts GlobalOptions, opts DebugExamine
return fmt.Errorf("--extract-pack and --no-lock are mutually exclusive")
}
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -370,7 +370,7 @@ func runDiff(ctx context.Context, opts DiffOptions, gopts GlobalOptions, args []
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -148,7 +148,7 @@ func runDump(ctx context.Context, opts DumpOptions, gopts GlobalOptions, args []
splittedPath := splitPath(path.Clean(pathToPrint))
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -615,7 +615,7 @@ func runFind(ctx context.Context, opts FindOptions, gopts GlobalOptions, args []
return errors.Fatal("cannot have several ID types")
}
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -189,7 +189,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun && gopts.NoLock)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun && gopts.NoLock, printer)
if err != nil {
return err
}
@@ -343,7 +343,7 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
printer.P("%d snapshots have been removed, running prune\n", len(removeSnIDs))
}
pruneOptions.DryRun = opts.DryRun
return runPruneWithRepo(ctx, pruneOptions, gopts, repo, removeSnIDs, term)
return runPruneWithRepo(ctx, pruneOptions, gopts, repo, removeSnIDs, printer)
}
return nil

View File

@@ -62,7 +62,7 @@ func runKeyAdd(ctx context.Context, gopts GlobalOptions, opts KeyAddOptions, arg
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithAppendLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -48,7 +48,7 @@ func runKeyList(ctx context.Context, gopts GlobalOptions, args []string, term *t
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -57,7 +57,7 @@ func runKeyPasswd(ctx context.Context, gopts GlobalOptions, opts KeyPasswdOption
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -45,7 +45,7 @@ func runKeyRemove(ctx context.Context, gopts GlobalOptions, args []string, term
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -51,7 +51,7 @@ func runList(ctx context.Context, gopts GlobalOptions, args []string, term *term
return errors.Fatal("type not specified")
}
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock || args[0] == "locks")
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock || args[0] == "locks", printer)
if err != nil {
return err
}

View File

@@ -364,7 +364,7 @@ func runLs(ctx context.Context, opts LsOptions, gopts GlobalOptions, args []stri
return false
}
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, termPrinter)
if err != nil {
return err
}

View File

@@ -138,7 +138,7 @@ func applyMigrations(ctx context.Context, opts MigrateOptions, gopts GlobalOptio
func runMigrate(ctx context.Context, opts MigrateOptions, gopts GlobalOptions, args []string, term *termstatus.Terminal) error {
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -142,7 +142,7 @@ func runMount(ctx context.Context, opts MountOptions, gopts GlobalOptions, args
debug.Log("start mount")
defer debug.Log("finish mount")
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -128,7 +128,10 @@ func checkSnapshots(t testing.TB, gopts GlobalOptions, mountpoint string, snapsh
}
}
_, repo, unlock, err := openWithReadLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
_, repo, unlock, err := openWithReadLock(context.TODO(), gopts, false, printer)
rtest.OK(t, err)
defer unlock()

View File

@@ -169,7 +169,8 @@ func runPrune(ctx context.Context, opts PruneOptions, gopts GlobalOptions, term
return errors.Fatal("--no-lock is only applicable in combination with --dry-run for prune command")
}
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun && gopts.NoLock)
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun && gopts.NoLock, printer)
if err != nil {
return err
}
@@ -183,11 +184,10 @@ func runPrune(ctx context.Context, opts PruneOptions, gopts GlobalOptions, term
opts.unsafeRecovery = true
}
return runPruneWithRepo(ctx, opts, gopts, repo, restic.NewIDSet(), term)
return runPruneWithRepo(ctx, opts, gopts, repo, restic.NewIDSet(), printer)
}
func runPruneWithRepo(ctx context.Context, opts PruneOptions, gopts GlobalOptions, repo *repository.Repository, ignoreSnapshots restic.IDSet, term *termstatus.Terminal) error {
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
func runPruneWithRepo(ctx context.Context, opts PruneOptions, gopts GlobalOptions, repo *repository.Repository, ignoreSnapshots restic.IDSet, printer progress.Printer) error {
if repo.Cache() == nil {
printer.S("warning: running prune without a cache, this may be very slow!")
}

View File

@@ -50,7 +50,7 @@ func runRecover(ctx context.Context, gopts GlobalOptions, term *termstatus.Termi
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -74,7 +74,8 @@ func newRebuildIndexCommand() *cobra.Command {
func runRebuildIndex(ctx context.Context, opts RepairIndexOptions, gopts GlobalOptions, term *termstatus.Terminal) error {
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -54,7 +54,8 @@ func runRepairPacks(ctx context.Context, gopts GlobalOptions, term *termstatus.T
}
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -78,7 +78,7 @@ func (opts *RepairOptions) AddFlags(f *pflag.FlagSet) {
func runRepairSnapshots(ctx context.Context, gopts GlobalOptions, opts RepairOptions, args []string, term *termstatus.Terminal) error {
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, opts.DryRun, printer)
if err != nil {
return err
}

View File

@@ -131,7 +131,7 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
debug.Log("restore %v to %v", snapshotIDString, opts.Target)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, msg)
if err != nil {
return err
}

View File

@@ -306,9 +306,9 @@ func runRewrite(ctx context.Context, opts RewriteOptions, gopts GlobalOptions, a
if opts.Forget {
printer.P("create exclusive lock for repository")
ctx, repo, unlock, err = openWithExclusiveLock(ctx, gopts, opts.DryRun)
ctx, repo, unlock, err = openWithExclusiveLock(ctx, gopts, opts.DryRun, printer)
} else {
ctx, repo, unlock, err = openWithAppendLock(ctx, gopts, opts.DryRun)
ctx, repo, unlock, err = openWithAppendLock(ctx, gopts, opts.DryRun, printer)
}
if err != nil {
return err

View File

@@ -41,7 +41,10 @@ func createBasicRewriteRepo(t testing.TB, env *testEnvironment) restic.ID {
func getSnapshot(t testing.TB, snapshotID restic.ID, env *testEnvironment) *restic.Snapshot {
t.Helper()
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(env.gopts.JSON, env.gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -112,7 +115,10 @@ func testRewriteMetadata(t *testing.T, metadata snapshotMetadataArgs) {
createBasicRewriteRepo(t, env)
testRunRewriteExclude(t, env.gopts, []string{}, true, metadata)
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(env.gopts.JSON, env.gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -155,7 +161,10 @@ func TestRewriteSnaphotSummary(t *testing.T) {
snapshots := testListSnapshots(t, env.gopts, 1)
// replace snapshot by one without a summary
_, repo, unlock, err := openWithExclusiveLock(context.TODO(), env.gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(env.gopts.JSON, env.gopts.verbosity, term)
_, repo, unlock, err := openWithExclusiveLock(context.TODO(), env.gopts, false, printer)
rtest.OK(t, err)
sn, err := restic.LoadSnapshot(context.TODO(), repo, snapshots[0])
rtest.OK(t, err)

View File

@@ -71,7 +71,7 @@ func (opts *SnapshotOptions) AddFlags(f *pflag.FlagSet) {
func runSnapshots(ctx context.Context, opts SnapshotOptions, gopts GlobalOptions, args []string, term *termstatus.Terminal) error {
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -104,7 +104,7 @@ func runStats(ctx context.Context, opts StatsOptions, gopts GlobalOptions, args
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock)
ctx, repo, unlock, err := openWithReadLock(ctx, gopts, gopts.NoLock, printer)
if err != nil {
return err
}

View File

@@ -130,7 +130,7 @@ func runTag(ctx context.Context, opts TagOptions, gopts GlobalOptions, term *ter
}
printer.P("create exclusive lock for repository")
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false)
ctx, repo, unlock, err := openWithExclusiveLock(ctx, gopts, false, printer)
if err != nil {
return err
}

View File

@@ -246,7 +246,10 @@ func testSetupBackupData(t testing.TB, env *testEnvironment) string {
}
func listPacks(gopts GlobalOptions, t *testing.T) restic.IDSet {
ctx, r, unlock, err := openWithReadLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, r, unlock, err := openWithReadLock(context.TODO(), gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -260,7 +263,10 @@ func listPacks(gopts GlobalOptions, t *testing.T) restic.IDSet {
}
func listTreePacks(gopts GlobalOptions, t *testing.T) restic.IDSet {
ctx, r, unlock, err := openWithReadLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, r, unlock, err := openWithReadLock(context.TODO(), gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -288,7 +294,10 @@ func captureBackend(gopts *GlobalOptions) func() backend.Backend {
func removePacks(gopts GlobalOptions, t testing.TB, remove restic.IDSet) {
be := captureBackend(&gopts)
ctx, _, unlock, err := openWithExclusiveLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, _, unlock, err := openWithExclusiveLock(context.TODO(), gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -299,7 +308,10 @@ func removePacks(gopts GlobalOptions, t testing.TB, remove restic.IDSet) {
func removePacksExcept(gopts GlobalOptions, t testing.TB, keep restic.IDSet, removeTreePacks bool) {
be := captureBackend(&gopts)
ctx, r, unlock, err := openWithExclusiveLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
ctx, r, unlock, err := openWithExclusiveLock(context.TODO(), gopts, false, printer)
rtest.OK(t, err)
defer unlock()
@@ -355,7 +367,10 @@ func lastSnapshot(old, new map[string]struct{}) (map[string]struct{}, string) {
}
func testLoadSnapshot(t testing.TB, gopts GlobalOptions, id restic.ID) *restic.Snapshot {
_, repo, unlock, err := openWithReadLock(context.TODO(), gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(gopts.JSON, gopts.verbosity, term)
_, repo, unlock, err := openWithReadLock(context.TODO(), gopts, false, printer)
defer unlock()
rtest.OK(t, err)
snapshot, err := restic.LoadSnapshot(context.TODO(), repo, id)

View File

@@ -161,7 +161,10 @@ func TestFindListOnce(t *testing.T) {
testRunBackup(t, "", []string{filepath.Join(env.testdata, "0", "0", "9", "3")}, opts, env.gopts)
thirdSnapshot := restic.NewIDSet(testListSnapshots(t, env.gopts, 3)...)
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false)
term, cancel := setupTermstatus()
defer cancel()
printer := newTerminalProgressPrinter(env.gopts.JSON, env.gopts.verbosity, term)
ctx, repo, unlock, err := openWithReadLock(context.TODO(), env.gopts, false, printer)
rtest.OK(t, err)
defer unlock()

View File

@@ -4,9 +4,10 @@ import (
"context"
"github.com/restic/restic/internal/repository"
"github.com/restic/restic/internal/ui/progress"
)
func internalOpenWithLocked(ctx context.Context, gopts GlobalOptions, dryRun bool, exclusive bool) (context.Context, *repository.Repository, func(), error) {
func internalOpenWithLocked(ctx context.Context, gopts GlobalOptions, dryRun bool, exclusive bool, printer progress.Printer) (context.Context, *repository.Repository, func(), error) {
repo, err := OpenRepository(ctx, gopts)
if err != nil {
return nil, nil, nil, err
@@ -18,9 +19,9 @@ func internalOpenWithLocked(ctx context.Context, gopts GlobalOptions, dryRun boo
lock, ctx, err = repository.Lock(ctx, repo, exclusive, gopts.RetryLock, func(msg string) {
if !gopts.JSON {
Verbosef("%s", msg)
printer.P("%s", msg)
}
}, Warnf)
}, printer.E)
if err != nil {
return nil, nil, nil, err
}
@@ -33,16 +34,16 @@ func internalOpenWithLocked(ctx context.Context, gopts GlobalOptions, dryRun boo
return ctx, repo, unlock, nil
}
func openWithReadLock(ctx context.Context, gopts GlobalOptions, noLock bool) (context.Context, *repository.Repository, func(), error) {
func openWithReadLock(ctx context.Context, gopts GlobalOptions, noLock bool, printer progress.Printer) (context.Context, *repository.Repository, func(), error) {
// TODO enforce read-only operations once the locking code has moved to the repository
return internalOpenWithLocked(ctx, gopts, noLock, false)
return internalOpenWithLocked(ctx, gopts, noLock, false, printer)
}
func openWithAppendLock(ctx context.Context, gopts GlobalOptions, dryRun bool) (context.Context, *repository.Repository, func(), error) {
func openWithAppendLock(ctx context.Context, gopts GlobalOptions, dryRun bool, printer progress.Printer) (context.Context, *repository.Repository, func(), error) {
// TODO enforce non-exclusive operations once the locking code has moved to the repository
return internalOpenWithLocked(ctx, gopts, dryRun, false)
return internalOpenWithLocked(ctx, gopts, dryRun, false, printer)
}
func openWithExclusiveLock(ctx context.Context, gopts GlobalOptions, dryRun bool) (context.Context, *repository.Repository, func(), error) {
return internalOpenWithLocked(ctx, gopts, dryRun, true)
func openWithExclusiveLock(ctx context.Context, gopts GlobalOptions, dryRun bool, printer progress.Printer) (context.Context, *repository.Repository, func(), error) {
return internalOpenWithLocked(ctx, gopts, dryRun, true, printer)
}