forked from TrueCloudLab/restic
Add restic.Fatal/f
This is a new error which implements the restic.Fataler interface. Errors of this type are written to stderr, the restic exits. For all other errors, restic prints the stack trace (if available).
This commit is contained in:
parent
045f545085
commit
c55b6ee544
20 changed files with 89 additions and 78 deletions
|
@ -13,8 +13,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
|
@ -232,7 +230,7 @@ func filterExisting(items []string) (result []string, err error) {
|
|||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
return nil, errors.New("all target directories/files do not exist")
|
||||
return nil, restic.Fatal("all target directories/files do not exist")
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -240,7 +238,7 @@ func filterExisting(items []string) (result []string, err error) {
|
|||
|
||||
func (cmd CmdBackup) readFromStdin(args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errors.Errorf("when reading from stdin, no additional files can be specified")
|
||||
return restic.Fatalf("when reading from stdin, no additional files can be specified")
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
@ -274,7 +272,7 @@ func (cmd CmdBackup) Execute(args []string) error {
|
|||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
target := make([]string, 0, len(args))
|
||||
|
@ -312,7 +310,7 @@ func (cmd CmdBackup) Execute(args []string) error {
|
|||
if !cmd.Force && cmd.Parent != "" {
|
||||
id, err := restic.FindSnapshot(repo, cmd.Parent)
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid id %q: %v", cmd.Parent, err)
|
||||
return restic.Fatalf("invalid id %q: %v", cmd.Parent, err)
|
||||
}
|
||||
|
||||
parentSnapshotID = &id
|
||||
|
|
|
@ -25,10 +25,6 @@ func (cmd CmdCache) Usage() string {
|
|||
}
|
||||
|
||||
func (cmd CmdCache) Execute(args []string) error {
|
||||
// if len(args) == 0 || len(args) > 2 {
|
||||
// return errors.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||
// }
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/debug"
|
||||
|
@ -34,7 +32,7 @@ func (cmd CmdCat) Usage() string {
|
|||
|
||||
func (cmd CmdCat) Execute(args []string) error {
|
||||
if len(args) < 1 || (args[0] != "masterkey" && args[0] != "config" && len(args) != 2) {
|
||||
return errors.Errorf("type or ID not specified, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("type or ID not specified, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
@ -184,7 +182,7 @@ func (cmd CmdCat) Execute(args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return errors.New("blob not found")
|
||||
return restic.Fatal("blob not found")
|
||||
|
||||
case "tree":
|
||||
debug.Log("cat", "cat tree %v", id.Str())
|
||||
|
@ -205,6 +203,6 @@ func (cmd CmdCat) Execute(args []string) error {
|
|||
return nil
|
||||
|
||||
default:
|
||||
return errors.New("invalid type")
|
||||
return restic.Fatal("invalid type")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
"restic"
|
||||
|
@ -67,7 +65,7 @@ func (cmd CmdCheck) newReadProgress(todo restic.Stat) *restic.Progress {
|
|||
|
||||
func (cmd CmdCheck) Execute(args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errors.New("check has no arguments")
|
||||
return restic.Fatal("check has no arguments")
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
@ -105,7 +103,7 @@ func (cmd CmdCheck) Execute(args []string) error {
|
|||
for _, err := range errs {
|
||||
cmd.global.Warnf("error: %v\n", err)
|
||||
}
|
||||
return errors.Errorf("LoadIndex returned errors")
|
||||
return restic.Fatal("LoadIndex returned errors")
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
@ -160,7 +158,7 @@ func (cmd CmdCheck) Execute(args []string) error {
|
|||
}
|
||||
|
||||
if errorsFound {
|
||||
return errors.New("repository contains errors")
|
||||
return restic.Fatal("repository contains errors")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ import (
|
|||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/pack"
|
||||
|
@ -204,7 +202,7 @@ func (cmd CmdDump) DumpIndexes() error {
|
|||
|
||||
func (cmd CmdDump) Execute(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.Errorf("type not specified, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("type not specified, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
@ -257,6 +255,6 @@ func (cmd CmdDump) Execute(args []string) error {
|
|||
|
||||
return nil
|
||||
default:
|
||||
return errors.Errorf("no such type %q", tpe)
|
||||
return restic.Fatalf("no such type %q", tpe)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/debug"
|
||||
|
@ -58,7 +56,7 @@ func parseTime(str string) (time.Time, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return time.Time{}, errors.Errorf("unable to parse time: %q", str)
|
||||
return time.Time{}, restic.Fatalf("unable to parse time: %q", str)
|
||||
}
|
||||
|
||||
func (c CmdFind) findInTree(repo *repository.Repository, id backend.ID, path string) ([]findResult, error) {
|
||||
|
@ -138,7 +136,7 @@ func (CmdFind) Usage() string {
|
|||
|
||||
func (c CmdFind) Execute(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.Errorf("wrong number of arguments, Usage: %s", c.Usage())
|
||||
return restic.Fatalf("wrong number of arguments, Usage: %s", c.Usage())
|
||||
}
|
||||
|
||||
var err error
|
||||
|
@ -178,7 +176,7 @@ func (c CmdFind) Execute(args []string) error {
|
|||
if c.Snapshot != "" {
|
||||
snapshotID, err := restic.FindSnapshot(repo, c.Snapshot)
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid id %q: %v", args[1], err)
|
||||
return restic.Fatalf("invalid id %q: %v", args[1], err)
|
||||
}
|
||||
|
||||
return c.findInSnapshot(repo, snapshotID)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/repository"
|
||||
)
|
||||
|
||||
|
@ -12,7 +11,7 @@ type CmdInit struct {
|
|||
|
||||
func (cmd CmdInit) Execute(args []string) error {
|
||||
if cmd.global.Repo == "" {
|
||||
return errors.New("Please specify repository location (-r)")
|
||||
return restic.Fatal("Please specify repository location (-r)")
|
||||
}
|
||||
|
||||
be, err := create(cmd.global.Repo)
|
||||
|
|
|
@ -2,8 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"restic"
|
||||
|
||||
"restic/backend"
|
||||
"restic/repository"
|
||||
|
@ -70,7 +69,7 @@ func (cmd CmdKey) getNewPassword() string {
|
|||
func (cmd CmdKey) addKey(repo *repository.Repository) error {
|
||||
id, err := repository.AddKey(repo, cmd.getNewPassword(), repo.Key())
|
||||
if err != nil {
|
||||
return errors.Errorf("creating new key failed: %v\n", err)
|
||||
return restic.Fatalf("creating new key failed: %v\n", err)
|
||||
}
|
||||
|
||||
cmd.global.Verbosef("saved new key as %s\n", id)
|
||||
|
@ -80,7 +79,7 @@ func (cmd CmdKey) addKey(repo *repository.Repository) error {
|
|||
|
||||
func (cmd CmdKey) deleteKey(repo *repository.Repository, name string) error {
|
||||
if name == repo.KeyName() {
|
||||
return errors.New("refusing to remove key currently used to access repository")
|
||||
return restic.Fatal("refusing to remove key currently used to access repository")
|
||||
}
|
||||
|
||||
err := repo.Backend().Remove(backend.Key, name)
|
||||
|
@ -95,7 +94,7 @@ func (cmd CmdKey) deleteKey(repo *repository.Repository, name string) error {
|
|||
func (cmd CmdKey) changePassword(repo *repository.Repository) error {
|
||||
id, err := repository.AddKey(repo, cmd.getNewPassword(), repo.Key())
|
||||
if err != nil {
|
||||
return errors.Errorf("creating new key failed: %v\n", err)
|
||||
return restic.Fatalf("creating new key failed: %v\n", err)
|
||||
}
|
||||
|
||||
err = repo.Backend().Remove(backend.Key, repo.KeyName())
|
||||
|
@ -114,7 +113,7 @@ func (cmd CmdKey) Usage() string {
|
|||
|
||||
func (cmd CmdKey) Execute(args []string) error {
|
||||
if len(args) < 1 || (args[0] == "rm" && len(args) != 2) {
|
||||
return errors.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
)
|
||||
|
||||
|
@ -26,7 +25,7 @@ func (cmd CmdList) Usage() string {
|
|||
|
||||
func (cmd CmdList) Execute(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.Errorf("type not specified, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("type not specified, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
@ -68,7 +67,7 @@ func (cmd CmdList) Execute(args []string) error {
|
|||
case "locks":
|
||||
t = backend.Lock
|
||||
default:
|
||||
return errors.New("invalid type")
|
||||
return restic.Fatal("invalid type")
|
||||
}
|
||||
|
||||
for id := range repo.List(t, nil) {
|
||||
|
|
|
@ -5,8 +5,6 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/repository"
|
||||
|
@ -74,7 +72,7 @@ func (cmd CmdLs) Usage() string {
|
|||
|
||||
func (cmd CmdLs) Execute(args []string) error {
|
||||
if len(args) < 1 || len(args) > 2 {
|
||||
return errors.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
|
|
@ -5,8 +5,7 @@ package main
|
|||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"restic"
|
||||
|
||||
resticfs "restic/fs"
|
||||
"restic/fuse"
|
||||
|
@ -43,7 +42,7 @@ func (cmd CmdMount) Usage() string {
|
|||
|
||||
func (cmd CmdMount) Execute(args []string) error {
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of parameters, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
|
|
@ -11,8 +11,6 @@ import (
|
|||
"restic/repository"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
|
@ -193,7 +191,7 @@ nextPack:
|
|||
removePacks.Insert(packID)
|
||||
|
||||
if !rewritePacks.Has(packID) {
|
||||
return errors.Errorf("pack %v is unneeded, but not contained in rewritePacks", packID.Str())
|
||||
return restic.Fatalf("pack %v is unneeded, but not contained in rewritePacks", packID.Str())
|
||||
}
|
||||
|
||||
rewritePacks.Delete(packID)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/debug"
|
||||
|
@ -35,15 +33,15 @@ func (cmd CmdRestore) Usage() string {
|
|||
|
||||
func (cmd CmdRestore) Execute(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.Errorf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of arguments, Usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
if cmd.Target == "" {
|
||||
return errors.New("please specify a directory to restore to (--target)")
|
||||
return restic.Fatal("please specify a directory to restore to (--target)")
|
||||
}
|
||||
|
||||
if len(cmd.Exclude) > 0 && len(cmd.Include) > 0 {
|
||||
return errors.New("exclude and include patterns are mutually exclusive")
|
||||
return restic.Fatal("exclude and include patterns are mutually exclusive")
|
||||
}
|
||||
|
||||
snapshotIDString := args[0]
|
||||
|
|
|
@ -8,8 +8,6 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
)
|
||||
|
@ -72,7 +70,7 @@ func (cmd CmdSnapshots) Usage() string {
|
|||
|
||||
func (cmd CmdSnapshots) Execute(args []string) error {
|
||||
if len(args) != 0 {
|
||||
return errors.Errorf("wrong number of arguments, usage: %s", cmd.Usage())
|
||||
return restic.Fatalf("wrong number of arguments, usage: %s", cmd.Usage())
|
||||
}
|
||||
|
||||
repo, err := cmd.global.OpenRepository()
|
||||
|
|
|
@ -4,12 +4,11 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"restic"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic/backend"
|
||||
"restic/backend/local"
|
||||
"restic/backend/rest"
|
||||
|
@ -247,7 +246,7 @@ const maxKeys = 20
|
|||
// OpenRepository reads the password and opens the repository.
|
||||
func (o GlobalOptions) OpenRepository() (*repository.Repository, error) {
|
||||
if o.Repo == "" {
|
||||
return nil, errors.New("Please specify repository location (-r)")
|
||||
return nil, restic.Fatal("Please specify repository location (-r)")
|
||||
}
|
||||
|
||||
be, err := open(o.Repo)
|
||||
|
@ -263,7 +262,7 @@ func (o GlobalOptions) OpenRepository() (*repository.Repository, error) {
|
|||
|
||||
err = s.SearchKey(o.password, maxKeys)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to open repo: %v", err)
|
||||
return nil, restic.Fatalf("unable to open repo: %v", err)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
@ -301,7 +300,7 @@ func open(s string) (backend.Backend, error) {
|
|||
}
|
||||
|
||||
debug.Log("open", "invalid repository location: %v", s)
|
||||
return nil, errors.Errorf("invalid scheme %q", loc.Scheme)
|
||||
return nil, restic.Fatalf("invalid scheme %q", loc.Scheme)
|
||||
}
|
||||
|
||||
// Create the backend specified by URI.
|
||||
|
@ -336,5 +335,5 @@ func create(s string) (backend.Backend, error) {
|
|||
}
|
||||
|
||||
debug.Log("open", "invalid repository scheme: %v", s)
|
||||
return nil, errors.Errorf("invalid scheme %q", loc.Scheme)
|
||||
return nil, restic.Fatalf("invalid scheme %q", loc.Scheme)
|
||||
}
|
||||
|
|
|
@ -10,8 +10,6 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic"
|
||||
"restic/backend"
|
||||
"restic/repository"
|
||||
|
@ -51,7 +49,7 @@ func waitForMount(dir string) error {
|
|||
time.Sleep(mountSleep)
|
||||
}
|
||||
|
||||
return errors.Errorf("subdir %q of dir %s never appeared", mountTestSubdir, dir)
|
||||
return restic.Fatalf("subdir %q of dir %s never appeared", mountTestSubdir, dir)
|
||||
}
|
||||
|
||||
func cmdMount(t testing.TB, global GlobalOptions, dir string, ready, done chan struct{}) {
|
||||
|
|
|
@ -10,13 +10,12 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"restic"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"restic/backend"
|
||||
"restic/debug"
|
||||
"restic/filter"
|
||||
|
@ -581,7 +580,7 @@ func testFileSize(filename string, size int64) error {
|
|||
}
|
||||
|
||||
if fi.Size() != size {
|
||||
return errors.Errorf("wrong file size for %v: expected %v, got %v", filename, size, fi.Size())
|
||||
return restic.Fatalf("wrong file size for %v: expected %v, got %v", filename, size, fi.Size())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -37,13 +37,15 @@ func main() {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
debug.Log("main", "command returned error: %#v", err)
|
||||
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
||||
}
|
||||
debug.Log("main", "command returned error: %#v", err)
|
||||
|
||||
if restic.IsAlreadyLocked(errors.Cause(err)) {
|
||||
fmt.Fprintf(os.Stderr, "\nthe `unlock` command can be used to remove stale locks\n")
|
||||
switch {
|
||||
case restic.IsAlreadyLocked(errors.Cause(err)):
|
||||
fmt.Fprintf(os.Stderr, "%v\nthe `unlock` command can be used to remove stale locks\n", err)
|
||||
case restic.IsFatal(errors.Cause(err)):
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
case err != nil:
|
||||
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
||||
}
|
||||
|
||||
RunCleanupHandlers()
|
||||
|
|
38
src/restic/errors.go
Normal file
38
src/restic/errors.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package restic
|
||||
|
||||
import "fmt"
|
||||
|
||||
// fatalError is an error that should be printed to the user, then the program
|
||||
// should exit with an error code.
|
||||
type fatalError string
|
||||
|
||||
func (e fatalError) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (e fatalError) Fatal() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Fataler is an error which should be printed to the user directly.
|
||||
// Afterwards, the program should exit with an error.
|
||||
type Fataler interface {
|
||||
Fatal() bool
|
||||
}
|
||||
|
||||
// IsFatal returns true if err is a fatal message that should be printed to the
|
||||
// user. Then, the program should exit.
|
||||
func IsFatal(err error) bool {
|
||||
e, ok := err.(Fataler)
|
||||
return ok && e.Fatal()
|
||||
}
|
||||
|
||||
// Fatal returns an error which implements the Fataler interface.
|
||||
func Fatal(s string) error {
|
||||
return fatalError(s)
|
||||
}
|
||||
|
||||
// Fatalf returns an error which implements the Fataler interface.
|
||||
func Fatalf(s string, data ...interface{}) error {
|
||||
return fatalError(fmt.Sprintf(s, data...))
|
||||
}
|
|
@ -2,10 +2,11 @@ package restic
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
const minTickerTime = time.Second / 60
|
||||
|
|
Loading…
Reference in a new issue