Merge pull request #5322 from zmanda/fix-gh-5233-forget-failure-exit-codes

forget: return exit code 3 on partial removal of snapshots
This commit is contained in:
Michael Eischer
2025-03-31 20:08:33 +02:00
committed by GitHub
3 changed files with 19 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
Bugfix: forget command returns exit code 3 on partial removal of snapshots
The `forget` command now returns exit code 3 when it fails to remove one or
more snapshots. Previously, it returned exit code 0, which could lead to
confusion if the command was used in a script.
https://github.com/restic/restic/issues/5233
https://github.com/restic/restic/pull/5322

View File

@@ -41,6 +41,7 @@ EXIT STATUS
Exit status is 0 if the command was successful.
Exit status is 1 if there was any error.
Exit status is 3 if there was an error removing one or more snapshots.
Exit status is 10 if the repository does not exist.
Exit status is 11 if the repository is already locked.
Exit status is 12 if the password is incorrect.
@@ -62,6 +63,7 @@ Exit status is 12 if the password is incorrect.
type ForgetPolicyCount int
var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead")
var ErrFailedToRemoveOneOrMoreSnapshots = errors.New("failed to remove one or more snapshots")
func (c *ForgetPolicyCount) Set(s string) error {
switch s {
@@ -305,12 +307,15 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
return ctx.Err()
}
// these are the snapshots that failed to be removed
failedSnIDs := restic.NewIDSet()
if len(removeSnIDs) > 0 {
if !opts.DryRun {
bar := printer.NewCounter("files deleted")
err := restic.ParallelRemove(ctx, repo, removeSnIDs, restic.WriteableSnapshotFile, func(id restic.ID, err error) error {
if err != nil {
printer.E("unable to remove %v/%v from the repository\n", restic.SnapshotFile, id)
failedSnIDs.Insert(id)
} else {
printer.VV("removed %v/%v\n", restic.SnapshotFile, id)
}
@@ -332,6 +337,10 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
}
}
if len(failedSnIDs) > 0 {
return ErrFailedToRemoveOneOrMoreSnapshots
}
if len(removeSnIDs) > 0 && opts.Prune {
if opts.DryRun {
printer.P("%d snapshots would be removed, running prune dry run\n", len(removeSnIDs))

View File

@@ -206,6 +206,8 @@ func main() {
exitCode = 0
case err == ErrInvalidSourceData:
exitCode = 3
case errors.Is(err, ErrFailedToRemoveOneOrMoreSnapshots):
exitCode = 3
case errors.Is(err, ErrNoRepository):
exitCode = 10
case restic.IsAlreadyLocked(err):