mirror of
https://github.com/restic/restic.git
synced 2025-12-11 18:47:50 +00:00
Merge pull request #5363 from zmanda/fix-gh-5258-backup-exits-with-wrong-code-on-ctrl-c
bugfix: fatal errors do not keep underlying error
This commit is contained in:
7
changelog/unreleased/issue-5258
Normal file
7
changelog/unreleased/issue-5258
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Bugfix: Exit with correct code on SIGINT
|
||||||
|
|
||||||
|
Restic previously returned exit code 1 on SIGINT, which is incorrect.
|
||||||
|
Restic now returns 130 on SIGINT.
|
||||||
|
|
||||||
|
https://github.com/restic/restic/issues/5258
|
||||||
|
https://github.com/restic/restic/pull/5363
|
||||||
@@ -248,7 +248,7 @@ func copyTree(ctx context.Context, srcRepo restic.Repository, dstRepo restic.Rep
|
|||||||
_, err = repository.Repack(ctx, srcRepo, dstRepo, packList, copyBlobs, bar, printer.P)
|
_, err = repository.Repack(ctx, srcRepo, dstRepo, packList, copyBlobs, bar, printer.P)
|
||||||
bar.Done()
|
bar.Done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Fatal(err.Error())
|
return errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (opts *DiffOptions) AddFlags(f *pflag.FlagSet) {
|
|||||||
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) {
|
func loadSnapshot(ctx context.Context, be restic.Lister, repo restic.LoaderUnpacked, desc string) (*restic.Snapshot, string, error) {
|
||||||
sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc)
|
sn, subfolder, err := restic.FindSnapshot(ctx, be, repo, desc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", errors.Fatal(err.Error())
|
return nil, "", errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
return sn, subfolder, err
|
return sn, subfolder, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
|||||||
PackSize: gopts.PackSize * 1024 * 1024,
|
PackSize: gopts.PackSize * 1024 * 1024,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Fatal(err.Error())
|
return errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.Init(ctx, version, gopts.password, chunkerPolynomial)
|
err = s.Init(ctx, version, gopts.password, chunkerPolynomial)
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ func OpenRepository(ctx context.Context, opts GlobalOptions, printer progress.Pr
|
|||||||
NoExtraVerify: opts.NoExtraVerify,
|
NoExtraVerify: opts.NoExtraVerify,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Fatal(err.Error())
|
return nil, errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordTriesLeft := 1
|
passwordTriesLeft := 1
|
||||||
@@ -478,7 +478,7 @@ func innerOpen(ctx context.Context, s string, gopts GlobalOptions, opts options.
|
|||||||
|
|
||||||
rt, err := backend.Transport(globalOptions.TransportOptions)
|
rt, err := backend.Transport(globalOptions.TransportOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Fatal(err.Error())
|
return nil, errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap the transport so that the throughput via HTTP is limited
|
// wrap the transport so that the throughput via HTTP is limited
|
||||||
|
|||||||
@@ -7,25 +7,48 @@ import (
|
|||||||
|
|
||||||
// fatalError is an error that should be printed to the user, then the program
|
// fatalError is an error that should be printed to the user, then the program
|
||||||
// should exit with an error code.
|
// should exit with an error code.
|
||||||
type fatalError string
|
type fatalError struct {
|
||||||
|
msg string
|
||||||
|
err error // Underlying error
|
||||||
|
}
|
||||||
|
|
||||||
func (e fatalError) Error() string {
|
func (e *fatalError) Error() string {
|
||||||
return string(e)
|
return e.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *fatalError) Unwrap() error {
|
||||||
|
return e.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFatal returns true if err is a fatal message that should be printed to the
|
// IsFatal returns true if err is a fatal message that should be printed to the
|
||||||
// user. Then, the program should exit.
|
// user. Then, the program should exit.
|
||||||
func IsFatal(err error) bool {
|
func IsFatal(err error) bool {
|
||||||
var fatal fatalError
|
var fatal *fatalError
|
||||||
return errors.As(err, &fatal)
|
return errors.As(err, &fatal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal returns an error that is marked fatal.
|
// Fatal returns an error that is marked fatal.
|
||||||
func Fatal(s string) error {
|
func Fatal(s string) error {
|
||||||
return Wrap(fatalError(s), "Fatal")
|
return Wrap(&fatalError{msg: s}, "Fatal")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf returns an error that is marked fatal.
|
// Fatalf returns an error that is marked fatal, preserving an underlying error if passed.
|
||||||
func Fatalf(s string, data ...interface{}) error {
|
func Fatalf(s string, data ...interface{}) error {
|
||||||
return Wrap(fatalError(fmt.Sprintf(s, data...)), "Fatal")
|
// Use the last error found.
|
||||||
|
var underlyingErr error
|
||||||
|
for i := len(data) - 1; i >= 0; i-- {
|
||||||
|
if err, ok := data[i].(error); ok {
|
||||||
|
underlyingErr = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := fmt.Sprintf(s, data...)
|
||||||
|
|
||||||
|
fatal := &fatalError{
|
||||||
|
msg: msg,
|
||||||
|
err: underlyingErr,
|
||||||
|
}
|
||||||
|
|
||||||
|
return Wrap(fatal, "Fatal")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,3 +20,23 @@ func TestFatal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFatalErrorWrapping(t *testing.T) {
|
||||||
|
underlying := errors.New("underlying error")
|
||||||
|
fatal := errors.Fatalf("fatal error: %v", underlying)
|
||||||
|
|
||||||
|
// Test that the fatal error message is preserved
|
||||||
|
if fatal.Error() != "Fatal: fatal error: underlying error" {
|
||||||
|
t.Errorf("unexpected error message: %v", fatal.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that we can unwrap to get the underlying error
|
||||||
|
if !errors.Is(fatal, underlying) {
|
||||||
|
t.Error("fatal error should wrap the underlying error")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the error is marked as fatal
|
||||||
|
if !errors.IsFatal(fatal) {
|
||||||
|
t.Error("error should be marked as fatal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ func (plan *PrunePlan) Execute(ctx context.Context, printer progress.Printer) er
|
|||||||
_, err := Repack(ctx, repo, repo, plan.repackPacks, plan.keepBlobs, bar, printer.P)
|
_, err := Repack(ctx, repo, repo, plan.repackPacks, plan.keepBlobs, bar, printer.P)
|
||||||
bar.Done()
|
bar.Done()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Fatal(err.Error())
|
return errors.Fatalf("%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also remove repacked packs
|
// Also remove repacked packs
|
||||||
|
|||||||
Reference in New Issue
Block a user