diff --git a/run_integration_tests.go b/run_integration_tests.go index 249839628..1468a5221 100644 --- a/run_integration_tests.go +++ b/run_integration_tests.go @@ -3,7 +3,9 @@ package main import ( + "bufio" "bytes" + "errors" "flag" "fmt" "io" @@ -17,6 +19,12 @@ import ( "strings" ) +// ForbiddenImports are the packages from the stdlib that should not be used in +// our code. +var ForbiddenImports = map[string]bool{ + "errors": true, +} + var runCrossCompile = flag.Bool("cross-compile", true, "run cross compilation tests") var minioServer = flag.String("minio", "", "path to the minio server binary") var debug = flag.Bool("debug", false, "output debug messages") @@ -345,7 +353,30 @@ func (env *TravisEnvironment) RunTests() error { return err } - return runGofmt() + if err = runGofmt(); err != nil { + return err + } + + deps, err := findImports() + if err != nil { + return err + } + + foundForbiddenImports := false + for name, imports := range deps { + for _, pkg := range imports { + if _, ok := ForbiddenImports[pkg]; ok { + fmt.Fprintf(os.Stderr, "========== package %v imports forbidden package %v\n", name, pkg) + foundForbiddenImports = true + } + } + } + + if foundForbiddenImports { + return errors.New("CI: forbidden imports found") + } + + return nil } // AppveyorEnvironment is the environment on Windows. @@ -413,6 +444,46 @@ func updateEnv(env []string, override map[string]string) []string { return newEnv } +func findImports() (map[string][]string, error) { + res := make(map[string][]string) + + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("Getwd() returned error: %v", err) + } + + gopath := cwd + ":" + filepath.Join(cwd, "vendor") + + cmd := exec.Command("go", "list", "-f", `{{.ImportPath}} {{join .Imports " "}}`, "./src/...") + cmd.Env = updateEnv(os.Environ(), map[string]string{"GOPATH": gopath}) + cmd.Stderr = os.Stderr + + output, err := cmd.Output() + if err != nil { + return nil, err + } + + sc := bufio.NewScanner(bytes.NewReader(output)) + for sc.Scan() { + wordScanner := bufio.NewScanner(strings.NewReader(sc.Text())) + wordScanner.Split(bufio.ScanWords) + + if !wordScanner.Scan() { + return nil, fmt.Errorf("package name not found in line: %s", output) + } + name := wordScanner.Text() + var deps []string + + for wordScanner.Scan() { + deps = append(deps, wordScanner.Text()) + } + + res[name] = deps + } + + return res, nil +} + func runGofmt() error { dir, err := os.Getwd() if err != nil { diff --git a/src/cmds/restic/cmd_backup.go b/src/cmds/restic/cmd_backup.go index b5c567de6..7a7640249 100644 --- a/src/cmds/restic/cmd_backup.go +++ b/src/cmds/restic/cmd_backup.go @@ -2,7 +2,6 @@ package main import ( "bufio" - "errors" "fmt" "os" "path/filepath" @@ -14,6 +13,8 @@ import ( "strings" "time" + "github.com/pkg/errors" + "golang.org/x/crypto/ssh/terminal" ) @@ -223,7 +224,7 @@ func (cmd CmdBackup) newArchiveStdinProgress() *restic.Progress { func filterExisting(items []string) (result []string, err error) { for _, item := range items { _, err := fs.Lstat(item) - if err != nil && os.IsNotExist(err) { + if err != nil && os.IsNotExist(errors.Cause(err)) { continue } @@ -231,7 +232,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 @@ -239,7 +240,7 @@ func filterExisting(items []string) (result []string, err error) { func (cmd CmdBackup) readFromStdin(args []string) error { if len(args) != 0 { - return fmt.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() @@ -273,7 +274,7 @@ func (cmd CmdBackup) Execute(args []string) error { } if len(args) == 0 { - return fmt.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)) @@ -311,7 +312,7 @@ func (cmd CmdBackup) Execute(args []string) error { if !cmd.Force && cmd.Parent != "" { id, err := restic.FindSnapshot(repo, cmd.Parent) if err != nil { - return fmt.Errorf("invalid id %q: %v", cmd.Parent, err) + return restic.Fatalf("invalid id %q: %v", cmd.Parent, err) } parentSnapshotID = &id diff --git a/src/cmds/restic/cmd_cache.go b/src/cmds/restic/cmd_cache.go index 0a7e0c5e9..aa4d5765f 100644 --- a/src/cmds/restic/cmd_cache.go +++ b/src/cmds/restic/cmd_cache.go @@ -25,10 +25,6 @@ func (cmd CmdCache) Usage() string { } func (cmd CmdCache) Execute(args []string) error { - // if len(args) == 0 || len(args) > 2 { - // return fmt.Errorf("wrong number of parameters, Usage: %s", cmd.Usage()) - // } - repo, err := cmd.global.OpenRepository() if err != nil { return err diff --git a/src/cmds/restic/cmd_cat.go b/src/cmds/restic/cmd_cat.go index 959dfabd3..4e52848da 100644 --- a/src/cmds/restic/cmd_cat.go +++ b/src/cmds/restic/cmd_cat.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "errors" "fmt" "os" @@ -33,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 fmt.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() @@ -54,7 +53,7 @@ func (cmd CmdCat) Execute(args []string) error { id, err = backend.ParseID(args[1]) if err != nil { if tpe != "snapshot" { - return err + return restic.Fatalf("unable to parse ID: %v\n", err) } // find snapshot id with prefix @@ -183,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()) @@ -204,6 +203,6 @@ func (cmd CmdCat) Execute(args []string) error { return nil default: - return errors.New("invalid type") + return restic.Fatal("invalid type") } } diff --git a/src/cmds/restic/cmd_check.go b/src/cmds/restic/cmd_check.go index 9bcd27917..a151fc93b 100644 --- a/src/cmds/restic/cmd_check.go +++ b/src/cmds/restic/cmd_check.go @@ -1,7 +1,6 @@ package main import ( - "errors" "fmt" "os" "time" @@ -66,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() @@ -104,7 +103,7 @@ func (cmd CmdCheck) Execute(args []string) error { for _, err := range errs { cmd.global.Warnf("error: %v\n", err) } - return fmt.Errorf("LoadIndex returned errors") + return restic.Fatal("LoadIndex returned errors") } done := make(chan struct{}) @@ -159,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 } diff --git a/src/cmds/restic/cmd_dump.go b/src/cmds/restic/cmd_dump.go index b7f815b3b..32b789094 100644 --- a/src/cmds/restic/cmd_dump.go +++ b/src/cmds/restic/cmd_dump.go @@ -14,8 +14,6 @@ import ( "restic/repository" "restic/worker" - - "github.com/juju/errors" ) type CmdDump struct { @@ -204,7 +202,7 @@ func (cmd CmdDump) DumpIndexes() error { func (cmd CmdDump) Execute(args []string) error { if len(args) != 1 { - return fmt.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) } } diff --git a/src/cmds/restic/cmd_find.go b/src/cmds/restic/cmd_find.go index 9f96187e1..1c66cd757 100644 --- a/src/cmds/restic/cmd_find.go +++ b/src/cmds/restic/cmd_find.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "path/filepath" "time" @@ -57,7 +56,7 @@ func parseTime(str string) (time.Time, error) { } } - return time.Time{}, fmt.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) { @@ -137,7 +136,7 @@ func (CmdFind) Usage() string { func (c CmdFind) Execute(args []string) error { if len(args) != 1 { - return fmt.Errorf("wrong number of arguments, Usage: %s", c.Usage()) + return restic.Fatalf("wrong number of arguments, Usage: %s", c.Usage()) } var err error @@ -177,7 +176,7 @@ func (c CmdFind) Execute(args []string) error { if c.Snapshot != "" { snapshotID, err := restic.FindSnapshot(repo, c.Snapshot) if err != nil { - return fmt.Errorf("invalid id %q: %v", args[1], err) + return restic.Fatalf("invalid id %q: %v", args[1], err) } return c.findInSnapshot(repo, snapshotID) diff --git a/src/cmds/restic/cmd_init.go b/src/cmds/restic/cmd_init.go index 887d34166..49b0907ad 100644 --- a/src/cmds/restic/cmd_init.go +++ b/src/cmds/restic/cmd_init.go @@ -1,8 +1,7 @@ package main import ( - "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) diff --git a/src/cmds/restic/cmd_key.go b/src/cmds/restic/cmd_key.go index 46e5b6bfd..67d5afa64 100644 --- a/src/cmds/restic/cmd_key.go +++ b/src/cmds/restic/cmd_key.go @@ -1,8 +1,8 @@ package main import ( - "errors" "fmt" + "restic" "restic/backend" "restic/repository" @@ -69,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 fmt.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) @@ -79,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) @@ -94,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 fmt.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()) @@ -113,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 fmt.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() diff --git a/src/cmds/restic/cmd_list.go b/src/cmds/restic/cmd_list.go index 3bfb5af9f..717d65ade 100644 --- a/src/cmds/restic/cmd_list.go +++ b/src/cmds/restic/cmd_list.go @@ -1,9 +1,7 @@ package main import ( - "errors" - "fmt" - + "restic" "restic/backend" ) @@ -27,7 +25,7 @@ func (cmd CmdList) Usage() string { func (cmd CmdList) Execute(args []string) error { if len(args) != 1 { - return fmt.Errorf("type not specified, Usage: %s", cmd.Usage()) + return restic.Fatalf("type not specified, Usage: %s", cmd.Usage()) } repo, err := cmd.global.OpenRepository() @@ -69,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) { diff --git a/src/cmds/restic/cmd_ls.go b/src/cmds/restic/cmd_ls.go index 2f1cccf4d..c55670a93 100644 --- a/src/cmds/restic/cmd_ls.go +++ b/src/cmds/restic/cmd_ls.go @@ -72,7 +72,7 @@ func (cmd CmdLs) Usage() string { func (cmd CmdLs) Execute(args []string) error { if len(args) < 1 || len(args) > 2 { - return fmt.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() diff --git a/src/cmds/restic/cmd_mount.go b/src/cmds/restic/cmd_mount.go index 13643c69a..36a2ce997 100644 --- a/src/cmds/restic/cmd_mount.go +++ b/src/cmds/restic/cmd_mount.go @@ -4,8 +4,10 @@ package main import ( - "fmt" "os" + "restic" + + "github.com/pkg/errors" resticfs "restic/fs" "restic/fuse" @@ -42,7 +44,7 @@ func (cmd CmdMount) Usage() string { func (cmd CmdMount) Execute(args []string) error { if len(args) == 0 { - return fmt.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() @@ -56,7 +58,7 @@ func (cmd CmdMount) Execute(args []string) error { } mountpoint := args[0] - if _, err := resticfs.Stat(mountpoint); os.IsNotExist(err) { + if _, err := resticfs.Stat(mountpoint); os.IsNotExist(errors.Cause(err)) { cmd.global.Verbosef("Mountpoint %s doesn't exist, creating it\n", mountpoint) err = resticfs.Mkdir(mountpoint, os.ModeDir|0700) if err != nil { diff --git a/src/cmds/restic/cmd_prune.go b/src/cmds/restic/cmd_prune.go index 7467c2bdd..eee330131 100644 --- a/src/cmds/restic/cmd_prune.go +++ b/src/cmds/restic/cmd_prune.go @@ -191,7 +191,7 @@ nextPack: removePacks.Insert(packID) if !rewritePacks.Has(packID) { - return fmt.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) diff --git a/src/cmds/restic/cmd_restore.go b/src/cmds/restic/cmd_restore.go index 97b77ec1b..9ff57565d 100644 --- a/src/cmds/restic/cmd_restore.go +++ b/src/cmds/restic/cmd_restore.go @@ -1,9 +1,6 @@ package main import ( - "errors" - "fmt" - "restic" "restic/backend" "restic/debug" @@ -36,15 +33,15 @@ func (cmd CmdRestore) Usage() string { func (cmd CmdRestore) Execute(args []string) error { if len(args) != 1 { - return fmt.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] diff --git a/src/cmds/restic/cmd_snapshots.go b/src/cmds/restic/cmd_snapshots.go index abca558f5..ccf889d23 100644 --- a/src/cmds/restic/cmd_snapshots.go +++ b/src/cmds/restic/cmd_snapshots.go @@ -70,7 +70,7 @@ func (cmd CmdSnapshots) Usage() string { func (cmd CmdSnapshots) Execute(args []string) error { if len(args) != 0 { - return fmt.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() diff --git a/src/cmds/restic/global.go b/src/cmds/restic/global.go index 511628a45..2aedb026e 100644 --- a/src/cmds/restic/global.go +++ b/src/cmds/restic/global.go @@ -1,10 +1,10 @@ package main import ( - "errors" "fmt" "io" "os" + "restic" "runtime" "strings" "syscall" @@ -19,6 +19,7 @@ import ( "restic/repository" "github.com/jessevdk/go-flags" + "github.com/pkg/errors" "golang.org/x/crypto/ssh/terminal" ) @@ -183,7 +184,7 @@ func readPassword(in io.Reader) (password string, err error) { n, err := io.ReadFull(in, buf) buf = buf[:n] - if err != nil && err != io.ErrUnexpectedEOF { + if err != nil && errors.Cause(err) != io.ErrUnexpectedEOF { return "", err } @@ -246,7 +247,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) @@ -262,7 +263,7 @@ func (o GlobalOptions) OpenRepository() (*repository.Repository, error) { err = s.SearchKey(o.password, maxKeys) if err != nil { - return nil, fmt.Errorf("unable to open repo: %v", err) + return nil, restic.Fatalf("unable to open repo: %v", err) } return s, nil @@ -300,7 +301,7 @@ func open(s string) (backend.Backend, error) { } debug.Log("open", "invalid repository location: %v", s) - return nil, fmt.Errorf("invalid scheme %q", loc.Scheme) + return nil, restic.Fatalf("invalid scheme %q", loc.Scheme) } // Create the backend specified by URI. @@ -335,5 +336,5 @@ func create(s string) (backend.Backend, error) { } debug.Log("open", "invalid repository scheme: %v", s) - return nil, fmt.Errorf("invalid scheme %q", loc.Scheme) + return nil, restic.Fatalf("invalid scheme %q", loc.Scheme) } diff --git a/src/cmds/restic/integration_fuse_test.go b/src/cmds/restic/integration_fuse_test.go index 6688770e4..25f4b7e84 100644 --- a/src/cmds/restic/integration_fuse_test.go +++ b/src/cmds/restic/integration_fuse_test.go @@ -4,13 +4,14 @@ package main import ( - "fmt" "io/ioutil" "os" "path/filepath" "testing" "time" + "github.com/pkg/errors" + "restic" "restic/backend" "restic/repository" @@ -50,7 +51,7 @@ func waitForMount(dir string) error { time.Sleep(mountSleep) } - return fmt.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{}) { @@ -126,7 +127,7 @@ func TestMount(t *testing.T) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } diff --git a/src/cmds/restic/integration_test.go b/src/cmds/restic/integration_test.go index 4b99d8a32..fff765bef 100644 --- a/src/cmds/restic/integration_test.go +++ b/src/cmds/restic/integration_test.go @@ -10,11 +10,14 @@ import ( "os" "path/filepath" "regexp" + "restic" "strings" "syscall" "testing" "time" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/filter" @@ -141,7 +144,7 @@ func TestBackup(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } @@ -203,7 +206,7 @@ func TestBackupNonExistingFile(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } @@ -231,7 +234,7 @@ func TestBackupMissingFile1(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } @@ -269,7 +272,7 @@ func TestBackupMissingFile2(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } @@ -307,7 +310,7 @@ func TestBackupDirectoryError(t *testing.T) { withTestEnvironment(t, func(env *testEnvironment, global GlobalOptions) { datafile := filepath.Join("testdata", "backup-data.tar.gz") fd, err := os.Open(datafile) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { t.Skipf("unable to find data file %q, skipping", datafile) return } @@ -579,7 +582,7 @@ func testFileSize(filename string, size int64) error { } if fi.Size() != size { - return fmt.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 @@ -624,7 +627,7 @@ func TestRestoreFilter(t *testing.T) { if ok, _ := filter.Match(pat, filepath.Base(test.name)); !ok { OK(t, err) } else { - Assert(t, os.IsNotExist(err), + Assert(t, os.IsNotExist(errors.Cause(err)), "expected %v to not exist in restore step %v, but it exists, err %v", test.name, i+1, err) } } @@ -672,15 +675,15 @@ func TestRestoreLatest(t *testing.T) { cmdRestoreLatest(t, global, filepath.Join(env.base, "restore1"), []string{filepath.Dir(p1)}, "") OK(t, testFileSize(p1rAbs, int64(102))) - if _, err := os.Stat(p2rAbs); os.IsNotExist(err) { - Assert(t, os.IsNotExist(err), + if _, err := os.Stat(p2rAbs); os.IsNotExist(errors.Cause(err)) { + Assert(t, os.IsNotExist(errors.Cause(err)), "expected %v to not exist in restore, but it exists, err %v", p2rAbs, err) } cmdRestoreLatest(t, global, filepath.Join(env.base, "restore2"), []string{filepath.Dir(p2)}, "") OK(t, testFileSize(p2rAbs, int64(103))) - if _, err := os.Stat(p1rAbs); os.IsNotExist(err) { - Assert(t, os.IsNotExist(err), + if _, err := os.Stat(p1rAbs); os.IsNotExist(errors.Cause(err)) { + Assert(t, os.IsNotExist(errors.Cause(err)), "expected %v to not exist in restore, but it exists, err %v", p1rAbs, err) } diff --git a/src/cmds/restic/main.go b/src/cmds/restic/main.go index 19d81e774..5ad0ab128 100644 --- a/src/cmds/restic/main.go +++ b/src/cmds/restic/main.go @@ -2,11 +2,13 @@ package main import ( "fmt" - "github.com/jessevdk/go-flags" "os" "restic" "restic/debug" "runtime" + + "github.com/jessevdk/go-flags" + "github.com/pkg/errors" ) func init() { @@ -35,12 +37,15 @@ func main() { os.Exit(0) } - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - } + debug.Log("main", "command returned error: %#v", err) - if restic.IsAlreadyLocked(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() diff --git a/src/restic/archive_reader.go b/src/restic/archive_reader.go index ad6bded8c..02b630b1d 100644 --- a/src/restic/archive_reader.go +++ b/src/restic/archive_reader.go @@ -9,6 +9,7 @@ import ( "restic/repository" "time" + "github.com/pkg/errors" "github.com/restic/chunker" ) @@ -16,7 +17,7 @@ import ( func saveTreeJSON(repo *repository.Repository, item interface{}) (backend.ID, error) { data, err := json.Marshal(item) if err != nil { - return backend.ID{}, err + return backend.ID{}, errors.Wrap(err, "") } data = append(data, '\n') @@ -48,12 +49,12 @@ func ArchiveReader(repo *repository.Repository, p *Progress, rd io.Reader, name for { chunk, err := chnker.Next(getBuf()) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } if err != nil { - return nil, backend.ID{}, err + return nil, backend.ID{}, errors.Wrap(err, "chunker.Next()") } id := backend.Hash(chunk.Data) diff --git a/src/restic/archive_reader_test.go b/src/restic/archive_reader_test.go index 49fcbecab..2d5b705db 100644 --- a/src/restic/archive_reader_test.go +++ b/src/restic/archive_reader_test.go @@ -48,6 +48,9 @@ func checkSavedFile(t *testing.T, repo *repository.Repository, treeID backend.ID buf2 = buf2[:len(buf)] _, err = io.ReadFull(rd, buf2) + if err != nil { + t.Fatal(err) + } if !bytes.Equal(buf, buf2) { t.Fatalf("blob %d (%v) is wrong", i, id.Str()) diff --git a/src/restic/archiver.go b/src/restic/archiver.go index e3ac4237c..5f72633a2 100644 --- a/src/restic/archiver.go +++ b/src/restic/archiver.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/fs" @@ -18,8 +20,6 @@ import ( "restic/repository" "github.com/restic/chunker" - - "github.com/juju/errors" ) const ( @@ -113,7 +113,7 @@ func (arch *Archiver) Save(t pack.BlobType, data []byte, id backend.ID) error { func (arch *Archiver) SaveTreeJSON(item interface{}) (backend.ID, error) { data, err := json.Marshal(item) if err != nil { - return backend.ID{}, err + return backend.ID{}, errors.Wrap(err, "Marshal") } data = append(data, '\n') @@ -129,7 +129,7 @@ func (arch *Archiver) SaveTreeJSON(item interface{}) (backend.ID, error) { func (arch *Archiver) reloadFileIfChanged(node *Node, file fs.File) (*Node, error) { fi, err := file.Stat() if err != nil { - return nil, err + return nil, errors.Wrap(err, "Stat") } if fi.ModTime() == node.ModTime { @@ -178,7 +178,7 @@ func waitForResults(resultChannels [](<-chan saveResult)) ([]saveResult, error) } if len(results) != len(resultChannels) { - return nil, fmt.Errorf("chunker returned %v chunks, but only %v blobs saved", len(resultChannels), len(results)) + return nil, errors.Errorf("chunker returned %v chunks, but only %v blobs saved", len(resultChannels), len(results)) } return results, nil @@ -198,7 +198,7 @@ func updateNodeContent(node *Node, results []saveResult) error { } if bytes != node.Size { - return fmt.Errorf("errors saving node %q: saved %d bytes, wanted %d bytes", node.path, bytes, node.Size) + return errors.Errorf("errors saving node %q: saved %d bytes, wanted %d bytes", node.path, bytes, node.Size) } debug.Log("Archiver.SaveFile", "SaveFile(%q): %v blobs\n", node.path, len(results)) @@ -212,7 +212,7 @@ func (arch *Archiver) SaveFile(p *Progress, node *Node) error { file, err := fs.Open(node.path) defer file.Close() if err != nil { - return err + return errors.Wrap(err, "Open") } node, err = arch.reloadFileIfChanged(node, file) @@ -225,12 +225,12 @@ func (arch *Archiver) SaveFile(p *Progress, node *Node) error { for { chunk, err := chnker.Next(getBuf()) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } if err != nil { - return errors.Annotate(err, "SaveFile() chunker.Next()") + return errors.Wrap(err, "chunker.Next") } resCh := make(chan saveResult, 1) @@ -819,7 +819,7 @@ func Scan(dirs []string, filter pipe.SelectFunc, p *Progress) (Stat, error) { debug.Log("Scan", "Done for %v, err: %v", dir, err) if err != nil { - return Stat{}, err + return Stat{}, errors.Wrap(err, "fs.Walk") } } diff --git a/src/restic/archiver_duplication_test.go b/src/restic/archiver_duplication_test.go index 56341a997..61f7aafb9 100644 --- a/src/restic/archiver_duplication_test.go +++ b/src/restic/archiver_duplication_test.go @@ -2,13 +2,14 @@ package restic_test import ( "crypto/rand" - "errors" "io" mrand "math/rand" "sync" "testing" "time" + "github.com/pkg/errors" + "restic" "restic/backend" "restic/pack" diff --git a/src/restic/archiver_test.go b/src/restic/archiver_test.go index e42151a27..47b2210fa 100644 --- a/src/restic/archiver_test.go +++ b/src/restic/archiver_test.go @@ -14,6 +14,7 @@ import ( "restic/repository" . "restic/test" + "github.com/pkg/errors" "github.com/restic/chunker" ) @@ -31,7 +32,7 @@ func benchmarkChunkEncrypt(b testing.TB, buf, buf2 []byte, rd Rdr, key *crypto.K for { chunk, err := ch.Next(buf) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } @@ -69,7 +70,7 @@ func benchmarkChunkEncryptP(b *testing.PB, buf []byte, rd Rdr, key *crypto.Key) for { chunk, err := ch.Next(buf) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } @@ -292,7 +293,7 @@ func getRandomData(seed int, size int) []chunker.Chunk { for { c, err := chunker.Next(nil) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } chunks = append(chunks, c) diff --git a/src/restic/backend/generic.go b/src/restic/backend/generic.go index c528f8998..7510ad0fe 100644 --- a/src/restic/backend/generic.go +++ b/src/restic/backend/generic.go @@ -1,6 +1,6 @@ package backend -import "errors" +import "github.com/pkg/errors" // ErrNoIDPrefixFound is returned by Find() when no ID for the given prefix // could be found. diff --git a/src/restic/backend/handle.go b/src/restic/backend/handle.go index 6bdf6af23..09561161b 100644 --- a/src/restic/backend/handle.go +++ b/src/restic/backend/handle.go @@ -1,8 +1,9 @@ package backend import ( - "errors" "fmt" + + "github.com/pkg/errors" ) // Handle is used to store and access data in a backend. @@ -33,7 +34,7 @@ func (h Handle) Valid() error { case Index: case Config: default: - return fmt.Errorf("invalid Type %q", h.Type) + return errors.Errorf("invalid Type %q", h.Type) } if h.Type == Config { diff --git a/src/restic/backend/id.go b/src/restic/backend/id.go index 115792707..2714ee63e 100644 --- a/src/restic/backend/id.go +++ b/src/restic/backend/id.go @@ -5,7 +5,8 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "errors" + + "github.com/pkg/errors" ) // Hash returns the ID for data. @@ -24,7 +25,7 @@ func ParseID(s string) (ID, error) { b, err := hex.DecodeString(s) if err != nil { - return ID{}, err + return ID{}, errors.Wrap(err, "hex.DecodeString") } if len(b) != IDSize { @@ -72,7 +73,7 @@ func (id ID) Equal(other ID) bool { func (id ID) EqualString(other string) (bool, error) { s, err := hex.DecodeString(other) if err != nil { - return false, err + return false, errors.Wrap(err, "hex.DecodeString") } id2 := ID{} @@ -96,12 +97,12 @@ func (id *ID) UnmarshalJSON(b []byte) error { var s string err := json.Unmarshal(b, &s) if err != nil { - return err + return errors.Wrap(err, "Unmarshal") } _, err = hex.Decode(id[:], []byte(s)) if err != nil { - return err + return errors.Wrap(err, "hex.Decode") } return nil diff --git a/src/restic/backend/local/config.go b/src/restic/backend/local/config.go index 456f3c428..a430f9dec 100644 --- a/src/restic/backend/local/config.go +++ b/src/restic/backend/local/config.go @@ -1,8 +1,9 @@ package local import ( - "errors" "strings" + + "github.com/pkg/errors" ) // ParseConfig parses a local backend config. diff --git a/src/restic/backend/local/local.go b/src/restic/backend/local/local.go index 9a85f7a5b..c51ee949b 100644 --- a/src/restic/backend/local/local.go +++ b/src/restic/backend/local/local.go @@ -1,13 +1,13 @@ package local import ( - "errors" - "fmt" "io" "io/ioutil" "os" "path/filepath" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/fs" @@ -35,7 +35,7 @@ func Open(dir string) (*Local, error) { // test if all necessary dirs are there for _, d := range paths(dir) { if _, err := fs.Stat(d); err != nil { - return nil, fmt.Errorf("%s does not exist", d) + return nil, errors.Wrap(err, "Open") } } @@ -55,7 +55,7 @@ func Create(dir string) (*Local, error) { for _, d := range paths(dir) { err := fs.MkdirAll(d, backend.Modes.Dir) if err != nil { - return nil, err + return nil, errors.Wrap(err, "MkdirAll") } } @@ -110,13 +110,13 @@ func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) { f, err := fs.Open(filename(b.p, h.Type, h.Name)) if err != nil { - return 0, err + return 0, errors.Wrap(err, "Open") } defer func() { e := f.Close() if err == nil && e != nil { - err = e + err = errors.Wrap(e, "Close") } }() @@ -128,7 +128,7 @@ func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) { } if err != nil { - return 0, err + return 0, errors.Wrap(err, "Seek") } return io.ReadFull(f, p) @@ -138,12 +138,12 @@ func (b *Local) Load(h backend.Handle, p []byte, off int64) (n int, err error) { func writeToTempfile(tempdir string, p []byte) (filename string, err error) { tmpfile, err := ioutil.TempFile(tempdir, "temp-") if err != nil { - return "", err + return "", errors.Wrap(err, "TempFile") } n, err := tmpfile.Write(p) if err != nil { - return "", err + return "", errors.Wrap(err, "Write") } if n != len(p) { @@ -151,17 +151,17 @@ func writeToTempfile(tempdir string, p []byte) (filename string, err error) { } if err = tmpfile.Sync(); err != nil { - return "", err + return "", errors.Wrap(err, "Syncn") } err = fs.ClearCache(tmpfile) if err != nil { - return "", err + return "", errors.Wrap(err, "ClearCache") } err = tmpfile.Close() if err != nil { - return "", err + return "", errors.Wrap(err, "Close") } return tmpfile.Name(), nil @@ -184,14 +184,14 @@ func (b *Local) Save(h backend.Handle, p []byte) (err error) { // test if new path already exists if _, err := fs.Stat(filename); err == nil { - return fmt.Errorf("Rename(): file %v already exists", filename) + return errors.Errorf("Rename(): file %v already exists", filename) } // create directories if necessary, ignore errors if h.Type == backend.Data { err = fs.MkdirAll(filepath.Dir(filename), backend.Modes.Dir) if err != nil { - return err + return errors.Wrap(err, "MkdirAll") } } @@ -200,13 +200,13 @@ func (b *Local) Save(h backend.Handle, p []byte) (err error) { h, filepath.Base(tmpfile), filepath.Base(filename), err) if err != nil { - return err + return errors.Wrap(err, "Rename") } // set mode to read-only fi, err := fs.Stat(filename) if err != nil { - return err + return errors.Wrap(err, "Stat") } return setNewFileMode(filename, fi) @@ -221,7 +221,7 @@ func (b *Local) Stat(h backend.Handle) (backend.BlobInfo, error) { fi, err := fs.Stat(filename(b.p, h.Type, h.Name)) if err != nil { - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "Stat") } return backend.BlobInfo{Size: fi.Size()}, nil @@ -232,10 +232,10 @@ func (b *Local) Test(t backend.Type, name string) (bool, error) { debug.Log("backend.local.Test", "Test %v %v", t, name) _, err := fs.Stat(filename(b.p, t, name)) if err != nil { - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { return false, nil } - return false, err + return false, errors.Wrap(err, "Stat") } return true, nil @@ -249,7 +249,7 @@ func (b *Local) Remove(t backend.Type, name string) error { // reset read-only flag err := fs.Chmod(fn, 0666) if err != nil { - return err + return errors.Wrap(err, "Chmod") } return fs.Remove(fn) @@ -262,13 +262,13 @@ func isFile(fi os.FileInfo) bool { func readdir(d string) (fileInfos []os.FileInfo, err error) { f, e := fs.Open(d) if e != nil { - return nil, e + return nil, errors.Wrap(e, "Open") } defer func() { e := f.Close() if err == nil { - err = e + err = errors.Wrap(e, "Close") } }() diff --git a/src/restic/backend/mem/mem_backend.go b/src/restic/backend/mem/mem_backend.go index 5682d4915..239e2c899 100644 --- a/src/restic/backend/mem/mem_backend.go +++ b/src/restic/backend/mem/mem_backend.go @@ -1,10 +1,11 @@ package mem import ( - "errors" "io" "sync" + "github.com/pkg/errors" + "restic/backend" "restic/debug" ) diff --git a/src/restic/backend/mem/mem_backend_test.go b/src/restic/backend/mem/mem_backend_test.go index a65cdc246..cde3bda1c 100644 --- a/src/restic/backend/mem/mem_backend_test.go +++ b/src/restic/backend/mem/mem_backend_test.go @@ -1,7 +1,7 @@ package mem_test import ( - "errors" + "github.com/pkg/errors" "restic/backend" "restic/backend/mem" diff --git a/src/restic/backend/mock_backend.go b/src/restic/backend/mock_backend.go index 921af4d6c..70429acfd 100644 --- a/src/restic/backend/mock_backend.go +++ b/src/restic/backend/mock_backend.go @@ -1,6 +1,6 @@ package backend -import "errors" +import "github.com/pkg/errors" // MockBackend implements a backend whose functions can be specified. This // should only be used for tests. diff --git a/src/restic/backend/rest/config.go b/src/restic/backend/rest/config.go index c4459344c..e59031071 100644 --- a/src/restic/backend/rest/config.go +++ b/src/restic/backend/rest/config.go @@ -1,9 +1,10 @@ package rest import ( - "errors" "net/url" "strings" + + "github.com/pkg/errors" ) // Config contains all configuration necessary to connect to a REST server. @@ -21,7 +22,7 @@ func ParseConfig(s string) (interface{}, error) { u, err := url.Parse(s) if err != nil { - return nil, err + return nil, errors.Wrap(err, "url.Parse") } cfg := Config{URL: u} diff --git a/src/restic/backend/rest/rest.go b/src/restic/backend/rest/rest.go index 125331d78..a98fd5a80 100644 --- a/src/restic/backend/rest/rest.go +++ b/src/restic/backend/rest/rest.go @@ -3,7 +3,6 @@ package rest import ( "bytes" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -11,6 +10,8 @@ import ( "path" "strings" + "github.com/pkg/errors" + "restic/backend" ) @@ -79,7 +80,7 @@ func (b *restBackend) Load(h backend.Handle, p []byte, off int64) (n int, err er if off < 0 { info, err := b.Stat(h) if err != nil { - return 0, err + return 0, errors.Wrap(err, "Stat") } if -off > info.Size { @@ -91,7 +92,7 @@ func (b *restBackend) Load(h backend.Handle, p []byte, off int64) (n int, err er req, err := http.NewRequest("GET", restPath(b.url, h), nil) if err != nil { - return 0, err + return 0, errors.Wrap(err, "http.NewRequest") } req.Header.Add("Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(p)))) <-b.connChan @@ -103,16 +104,16 @@ func (b *restBackend) Load(h backend.Handle, p []byte, off int64) (n int, err er e := resp.Body.Close() if err == nil { - err = e + err = errors.Wrap(e, "Close") } }() } if err != nil { - return 0, err + return 0, errors.Wrap(err, "client.Do") } if resp.StatusCode != 200 && resp.StatusCode != 206 { - return 0, fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) + return 0, errors.Errorf("unexpected HTTP response code %v", resp.StatusCode) } return io.ReadFull(resp.Body, p) @@ -133,17 +134,17 @@ func (b *restBackend) Save(h backend.Handle, p []byte) (err error) { e := resp.Body.Close() if err == nil { - err = e + err = errors.Wrap(e, "Close") } }() } if err != nil { - return err + return errors.Wrap(err, "client.Post") } if resp.StatusCode != 200 { - return fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) + return errors.Errorf("unexpected HTTP response code %v", resp.StatusCode) } return nil @@ -159,15 +160,15 @@ func (b *restBackend) Stat(h backend.Handle) (backend.BlobInfo, error) { resp, err := b.client.Head(restPath(b.url, h)) b.connChan <- struct{}{} if err != nil { - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "client.Head") } if err = resp.Body.Close(); err != nil { - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "Close") } if resp.StatusCode != 200 { - return backend.BlobInfo{}, fmt.Errorf("unexpected HTTP response code %v", resp.StatusCode) + return backend.BlobInfo{}, errors.Errorf("unexpected HTTP response code %v", resp.StatusCode) } if resp.ContentLength < 0 { @@ -200,14 +201,14 @@ func (b *restBackend) Remove(t backend.Type, name string) error { req, err := http.NewRequest("DELETE", restPath(b.url, h), nil) if err != nil { - return err + return errors.Wrap(err, "http.NewRequest") } <-b.connChan resp, err := b.client.Do(req) b.connChan <- struct{}{} if err != nil { - return err + return errors.Wrap(err, "client.Do") } if resp.StatusCode != 200 { diff --git a/src/restic/backend/rest/rest_test.go b/src/restic/backend/rest/rest_test.go index bbcfff9b0..4e77cf612 100644 --- a/src/restic/backend/rest/rest_test.go +++ b/src/restic/backend/rest/rest_test.go @@ -1,11 +1,12 @@ package rest_test import ( - "errors" "fmt" "net/url" "os" + "github.com/pkg/errors" + "restic/backend" "restic/backend/rest" "restic/backend/test" diff --git a/src/restic/backend/s3/config.go b/src/restic/backend/s3/config.go index 5cd74ce79..4eda2b0e8 100644 --- a/src/restic/backend/s3/config.go +++ b/src/restic/backend/s3/config.go @@ -1,10 +1,11 @@ package s3 import ( - "errors" "net/url" "path" "strings" + + "github.com/pkg/errors" ) // Config contains all configuration necessary to connect to an s3 compatible @@ -31,7 +32,7 @@ func ParseConfig(s string) (interface{}, error) { // bucket name and prefix url, err := url.Parse(s[3:]) if err != nil { - return nil, err + return nil, errors.Wrap(err, "url.Parse") } if url.Path == "" { diff --git a/src/restic/backend/s3/s3.go b/src/restic/backend/s3/s3.go index c4e1aae54..835a7c485 100644 --- a/src/restic/backend/s3/s3.go +++ b/src/restic/backend/s3/s3.go @@ -2,10 +2,11 @@ package s3 import ( "bytes" - "errors" "io" "strings" + "github.com/pkg/errors" + "github.com/minio/minio-go" "restic/backend" @@ -29,7 +30,7 @@ func Open(cfg Config) (backend.Backend, error) { client, err := minio.New(cfg.Endpoint, cfg.KeyID, cfg.Secret, !cfg.UseHTTP) if err != nil { - return nil, err + return nil, errors.Wrap(err, "minio.New") } be := &s3{client: client, bucketname: cfg.Bucket, prefix: cfg.Prefix} @@ -38,14 +39,14 @@ func Open(cfg Config) (backend.Backend, error) { ok, err := client.BucketExists(cfg.Bucket) if err != nil { debug.Log("s3.Open", "BucketExists(%v) returned err %v, trying to create the bucket", cfg.Bucket, err) - return nil, err + return nil, errors.Wrap(err, "client.BucketExists") } if !ok { // create new bucket with default ACL in default region err = client.MakeBucket(cfg.Bucket, "") if err != nil { - return nil, err + return nil, errors.Wrap(err, "client.MakeBucket") } } @@ -94,20 +95,20 @@ func (be s3) Load(h backend.Handle, p []byte, off int64) (n int, err error) { obj, err = be.client.GetObject(be.bucketname, path) if err != nil { debug.Log("s3.Load", " err %v", err) - return 0, err + return 0, errors.Wrap(err, "client.GetObject") } // make sure that the object is closed properly. defer func() { e := obj.Close() if err == nil { - err = e + err = errors.Wrap(e, "Close") } }() info, err := obj.Stat() if err != nil { - return 0, err + return 0, errors.Wrap(err, "obj.Stat") } // handle negative offsets @@ -124,7 +125,7 @@ func (be s3) Load(h backend.Handle, p []byte, off int64) (n int, err error) { // return an error if the offset is beyond the end of the file if off > info.Size { - return 0, io.EOF + return 0, errors.Wrap(io.EOF, "") } var nextError error @@ -140,7 +141,7 @@ func (be s3) Load(h backend.Handle, p []byte, off int64) (n int, err error) { } n, err = obj.ReadAt(p, off) - if int64(n) == info.Size-off && err == io.EOF { + if int64(n) == info.Size-off && errors.Cause(err) == io.EOF { err = nil } @@ -178,7 +179,7 @@ func (be s3) Save(h backend.Handle, p []byte) (err error) { n, err := be.client.PutObject(be.bucketname, path, bytes.NewReader(p), "binary/octet-stream") debug.Log("s3.Save", "%v -> %v bytes, err %#v", path, n, err) - return err + return errors.Wrap(err, "client.PutObject") } // Stat returns information about a blob. @@ -191,21 +192,21 @@ func (be s3) Stat(h backend.Handle) (bi backend.BlobInfo, err error) { obj, err = be.client.GetObject(be.bucketname, path) if err != nil { debug.Log("s3.Stat", "GetObject() err %v", err) - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "client.GetObject") } // make sure that the object is closed properly. defer func() { e := obj.Close() if err == nil { - err = e + err = errors.Wrap(e, "Close") } }() fi, err := obj.Stat() if err != nil { debug.Log("s3.Stat", "Stat() err %v", err) - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "Stat") } return backend.BlobInfo{Size: fi.Size}, nil @@ -229,7 +230,7 @@ func (be *s3) Remove(t backend.Type, name string) error { path := be.s3path(t, name) err := be.client.RemoveObject(be.bucketname, path) debug.Log("s3.Remove", "%v %v -> err %v", t, name, err) - return err + return errors.Wrap(err, "client.RemoveObject") } // List returns a channel that yields all names of blobs of type t. A diff --git a/src/restic/backend/s3/s3_test.go b/src/restic/backend/s3/s3_test.go index 586398de9..6fd9c3bf6 100644 --- a/src/restic/backend/s3/s3_test.go +++ b/src/restic/backend/s3/s3_test.go @@ -1,11 +1,12 @@ package s3_test import ( - "errors" "fmt" "net/url" "os" + "github.com/pkg/errors" + "restic/backend" "restic/backend/s3" "restic/backend/test" diff --git a/src/restic/backend/sftp/config.go b/src/restic/backend/sftp/config.go index e6dfd0d27..d8e200491 100644 --- a/src/restic/backend/sftp/config.go +++ b/src/restic/backend/sftp/config.go @@ -1,11 +1,11 @@ package sftp import ( - "errors" - "fmt" "net/url" "path" "strings" + + "github.com/pkg/errors" ) // Config collects all information required to connect to an sftp server. @@ -26,7 +26,7 @@ func ParseConfig(s string) (interface{}, error) { // parse the "sftp://user@host/path" url format url, err := url.Parse(s) if err != nil { - return nil, err + return nil, errors.Wrap(err, "url.Parse") } if url.User != nil { user = url.User.Username() @@ -34,7 +34,7 @@ func ParseConfig(s string) (interface{}, error) { host = url.Host dir = url.Path if dir == "" { - return nil, fmt.Errorf("invalid backend %q, no directory specified", s) + return nil, errors.Errorf("invalid backend %q, no directory specified", s) } dir = dir[1:] diff --git a/src/restic/backend/sftp/sftp.go b/src/restic/backend/sftp/sftp.go index 0a79d4c6b..c82e29683 100644 --- a/src/restic/backend/sftp/sftp.go +++ b/src/restic/backend/sftp/sftp.go @@ -12,10 +12,11 @@ import ( "strings" "time" + "github.com/pkg/errors" + "restic/backend" "restic/debug" - "github.com/juju/errors" "github.com/pkg/sftp" ) @@ -40,7 +41,7 @@ func startClient(program string, args ...string) (*SFTP, error) { // prefix the errors with the program name stderr, err := cmd.StderrPipe() if err != nil { - return nil, err + return nil, errors.Wrap(err, "cmd.StderrPipe") } go func() { @@ -56,16 +57,16 @@ func startClient(program string, args ...string) (*SFTP, error) { // get stdin and stdout wr, err := cmd.StdinPipe() if err != nil { - return nil, err + return nil, errors.Wrap(err, "cmd.StdinPipe") } rd, err := cmd.StdoutPipe() if err != nil { - return nil, err + return nil, errors.Wrap(err, "cmd.StdoutPipe") } // start the process if err := cmd.Start(); err != nil { - return nil, err + return nil, errors.Wrap(err, "cmd.Start") } // wait in a different goroutine @@ -73,13 +74,13 @@ func startClient(program string, args ...string) (*SFTP, error) { go func() { err := cmd.Wait() debug.Log("sftp.Wait", "ssh command exited, err %v", err) - ch <- err + ch <- errors.Wrap(err, "cmd.Wait") }() // open the SFTP session client, err := sftp.NewClientPipe(rd, wr) if err != nil { - return nil, fmt.Errorf("unable to start the sftp session, error: %v", err) + return nil, errors.Errorf("unable to start the sftp session, error: %v", err) } return &SFTP{c: client, cmd: cmd, result: ch}, nil @@ -125,7 +126,7 @@ func Open(dir string, program string, args ...string) (*SFTP, error) { // test if all necessary dirs and files are there for _, d := range paths(dir) { if _, err := sftp.c.Lstat(d); err != nil { - return nil, fmt.Errorf("%s does not exist", d) + return nil, errors.Errorf("%s does not exist", d) } } @@ -181,7 +182,7 @@ func Create(dir string, program string, args ...string) (*SFTP, error) { err = sftp.Close() if err != nil { - return nil, err + return nil, errors.Wrap(err, "Close") } // open backend @@ -206,9 +207,8 @@ func (r *SFTP) tempFile() (string, *sftp.File, error) { buf := make([]byte, tempfileRandomSuffixLength) _, err := io.ReadFull(rand.Reader, buf) if err != nil { - return "", nil, errors.Annotatef(err, - "unable to read %d random bytes for tempfile name", - tempfileRandomSuffixLength) + return "", nil, errors.Errorf("unable to read %d random bytes for tempfile name: %v", + tempfileRandomSuffixLength, err) } // construct tempfile name @@ -217,7 +217,7 @@ func (r *SFTP) tempFile() (string, *sftp.File, error) { // create file in temp dir f, err := r.c.Create(name) if err != nil { - return "", nil, errors.Annotatef(err, "creating tempfile %q failed", name) + return "", nil, errors.Errorf("creating tempfile %q failed: %v", name, err) } return name, f, nil @@ -231,7 +231,7 @@ func (r *SFTP) mkdirAll(dir string, mode os.FileMode) error { return nil } - return fmt.Errorf("mkdirAll(%s): entry exists but is not a directory", dir) + return errors.Errorf("mkdirAll(%s): entry exists but is not a directory", dir) } // create parent directories @@ -244,11 +244,11 @@ func (r *SFTP) mkdirAll(dir string, mode os.FileMode) error { fi, err = r.c.Lstat(dir) if err != nil { // return previous errors - return fmt.Errorf("mkdirAll(%s): unable to create directories: %v, %v", dir, errMkdirAll, errMkdir) + return errors.Errorf("mkdirAll(%s): unable to create directories: %v, %v", dir, errMkdirAll, errMkdir) } if !fi.IsDir() { - return fmt.Errorf("mkdirAll(%s): entry exists but is not a directory", dir) + return errors.Errorf("mkdirAll(%s): entry exists but is not a directory", dir) } // set mode @@ -269,21 +269,22 @@ func (r *SFTP) renameFile(oldname string, t backend.Type, name string) error { // test if new file exists if _, err := r.c.Lstat(filename); err == nil { - return fmt.Errorf("Close(): file %v already exists", filename) + return errors.Errorf("Close(): file %v already exists", filename) } err := r.c.Rename(oldname, filename) if err != nil { - return err + return errors.Wrap(err, "Rename") } // set mode to read-only fi, err := r.c.Lstat(filename) if err != nil { - return err + return errors.Wrap(err, "Lstat") } - return r.c.Chmod(filename, fi.Mode()&os.FileMode(^uint32(0222))) + err = r.c.Chmod(filename, fi.Mode()&os.FileMode(^uint32(0222))) + return errors.Wrap(err, "Chmod") } // Join joins the given paths and cleans them afterwards. This always uses @@ -336,13 +337,13 @@ func (r *SFTP) Load(h backend.Handle, p []byte, off int64) (n int, err error) { f, err := r.c.Open(r.filename(h.Type, h.Name)) if err != nil { - return 0, err + return 0, errors.Wrap(err, "Open") } defer func() { e := f.Close() if err == nil && e != nil { - err = e + err = errors.Wrap(e, "Close") } }() @@ -354,7 +355,7 @@ func (r *SFTP) Load(h backend.Handle, p []byte, off int64) (n int, err error) { } if err != nil { - return 0, err + return 0, errors.Wrap(err, "Seek") } return io.ReadFull(f, p) @@ -380,7 +381,7 @@ func (r *SFTP) Save(h backend.Handle, p []byte) (err error) { n, err := tmpfile.Write(p) if err != nil { - return err + return errors.Wrap(err, "Write") } if n != len(p) { @@ -389,17 +390,13 @@ func (r *SFTP) Save(h backend.Handle, p []byte) (err error) { err = tmpfile.Close() if err != nil { - return err + return errors.Wrap(err, "Close") } err = r.renameFile(filename, h.Type, h.Name) debug.Log("sftp.Save", "save %v: rename %v: %v", h, path.Base(filename), err) - if err != nil { - return fmt.Errorf("sftp: renameFile: %v", err) - } - - return nil + return err } // Stat returns information about a blob. @@ -415,7 +412,7 @@ func (r *SFTP) Stat(h backend.Handle) (backend.BlobInfo, error) { fi, err := r.c.Lstat(r.filename(h.Type, h.Name)) if err != nil { - return backend.BlobInfo{}, err + return backend.BlobInfo{}, errors.Wrap(err, "Lstat") } return backend.BlobInfo{Size: fi.Size()}, nil @@ -429,12 +426,12 @@ func (r *SFTP) Test(t backend.Type, name string) (bool, error) { } _, err := r.c.Lstat(r.filename(t, name)) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { return false, nil } if err != nil { - return false, err + return false, errors.Wrap(err, "Lstat") } return true, nil diff --git a/src/restic/backend/sftp/sftp_backend_test.go b/src/restic/backend/sftp/sftp_backend_test.go index 52b50f6f2..2d8e609ca 100644 --- a/src/restic/backend/sftp/sftp_backend_test.go +++ b/src/restic/backend/sftp/sftp_backend_test.go @@ -6,6 +6,8 @@ import ( "path/filepath" "strings" + "github.com/pkg/errors" + "restic/backend" "restic/backend/sftp" "restic/backend/test" @@ -37,7 +39,7 @@ func init() { for _, dir := range strings.Split(TestSFTPPath, ":") { testpath := filepath.Join(dir, "sftp-server") _, err := os.Stat(testpath) - if !os.IsNotExist(err) { + if !os.IsNotExist(errors.Cause(err)) { sftpserver = testpath break } diff --git a/src/restic/backend/test/tests.go b/src/restic/backend/test/tests.go index 77896499e..a9b18e361 100644 --- a/src/restic/backend/test/tests.go +++ b/src/restic/backend/test/tests.go @@ -10,6 +10,8 @@ import ( "sort" "testing" + "github.com/pkg/errors" + "restic/backend" . "restic/test" ) @@ -223,7 +225,7 @@ func TestLoad(t testing.TB) { // if we requested data beyond the end of the file, require // ErrUnexpectedEOF error if l > len(d) { - if err != io.ErrUnexpectedEOF { + if errors.Cause(err) != io.ErrUnexpectedEOF { t.Errorf("Load(%d, %d) did not return io.ErrUnexpectedEOF", len(buf), int64(o)) } err = nil @@ -270,7 +272,7 @@ func TestLoad(t testing.TB) { // if we requested data beyond the end of the file, require // ErrUnexpectedEOF error if l > len(d) { - if err != io.ErrUnexpectedEOF { + if errors.Cause(err) != io.ErrUnexpectedEOF { t.Errorf("Load(%d, %d) did not return io.ErrUnexpectedEOF", len(buf), int64(o)) continue } @@ -303,7 +305,7 @@ func TestLoad(t testing.TB) { t.Errorf("wrong length for larger buffer returned, want %d, got %d", length, n) } - if err != io.ErrUnexpectedEOF { + if errors.Cause(err) != io.ErrUnexpectedEOF { t.Errorf("wrong error returned for larger buffer: want io.ErrUnexpectedEOF, got %#v", err) } @@ -337,7 +339,7 @@ func TestLoadNegativeOffset(t testing.TB) { // if we requested data beyond the end of the file, require // ErrUnexpectedEOF error if len(buf) > -o { - if err != io.ErrUnexpectedEOF { + if errors.Cause(err) != io.ErrUnexpectedEOF { t.Errorf("Load(%d, %d) did not return io.ErrUnexpectedEOF", len(buf), o) continue } diff --git a/src/restic/backend/test/tests_test.go b/src/restic/backend/test/tests_test.go index 1674f1f5e..5dbba88a4 100644 --- a/src/restic/backend/test/tests_test.go +++ b/src/restic/backend/test/tests_test.go @@ -1,7 +1,7 @@ package test_test import ( - "errors" + "github.com/pkg/errors" "restic/backend" "restic/backend/mem" diff --git a/src/restic/backend/utils.go b/src/restic/backend/utils.go index e1c36236b..9bd87b4fb 100644 --- a/src/restic/backend/utils.go +++ b/src/restic/backend/utils.go @@ -1,6 +1,10 @@ package backend -import "io" +import ( + "io" + + "github.com/pkg/errors" +) // LoadAll reads all data stored in the backend for the handle. The buffer buf // is resized to accomodate all data in the blob. Errors returned by be.Load() @@ -9,7 +13,7 @@ import "io" func LoadAll(be Backend, h Handle, buf []byte) ([]byte, error) { fi, err := be.Stat(h) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Stat") } if fi.Size > int64(len(buf)) { @@ -17,7 +21,7 @@ func LoadAll(be Backend, h Handle, buf []byte) ([]byte, error) { } n, err := be.Load(h, buf, 0) - if err == io.ErrUnexpectedEOF { + if errors.Cause(err) == io.ErrUnexpectedEOF { err = nil } buf = buf[:n] diff --git a/src/restic/cache.go b/src/restic/cache.go index e4b8507ca..1af4e9605 100644 --- a/src/restic/cache.go +++ b/src/restic/cache.go @@ -1,14 +1,14 @@ package restic import ( - "errors" - "fmt" "io" "os" "path/filepath" "runtime" "strings" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/fs" @@ -48,13 +48,13 @@ func (c *Cache) Has(t backend.Type, subtype string, id backend.ID) (bool, error) defer fd.Close() if err != nil { - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { debug.Log("Cache.Has", "test for file %v: not cached", filename) return false, nil } debug.Log("Cache.Has", "test for file %v: error %v", filename, err) - return false, err + return false, errors.Wrap(err, "Open") } debug.Log("Cache.Has", "test for file %v: is cached", filename) @@ -73,13 +73,13 @@ func (c *Cache) Store(t backend.Type, subtype string, id backend.ID) (io.WriteCl dirname := filepath.Dir(filename) err = fs.MkdirAll(dirname, 0700) if err != nil { - return nil, err + return nil, errors.Wrap(err, "MkdirAll") } file, err := fs.Create(filename) if err != nil { debug.Log("Cache.Store", "error creating file %v: %v", filename, err) - return nil, err + return nil, errors.Wrap(err, "Create") } debug.Log("Cache.Store", "created file %v", filename) @@ -106,11 +106,11 @@ func (c *Cache) purge(t backend.Type, subtype string, id backend.ID) error { err = fs.Remove(filename) debug.Log("Cache.purge", "Remove file %v: %v", filename, err) - if err != nil && os.IsNotExist(err) { + if err != nil && os.IsNotExist(errors.Cause(err)) { return nil } - return err + return errors.Wrap(err, "Remove") } // Clear removes information from the cache that isn't present in the repository any more. @@ -155,21 +155,21 @@ func (c *Cache) list(t backend.Type) ([]cacheEntry, error) { case backend.Snapshot: dir = filepath.Join(c.base, "snapshots") default: - return nil, fmt.Errorf("cache not supported for type %v", t) + return nil, errors.Errorf("cache not supported for type %v", t) } fd, err := fs.Open(dir) if err != nil { - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { return []cacheEntry{}, nil } - return nil, err + return nil, errors.Wrap(err, "Open") } defer fd.Close() fis, err := fd.Readdir(-1) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Readdir") } entries := make([]cacheEntry, 0, len(fis)) @@ -207,7 +207,7 @@ func (c *Cache) filename(t backend.Type, subtype string, id backend.ID) (string, return filepath.Join(c.base, "snapshots", filename), nil } - return "", fmt.Errorf("cache not supported for type %v", t) + return "", errors.Errorf("cache not supported for type %v", t) } func getCacheDir() (string, error) { @@ -231,21 +231,21 @@ func getWindowsCacheDir() (string, error) { cachedir = filepath.Join(cachedir, "restic") fi, err := fs.Stat(cachedir) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { err = fs.MkdirAll(cachedir, 0700) if err != nil { - return "", err + return "", errors.Wrap(err, "MkdirAll") } return cachedir, nil } if err != nil { - return "", err + return "", errors.Wrap(err, "Stat") } if !fi.IsDir() { - return "", fmt.Errorf("cache dir %v is not a directory", cachedir) + return "", errors.Errorf("cache dir %v is not a directory", cachedir) } return cachedir, nil } @@ -268,10 +268,10 @@ func getXDGCacheDir() (string, error) { } fi, err := fs.Stat(cachedir) - if os.IsNotExist(err) { + if os.IsNotExist(errors.Cause(err)) { err = fs.MkdirAll(cachedir, 0700) if err != nil { - return "", err + return "", errors.Wrap(err, "MkdirAll") } fi, err = fs.Stat(cachedir) @@ -279,11 +279,11 @@ func getXDGCacheDir() (string, error) { } if err != nil { - return "", err + return "", errors.Wrap(err, "Stat") } if !fi.IsDir() { - return "", fmt.Errorf("cache dir %v is not a directory", cachedir) + return "", errors.Errorf("cache dir %v is not a directory", cachedir) } return cachedir, nil diff --git a/src/restic/cache_test.go b/src/restic/cache_test.go index d4157b1b5..c72b26e2a 100644 --- a/src/restic/cache_test.go +++ b/src/restic/cache_test.go @@ -18,6 +18,9 @@ func TestCache(t *testing.T) { // archive some files, this should automatically cache all blobs from the snapshot _, _, err = arch.Snapshot(nil, []string{BenchArchiveDirectory}, nil) + if err != nil { + t.Fatal(err) + } // TODO: test caching index } diff --git a/src/restic/checker/checker.go b/src/restic/checker/checker.go index fc15b35fd..1755bd3ac 100644 --- a/src/restic/checker/checker.go +++ b/src/restic/checker/checker.go @@ -2,10 +2,11 @@ package checker import ( "bytes" - "errors" "fmt" "sync" + "github.com/pkg/errors" + "restic" "restic/backend" "restic/crypto" @@ -84,7 +85,7 @@ func (c *Checker) LoadIndex() (hints []error, errs []error) { worker := func(id backend.ID, done <-chan struct{}) error { debug.Log("LoadIndex", "worker got index %v", id) idx, err := repository.LoadIndexWithDecoder(c.repo, id, repository.DecodeIndex) - if err == repository.ErrOldIndexFormat { + if errors.Cause(err) == repository.ErrOldIndexFormat { debug.Log("LoadIndex", "index %v has old format", id.Str()) hints = append(hints, ErrOldIndexFormat{id}) @@ -126,7 +127,7 @@ func (c *Checker) LoadIndex() (hints []error, errs []error) { debug.Log("LoadIndex", "process index %v", res.ID) idxID, err := backend.ParseID(res.ID) if err != nil { - errs = append(errs, fmt.Errorf("unable to parse as index ID: %v", res.ID)) + errs = append(errs, errors.Errorf("unable to parse as index ID: %v", res.ID)) continue } @@ -281,7 +282,7 @@ func loadTreeFromSnapshot(repo *repository.Repository, id backend.ID) (backend.I if sn.Tree == nil { debug.Log("Checker.loadTreeFromSnapshot", "snapshot %v has no tree", id.Str()) - return backend.ID{}, fmt.Errorf("snapshot %v has no tree", id) + return backend.ID{}, errors.Errorf("snapshot %v has no tree", id) } return *sn.Tree, nil @@ -583,24 +584,24 @@ func (c *Checker) checkTree(id backend.ID, tree *restic.Tree) (errs []error) { switch node.Type { case "file": if node.Content == nil { - errs = append(errs, Error{TreeID: id, Err: fmt.Errorf("file %q has nil blob list", node.Name)}) + errs = append(errs, Error{TreeID: id, Err: errors.Errorf("file %q has nil blob list", node.Name)}) } for b, blobID := range node.Content { if blobID.IsNull() { - errs = append(errs, Error{TreeID: id, Err: fmt.Errorf("file %q blob %d has null ID", node.Name, b)}) + errs = append(errs, Error{TreeID: id, Err: errors.Errorf("file %q blob %d has null ID", node.Name, b)}) continue } blobs = append(blobs, blobID) } case "dir": if node.Subtree == nil { - errs = append(errs, Error{TreeID: id, Err: fmt.Errorf("dir node %q has no subtree", node.Name)}) + errs = append(errs, Error{TreeID: id, Err: errors.Errorf("dir node %q has no subtree", node.Name)}) continue } if node.Subtree.IsNull() { - errs = append(errs, Error{TreeID: id, Err: fmt.Errorf("dir node %q subtree id is null", node.Name)}) + errs = append(errs, Error{TreeID: id, Err: errors.Errorf("dir node %q subtree id is null", node.Name)}) continue } @@ -608,7 +609,7 @@ func (c *Checker) checkTree(id backend.ID, tree *restic.Tree) (errs []error) { // nothing to check default: - errs = append(errs, Error{TreeID: id, Err: fmt.Errorf("node %q with invalid type %q", node.Name, node.Type)}) + errs = append(errs, Error{TreeID: id, Err: errors.Errorf("node %q with invalid type %q", node.Name, node.Type)}) } if node.Name == "" { @@ -670,7 +671,7 @@ func checkPack(r *repository.Repository, id backend.ID) error { hash := backend.Hash(buf) if !hash.Equal(id) { debug.Log("Checker.checkPack", "Pack ID does not match, want %v, got %v", id.Str(), hash.Str()) - return fmt.Errorf("Pack ID does not match, want %v, got %v", id.Str(), hash.Str()) + return errors.Errorf("Pack ID does not match, want %v, got %v", id.Str(), hash.Str()) } blobs, err := pack.List(r.Key(), bytes.NewReader(buf), int64(len(buf))) @@ -686,20 +687,20 @@ func checkPack(r *repository.Repository, id backend.ID) error { plainBuf, err = crypto.Decrypt(r.Key(), plainBuf, buf[blob.Offset:blob.Offset+blob.Length]) if err != nil { debug.Log("Checker.checkPack", " error decrypting blob %v: %v", blob.ID.Str(), err) - errs = append(errs, fmt.Errorf("blob %v: %v", i, err)) + errs = append(errs, errors.Errorf("blob %v: %v", i, err)) continue } hash := backend.Hash(plainBuf) if !hash.Equal(blob.ID) { debug.Log("Checker.checkPack", " Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str()) - errs = append(errs, fmt.Errorf("Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str())) + errs = append(errs, errors.Errorf("Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str())) continue } } if len(errs) > 0 { - return fmt.Errorf("pack %v contains %v errors: %v", id.Str(), len(errs), errs) + return errors.Errorf("pack %v contains %v errors: %v", id.Str(), len(errs), errs) } return nil diff --git a/src/restic/crypto/crypto.go b/src/restic/crypto/crypto.go index 17cfa3097..33b9dfda8 100644 --- a/src/restic/crypto/crypto.go +++ b/src/restic/crypto/crypto.go @@ -5,9 +5,10 @@ import ( "crypto/cipher" "crypto/rand" "encoding/json" - "errors" "fmt" + "github.com/pkg/errors" + "golang.org/x/crypto/poly1305" ) @@ -167,7 +168,7 @@ func (m *MACKey) UnmarshalJSON(data []byte) error { j := jsonMACKey{} err := json.Unmarshal(data, &j) if err != nil { - return err + return errors.Wrap(err, "Unmarshal") } copy(m.K[:], j.K) copy(m.R[:], j.R) @@ -205,7 +206,7 @@ func (k *EncryptionKey) UnmarshalJSON(data []byte) error { d := make([]byte, aesKeySize) err := json.Unmarshal(data, &d) if err != nil { - return err + return errors.Wrap(err, "Unmarshal") } copy(k[:], d) diff --git a/src/restic/crypto/kdf.go b/src/restic/crypto/kdf.go index 7fe124e44..ea8be37b6 100644 --- a/src/restic/crypto/kdf.go +++ b/src/restic/crypto/kdf.go @@ -2,10 +2,10 @@ package crypto import ( "crypto/rand" - "fmt" "time" sscrypt "github.com/elithrar/simple-scrypt" + "github.com/pkg/errors" "golang.org/x/crypto/scrypt" ) @@ -37,7 +37,7 @@ func Calibrate(timeout time.Duration, memory int) (KDFParams, error) { params, err := sscrypt.Calibrate(timeout, memory, defaultParams) if err != nil { - return DefaultKDFParams, err + return DefaultKDFParams, errors.Wrap(err, "scrypt.Calibrate") } return KDFParams{ @@ -51,7 +51,7 @@ func Calibrate(timeout time.Duration, memory int) (KDFParams, error) { // using the supplied parameters N, R and P and the Salt. func KDF(p KDFParams, salt []byte, password string) (*Key, error) { if len(salt) != saltLength { - return nil, fmt.Errorf("scrypt() called with invalid salt bytes (len %d)", len(salt)) + return nil, errors.Errorf("scrypt() called with invalid salt bytes (len %d)", len(salt)) } // make sure we have valid parameters @@ -64,7 +64,7 @@ func KDF(p KDFParams, salt []byte, password string) (*Key, error) { } if err := params.Check(); err != nil { - return nil, err + return nil, errors.Wrap(err, "Check") } derKeys := &Key{} @@ -72,11 +72,11 @@ func KDF(p KDFParams, salt []byte, password string) (*Key, error) { keybytes := macKeySize + aesKeySize scryptKeys, err := scrypt.Key([]byte(password), salt, p.N, p.R, p.P, keybytes) if err != nil { - return nil, fmt.Errorf("error deriving keys from password: %v", err) + return nil, errors.Wrap(err, "scrypt.Key") } if len(scryptKeys) != keybytes { - return nil, fmt.Errorf("invalid numbers of bytes expanded from scrypt(): %d", len(scryptKeys)) + return nil, errors.Errorf("invalid numbers of bytes expanded from scrypt(): %d", len(scryptKeys)) } // first 32 byte of scrypt output is the encryption key diff --git a/src/restic/debug/debug.go b/src/restic/debug/debug.go index 12b8c490a..aeae376cd 100644 --- a/src/restic/debug/debug.go +++ b/src/restic/debug/debug.go @@ -14,6 +14,8 @@ import ( "strings" "sync" "time" + + "github.com/pkg/errors" ) type process struct { @@ -59,7 +61,7 @@ func initDebugLogger() { } } - if err != nil && os.IsNotExist(err) { + if err != nil && os.IsNotExist(errors.Cause(err)) { f, err = fs.OpenFile(debugfile, os.O_WRONLY|os.O_CREATE, 0600) } diff --git a/src/restic/errors.go b/src/restic/errors.go new file mode 100644 index 000000000..1aa7e1fdc --- /dev/null +++ b/src/restic/errors.go @@ -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...)) +} diff --git a/src/restic/filter/filter.go b/src/restic/filter/filter.go index 7105a76a0..48ce01fb8 100644 --- a/src/restic/filter/filter.go +++ b/src/restic/filter/filter.go @@ -1,9 +1,10 @@ package filter import ( - "errors" "path/filepath" "strings" + + "github.com/pkg/errors" ) // ErrBadString is returned when Match is called with the empty string as the @@ -84,7 +85,7 @@ func match(patterns, strs []string) (matched bool, err error) { for i := len(patterns) - 1; i >= 0; i-- { ok, err := filepath.Match(patterns[i], strs[offset+i]) if err != nil { - return false, err + return false, errors.Wrap(err, "Match") } if !ok { diff --git a/src/restic/fs/file_linux.go b/src/restic/fs/file_linux.go index 4e0831b76..e3cdf9600 100644 --- a/src/restic/fs/file_linux.go +++ b/src/restic/fs/file_linux.go @@ -6,13 +6,15 @@ import ( "os" "syscall" + "github.com/pkg/errors" + "golang.org/x/sys/unix" ) // Open opens a file for reading, without updating the atime and without caching data on read. func Open(name string) (File, error) { file, err := os.OpenFile(name, os.O_RDONLY|syscall.O_NOATIME, 0) - if os.IsPermission(err) { + if os.IsPermission(errors.Cause(err)) { file, err = os.OpenFile(name, os.O_RDONLY, 0) } return &nonCachingFile{File: file}, err diff --git a/src/restic/fuse/file.go b/src/restic/fuse/file.go index ef6766d9e..f6dfa771e 100644 --- a/src/restic/fuse/file.go +++ b/src/restic/fuse/file.go @@ -4,9 +4,10 @@ package fuse import ( - "errors" "sync" + "github.com/pkg/errors" + "restic" "restic/backend" "restic/debug" diff --git a/src/restic/fuse/file_test.go b/src/restic/fuse/file_test.go index 12bcb8598..cb1c67452 100644 --- a/src/restic/fuse/file_test.go +++ b/src/restic/fuse/file_test.go @@ -5,11 +5,12 @@ package fuse import ( "bytes" - "errors" "math/rand" "testing" "time" + "github.com/pkg/errors" + "bazil.org/fuse" "restic" diff --git a/src/restic/fuse/link.go b/src/restic/fuse/link.go index 1cf02df0f..732446a7a 100644 --- a/src/restic/fuse/link.go +++ b/src/restic/fuse/link.go @@ -4,11 +4,12 @@ package fuse import ( + "restic" + "restic/repository" + "bazil.org/fuse" "bazil.org/fuse/fs" "golang.org/x/net/context" - "restic" - "restic/repository" ) // Statically ensure that *file implements the given interface diff --git a/src/restic/index/index.go b/src/restic/index/index.go index 0d2d70397..20d2e08fe 100644 --- a/src/restic/index/index.go +++ b/src/restic/index/index.go @@ -2,7 +2,6 @@ package index import ( - "errors" "fmt" "os" "restic" @@ -12,6 +11,8 @@ import ( "restic/pack" "restic/types" "restic/worker" + + "github.com/pkg/errors" ) // Pack contains information about the contents of a pack. @@ -180,7 +181,7 @@ func Load(repo types.Repository, p *restic.Progress) (*Index, error) { // error is returned. func (idx *Index) AddPack(id backend.ID, size int64, entries []pack.Blob) error { if _, ok := idx.Packs[id]; ok { - return fmt.Errorf("pack %v already present in the index", id.Str()) + return errors.Errorf("pack %v already present in the index", id.Str()) } idx.Packs[id] = Pack{Size: size, Entries: entries} @@ -203,7 +204,7 @@ func (idx *Index) AddPack(id backend.ID, size int64, entries []pack.Blob) error // RemovePack deletes a pack from the index. func (idx *Index) RemovePack(id backend.ID) error { if _, ok := idx.Packs[id]; !ok { - return fmt.Errorf("pack %v not found in the index", id.Str()) + return errors.Errorf("pack %v not found in the index", id.Str()) } for _, blob := range idx.Packs[id].Entries { @@ -278,7 +279,7 @@ func (idx *Index) FindBlob(h pack.Handle) ([]Location, error) { for packID := range blob.Packs { pack, ok := idx.Packs[packID] if !ok { - return nil, fmt.Errorf("pack %v not found in index", packID.Str()) + return nil, errors.Errorf("pack %v not found in index", packID.Str()) } for _, entry := range pack.Entries { diff --git a/src/restic/lock.go b/src/restic/lock.go index 5628e7577..a2780379d 100644 --- a/src/restic/lock.go +++ b/src/restic/lock.go @@ -9,6 +9,8 @@ import ( "syscall" "time" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/repository" @@ -47,7 +49,7 @@ func (e ErrAlreadyLocked) Error() string { // IsAlreadyLocked returns true iff err is an instance of ErrAlreadyLocked. func IsAlreadyLocked(err error) bool { - if _, ok := err.(ErrAlreadyLocked); ok { + if _, ok := errors.Cause(err).(ErrAlreadyLocked); ok { return true } @@ -189,7 +191,7 @@ var staleTimeout = 30 * time.Minute // process isn't alive any more. func (l *Lock) Stale() bool { debug.Log("Lock.Stale", "testing if lock %v for process %d is stale", l, l.PID) - if time.Now().Sub(l.Time) > staleTimeout { + if time.Since(l.Time) > staleTimeout { debug.Log("Lock.Stale", "lock is stale, timestamp is too old: %v\n", l.Time) return true } diff --git a/src/restic/lock_unix.go b/src/restic/lock_unix.go index 04395c9a6..6b481ed26 100644 --- a/src/restic/lock_unix.go +++ b/src/restic/lock_unix.go @@ -8,6 +8,8 @@ import ( "strconv" "syscall" + "github.com/pkg/errors" + "restic/debug" ) @@ -16,11 +18,11 @@ func uidGidInt(u user.User) (uid, gid uint32, err error) { var ui, gi int64 ui, err = strconv.ParseInt(u.Uid, 10, 32) if err != nil { - return + return uid, gid, errors.Wrap(err, "ParseInt") } gi, err = strconv.ParseInt(u.Gid, 10, 32) if err != nil { - return + return uid, gid, errors.Wrap(err, "ParseInt") } uid = uint32(ui) gid = uint32(gi) diff --git a/src/restic/node.go b/src/restic/node.go index a2f64dacd..37ef5e04c 100644 --- a/src/restic/node.go +++ b/src/restic/node.go @@ -10,6 +10,8 @@ import ( "syscall" "time" + "github.com/pkg/errors" + "runtime" "restic/backend" @@ -17,8 +19,6 @@ import ( "restic/fs" "restic/pack" "restic/repository" - - "github.com/juju/errors" ) // Node is a file, directory or other item in a backup. @@ -114,32 +114,32 @@ func (node *Node) CreateAt(path string, repo *repository.Repository) error { switch node.Type { case "dir": if err := node.createDirAt(path); err != nil { - return errors.Annotate(err, "createDirAt") + return err } case "file": if err := node.createFileAt(path, repo); err != nil { - return errors.Annotate(err, "createFileAt") + return err } case "symlink": if err := node.createSymlinkAt(path); err != nil { - return errors.Annotate(err, "createSymlinkAt") + return err } case "dev": if err := node.createDevAt(path); err != nil { - return errors.Annotate(err, "createDevAt") + return err } case "chardev": if err := node.createCharDevAt(path); err != nil { - return errors.Annotate(err, "createCharDevAt") + return err } case "fifo": if err := node.createFifoAt(path); err != nil { - return errors.Annotate(err, "createFifoAt") + return err } case "socket": return nil default: - return fmt.Errorf("filetype %q not implemented!\n", node.Type) + return errors.Errorf("filetype %q not implemented!\n", node.Type) } err := node.restoreMetadata(path) @@ -155,13 +155,13 @@ func (node Node) restoreMetadata(path string) error { err = lchown(path, int(node.UID), int(node.GID)) if err != nil { - return errors.Annotate(err, "Lchown") + return errors.Wrap(err, "Lchown") } if node.Type != "symlink" { err = fs.Chmod(path, node.Mode) if err != nil { - return errors.Annotate(err, "Chmod") + return errors.Wrap(err, "Chmod") } } @@ -183,15 +183,11 @@ func (node Node) RestoreTimestamps(path string) error { } if node.Type == "symlink" { - if err := node.restoreSymlinkTimestamps(path, utimes); err != nil { - return err - } - - return nil + return node.restoreSymlinkTimestamps(path, utimes) } if err := syscall.UtimesNano(path, utimes[:]); err != nil { - return errors.Annotate(err, "UtimesNano") + return errors.Wrap(err, "UtimesNano") } return nil @@ -200,7 +196,7 @@ func (node Node) RestoreTimestamps(path string) error { func (node Node) createDirAt(path string) error { err := fs.Mkdir(path, node.Mode) if err != nil { - return errors.Annotate(err, "Mkdir") + return errors.Wrap(err, "Mkdir") } return nil @@ -211,7 +207,7 @@ func (node Node) createFileAt(path string, repo *repository.Repository) error { defer f.Close() if err != nil { - return errors.Annotate(err, "OpenFile") + return errors.Wrap(err, "OpenFile") } var buf []byte @@ -228,12 +224,12 @@ func (node Node) createFileAt(path string, repo *repository.Repository) error { buf, err := repo.LoadBlob(id, pack.Data, buf) if err != nil { - return errors.Annotate(err, "Load") + return err } _, err = f.Write(buf) if err != nil { - return errors.Annotate(err, "Write") + return errors.Wrap(err, "Write") } } @@ -247,7 +243,7 @@ func (node Node) createSymlinkAt(path string) error { } err := fs.Symlink(node.LinkTarget, path) if err != nil { - return errors.Annotate(err, "Symlink") + return errors.Wrap(err, "Symlink") } return nil @@ -280,11 +276,11 @@ func (node *Node) UnmarshalJSON(data []byte) error { err := json.Unmarshal(data, nj) if err != nil { - return err + return errors.Wrap(err, "Unmarshal") } nj.Name, err = strconv.Unquote(`"` + nj.Name + `"`) - return err + return errors.Wrap(err, "Unquote") } func (node Node) Equals(other Node) bool { @@ -422,7 +418,7 @@ func (node *Node) fillUser(stat statT) error { username, err := lookupUsername(strconv.Itoa(int(stat.uid()))) if err != nil { - return errors.Annotate(err, "fillUser") + return err } node.User = username @@ -470,7 +466,7 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error { var err error if err = node.fillUser(stat); err != nil { - return errors.Annotate(err, "fillExtra") + return err } switch node.Type { @@ -480,6 +476,7 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error { case "dir": case "symlink": node.LinkTarget, err = fs.Readlink(path) + err = errors.Wrap(err, "Readlink") case "dev": node.Device = uint64(stat.rdev()) case "chardev": @@ -487,7 +484,7 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error { case "fifo": case "socket": default: - err = fmt.Errorf("invalid node type %q", node.Type) + err = errors.Errorf("invalid node type %q", node.Type) } return err diff --git a/src/restic/node_linux.go b/src/restic/node_linux.go index a4652d44c..d3d181815 100644 --- a/src/restic/node_linux.go +++ b/src/restic/node_linux.go @@ -5,22 +5,22 @@ import ( "syscall" "unsafe" - "restic/fs" + "github.com/pkg/errors" - "github.com/juju/errors" + "restic/fs" ) func (node Node) restoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error { dir, err := fs.Open(filepath.Dir(path)) defer dir.Close() if err != nil { - return err + return errors.Wrap(err, "Open") } err = utimesNanoAt(int(dir.Fd()), filepath.Base(path), utimes, AT_SYMLINK_NOFOLLOW) if err != nil { - return errors.Annotate(err, "UtimesNanoAt") + return errors.Wrap(err, "UtimesNanoAt") } return nil diff --git a/src/restic/node_windows.go b/src/restic/node_windows.go index c238cf87c..08a7f86a2 100644 --- a/src/restic/node_windows.go +++ b/src/restic/node_windows.go @@ -1,8 +1,9 @@ package restic import ( - "errors" "syscall" + + "github.com/pkg/errors" ) // mknod() creates a filesystem node (file, device diff --git a/src/restic/pack/pack.go b/src/restic/pack/pack.go index 4ffbf4d70..3fb7206a5 100644 --- a/src/restic/pack/pack.go +++ b/src/restic/pack/pack.go @@ -3,11 +3,12 @@ package pack import ( "bytes" "encoding/binary" - "errors" "fmt" "io" "sync" + "github.com/pkg/errors" + "restic/backend" "restic/crypto" ) @@ -106,7 +107,7 @@ func (p *Packer) Add(t BlobType, id backend.ID, data []byte) (int, error) { p.bytes += uint(n) p.blobs = append(p.blobs, c) - return n, err + return n, errors.Wrap(err, "Write") } var entrySize = uint(binary.Size(BlobType(0)) + binary.Size(uint32(0)) + backend.IDSize) @@ -141,7 +142,7 @@ func (p *Packer) Finalize() (uint, error) { // append the header n, err := p.wr.Write(encryptedHeader) if err != nil { - return 0, err + return 0, errors.Wrap(err, "Write") } hdrBytes := bytesHeader + crypto.Extension @@ -154,7 +155,7 @@ func (p *Packer) Finalize() (uint, error) { // write length err = binary.Write(p.wr, binary.LittleEndian, uint32(uint(len(p.blobs))*entrySize+crypto.Extension)) if err != nil { - return 0, err + return 0, errors.Wrap(err, "binary.Write") } bytesWritten += uint(binary.Size(uint32(0))) @@ -181,12 +182,12 @@ func (p *Packer) writeHeader(wr io.Writer) (bytesWritten uint, err error) { case Tree: entry.Type = 1 default: - return 0, fmt.Errorf("invalid blob type %v", b.Type) + return 0, errors.Errorf("invalid blob type %v", b.Type) } err := binary.Write(wr, binary.LittleEndian, entry) if err != nil { - return bytesWritten, err + return bytesWritten, errors.Wrap(err, "binary.Write") } bytesWritten += entrySize @@ -236,7 +237,7 @@ func readHeaderLength(rd io.ReaderAt, size int64) (uint32, error) { buf := make([]byte, binary.Size(uint32(0))) n, err := rd.ReadAt(buf, off) if err != nil { - return 0, err + return 0, errors.Wrap(err, "ReadAt") } if n != len(buf) { @@ -267,7 +268,7 @@ func readHeader(rd io.ReaderAt, size int64) ([]byte, error) { buf := make([]byte, int(hl)) n, err := rd.ReadAt(buf, size-int64(hl)-int64(binary.Size(hl))) if err != nil { - return nil, err + return nil, errors.Wrap(err, "ReadAt") } if n != len(buf) { @@ -295,12 +296,12 @@ func List(k *crypto.Key, rd io.ReaderAt, size int64) (entries []Blob, err error) for { e := headerEntry{} err = binary.Read(hdrRd, binary.LittleEndian, &e) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } if err != nil { - return nil, err + return nil, errors.Wrap(err, "binary.Read") } entry := Blob{ @@ -315,7 +316,7 @@ func List(k *crypto.Key, rd io.ReaderAt, size int64) (entries []Blob, err error) case 1: entry.Type = Tree default: - return nil, fmt.Errorf("invalid type %d", e.Type) + return nil, errors.Errorf("invalid type %d", e.Type) } entries = append(entries, entry) diff --git a/src/restic/pipe/pipe.go b/src/restic/pipe/pipe.go index 92343f545..48a83a362 100644 --- a/src/restic/pipe/pipe.go +++ b/src/restic/pipe/pipe.go @@ -1,12 +1,13 @@ package pipe import ( - "errors" "fmt" "os" "path/filepath" "sort" + "github.com/pkg/errors" + "restic/debug" "restic/fs" ) @@ -62,12 +63,12 @@ func (e Dir) Result() chan<- Result { return e.result } func readDirNames(dirname string) ([]string, error) { f, err := fs.Open(dirname) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Open") } names, err := f.Readdirnames(-1) f.Close() if err != nil { - return nil, err + return nil, errors.Wrap(err, "Readdirnames") } sort.Strings(names) return names, nil @@ -93,6 +94,7 @@ func walk(basedir, dir string, selectFunc SelectFunc, done <-chan struct{}, jobs info, err := fs.Lstat(dir) if err != nil { + err = errors.Wrap(err, "Lstat") debug.Log("pipe.walk", "error for %v: %v, res %p", dir, err, res) select { case jobs <- Dir{basedir: basedir, path: relpath, info: info, error: err, result: res}: @@ -146,6 +148,7 @@ func walk(basedir, dir string, selectFunc SelectFunc, done <-chan struct{}, jobs entries = append(entries, ch) if statErr != nil { + statErr = errors.Wrap(statErr, "Lstat") debug.Log("pipe.walk", "sending file job for %v, err %v, res %p", subpath, err, res) select { case jobs <- Entry{info: fi, error: statErr, basedir: basedir, path: filepath.Join(relpath, name), result: ch}: diff --git a/src/restic/progress.go b/src/restic/progress.go index 2250cd689..49d9420d3 100644 --- a/src/restic/progress.go +++ b/src/restic/progress.go @@ -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 diff --git a/src/restic/repository/config.go b/src/restic/repository/config.go index 46f739d35..c9e4eac85 100644 --- a/src/restic/repository/config.go +++ b/src/restic/repository/config.go @@ -4,10 +4,11 @@ import ( "crypto/rand" "crypto/sha256" "encoding/hex" - "errors" "io" "testing" + "github.com/pkg/errors" + "restic/backend" "restic/debug" @@ -48,13 +49,13 @@ func CreateConfig() (Config, error) { cfg.ChunkerPolynomial, err = chunker.RandomPolynomial() if err != nil { - return Config{}, err + return Config{}, errors.Wrap(err, "chunker.RandomPolynomial") } newID := make([]byte, repositoryIDSize) _, err = io.ReadFull(rand.Reader, newID) if err != nil { - return Config{}, err + return Config{}, errors.Wrap(err, "io.ReadFull") } cfg.ID = hex.EncodeToString(newID) diff --git a/src/restic/repository/index.go b/src/restic/repository/index.go index 86968ba1d..f49a1735f 100644 --- a/src/restic/repository/index.go +++ b/src/restic/repository/index.go @@ -3,12 +3,13 @@ package repository import ( "bytes" "encoding/json" - "errors" "fmt" "io" "sync" "time" + "github.com/pkg/errors" + "restic/backend" "restic/crypto" "restic/debug" @@ -139,7 +140,7 @@ func (idx *Index) Lookup(id backend.ID, tpe pack.BlobType) (blobs []PackedBlob, } debug.Log("Index.Lookup", "id %v not found", id.Str()) - return nil, fmt.Errorf("id %v not found in index", id) + return nil, errors.Errorf("id %v not found in index", id) } // ListPack returns a list of blobs contained in a pack. @@ -326,7 +327,7 @@ func (idx *Index) generatePackList() ([]*packJSON, error) { if blob.packID.IsNull() { debug.Log("Index.generatePackList", "blob %v has no packID! (offset %v, length %v)", h, blob.offset, blob.length) - return nil, fmt.Errorf("unable to serialize index: pack for blob %v hasn't been written yet", h) + return nil, errors.Errorf("unable to serialize index: pack for blob %v hasn't been written yet", h) } // see if pack is already in map @@ -455,7 +456,7 @@ func (idx *Index) Dump(w io.Writer) error { _, err = w.Write(append(buf, '\n')) if err != nil { - return err + return errors.Wrap(err, "Write") } debug.Log("Index.Dump", "done") @@ -491,7 +492,7 @@ func DecodeIndex(rd io.Reader) (idx *Index, err error) { err = ErrOldIndexFormat } - return nil, err + return nil, errors.Wrap(err, "Decode") } idx = NewIndex() @@ -510,7 +511,7 @@ func DecodeIndex(rd io.Reader) (idx *Index, err error) { idx.final = true debug.Log("Index.DecodeIndex", "done") - return idx, err + return idx, nil } // DecodeOldIndex loads and unserializes an index in the old format from rd. @@ -522,7 +523,7 @@ func DecodeOldIndex(rd io.Reader) (idx *Index, err error) { err = dec.Decode(&list) if err != nil { debug.Log("Index.DecodeOldIndex", "Error %#v", err) - return nil, err + return nil, errors.Wrap(err, "Decode") } idx = NewIndex() @@ -540,7 +541,7 @@ func DecodeOldIndex(rd io.Reader) (idx *Index, err error) { idx.final = true debug.Log("Index.DecodeOldIndex", "done") - return idx, err + return idx, nil } // LoadIndexWithDecoder loads the index and decodes it with fn. diff --git a/src/restic/repository/key.go b/src/restic/repository/key.go index 2599f6e2e..2f2e79758 100644 --- a/src/restic/repository/key.go +++ b/src/restic/repository/key.go @@ -2,12 +2,13 @@ package repository import ( "encoding/json" - "errors" "fmt" "os" "os/user" "time" + "github.com/pkg/errors" + "restic/backend" "restic/crypto" "restic/debug" @@ -79,7 +80,7 @@ func OpenKey(s *Repository, name string, password string) (*Key, error) { } k.user, err = crypto.KDF(params, k.Salt, password) if err != nil { - return nil, err + return nil, errors.Wrap(err, "crypto.KDF") } // decrypt master keys @@ -93,7 +94,7 @@ func OpenKey(s *Repository, name string, password string) (*Key, error) { err = json.Unmarshal(buf, k.master) if err != nil { debug.Log("OpenKey", "Unmarshal() returned error %v", err) - return nil, err + return nil, errors.Wrap(err, "Unmarshal") } k.name = name @@ -125,7 +126,7 @@ func SearchKey(s *Repository, password string, maxKeys int) (*Key, error) { debug.Log("SearchKey", "key %v returned error %v", name[:12], err) // ErrUnauthenticated means the password is wrong, try the next key - if err == crypto.ErrUnauthenticated { + if errors.Cause(err) == crypto.ErrUnauthenticated { continue } @@ -150,7 +151,7 @@ func LoadKey(s *Repository, name string) (k *Key, err error) { k = &Key{} err = json.Unmarshal(data, k) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Unmarshal") } return k, nil @@ -162,7 +163,7 @@ func AddKey(s *Repository, password string, template *crypto.Key) (*Key, error) if KDFParams == nil { p, err := crypto.Calibrate(KDFTimeout, KDFMemory) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Calibrate") } KDFParams = &p @@ -211,7 +212,7 @@ func AddKey(s *Repository, password string, template *crypto.Key) (*Key, error) // encrypt master keys (as json) with user key buf, err := json.Marshal(newkey.master) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Marshal") } newkey.Data, err = crypto.Encrypt(newkey.user, nil, buf) @@ -219,7 +220,7 @@ func AddKey(s *Repository, password string, template *crypto.Key) (*Key, error) // dump as json buf, err = json.Marshal(newkey) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Marshal") } // store in repository and return diff --git a/src/restic/repository/master_index.go b/src/restic/repository/master_index.go index c6114d055..96425f9e8 100644 --- a/src/restic/repository/master_index.go +++ b/src/restic/repository/master_index.go @@ -1,9 +1,10 @@ package repository import ( - "fmt" "sync" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/pack" @@ -37,7 +38,7 @@ func (mi *MasterIndex) Lookup(id backend.ID, tpe pack.BlobType) (blobs []PackedB } debug.Log("MasterIndex.Lookup", "id %v not found in any index", id.Str()) - return nil, fmt.Errorf("id %v not found in any index", id) + return nil, errors.Errorf("id %v not found in any index", id) } // LookupSize queries all known Indexes for the ID and returns the first match. @@ -52,7 +53,7 @@ func (mi *MasterIndex) LookupSize(id backend.ID, tpe pack.BlobType) (uint, error } } - return 0, fmt.Errorf("id %v not found in any index", id) + return 0, errors.Errorf("id %v not found in any index", id) } // ListPack returns the list of blobs in a pack. The first matching index is diff --git a/src/restic/repository/packer_manager.go b/src/restic/repository/packer_manager.go index cbf27e626..32c8a73d4 100644 --- a/src/restic/repository/packer_manager.go +++ b/src/restic/repository/packer_manager.go @@ -1,12 +1,13 @@ package repository import ( - "fmt" "io" "io/ioutil" "os" "sync" + "github.com/pkg/errors" + "restic/backend" "restic/crypto" "restic/debug" @@ -70,7 +71,7 @@ func (r *packerManager) findPacker(size uint) (packer *pack.Packer, err error) { debug.Log("Repo.findPacker", "create new pack for %d bytes", size) tmpfile, err := ioutil.TempFile("", "restic-temp-pack-") if err != nil { - return nil, err + return nil, errors.Wrap(err, "ioutil.TempFile") } return pack.NewPacker(r.key, tmpfile), nil @@ -96,18 +97,21 @@ func (r *Repository) savePacker(p *pack.Packer) error { tmpfile := p.Writer().(*os.File) f, err := fs.Open(tmpfile.Name()) if err != nil { - return err + return errors.Wrap(err, "Open") } data := make([]byte, n) m, err := io.ReadFull(f, data) + if err != nil { + return errors.Wrap(err, "ReadFul") + } if uint(m) != n { - return fmt.Errorf("read wrong number of bytes from %v: want %v, got %v", tmpfile.Name(), n, m) + return errors.Errorf("read wrong number of bytes from %v: want %v, got %v", tmpfile.Name(), n, m) } if err = f.Close(); err != nil { - return err + return errors.Wrap(err, "Close") } id := backend.Hash(data) @@ -123,7 +127,7 @@ func (r *Repository) savePacker(p *pack.Packer) error { err = fs.Remove(tmpfile.Name()) if err != nil { - return err + return errors.Wrap(err, "Remove") } // update blobs in the index diff --git a/src/restic/repository/parallel_test.go b/src/restic/repository/parallel_test.go index dfcce0a15..6aab24b0e 100644 --- a/src/restic/repository/parallel_test.go +++ b/src/restic/repository/parallel_test.go @@ -1,11 +1,12 @@ package repository_test import ( - "errors" "math/rand" "testing" "time" + "github.com/pkg/errors" + "restic/backend" "restic/repository" . "restic/test" diff --git a/src/restic/repository/rand_reader.go b/src/restic/repository/rand_reader.go index 201826a94..2afbd60b7 100644 --- a/src/restic/repository/rand_reader.go +++ b/src/restic/repository/rand_reader.go @@ -3,6 +3,8 @@ package repository import ( "io" "math/rand" + + "github.com/pkg/errors" ) // RandReader allows reading from a rand.Rand. @@ -56,7 +58,7 @@ func (rd *RandReader) Read(p []byte) (int, error) { n, err := rd.read(p[:l]) pos += n if err != nil { - return pos, err + return pos, errors.Wrap(err, "Read") } p = p[n:] @@ -64,7 +66,7 @@ func (rd *RandReader) Read(p []byte) (int, error) { rd.buf = rd.buf[:7] n, err = rd.read(rd.buf) if err != nil { - return pos, err + return pos, errors.Wrap(err, "Read") } // copy the remaining bytes from the buffer to p diff --git a/src/restic/repository/repack.go b/src/restic/repository/repack.go index bf8d7a3a7..2c61705da 100644 --- a/src/restic/repository/repack.go +++ b/src/restic/repository/repack.go @@ -7,6 +7,8 @@ import ( "restic/crypto" "restic/debug" "restic/pack" + + "github.com/pkg/errors" ) // Repack takes a list of packs together with a list of blobs contained in @@ -22,7 +24,7 @@ func Repack(repo *Repository, packs backend.IDSet, keepBlobs pack.BlobSet) (err h := backend.Handle{Type: backend.Data, Name: packID.String()} l, err := repo.Backend().Load(h, buf[:cap(buf)], 0) - if err == io.ErrUnexpectedEOF { + if errors.Cause(err) == io.ErrUnexpectedEOF { err = nil buf = buf[:l] } diff --git a/src/restic/repository/repository.go b/src/restic/repository/repository.go index 8949b813f..d2a5a0fa9 100644 --- a/src/restic/repository/repository.go +++ b/src/restic/repository/repository.go @@ -3,11 +3,12 @@ package repository import ( "bytes" "encoding/json" - "errors" "fmt" "io" "os" + "github.com/pkg/errors" + "restic/backend" "restic/crypto" "restic/debug" @@ -101,6 +102,7 @@ func (r *Repository) LoadBlob(id backend.ID, t pack.BlobType, plaintextBuf []byt return nil, err } + var lastError error for _, blob := range blobs { debug.Log("Repo.LoadBlob", "id %v found: %v", id.Str(), blob) @@ -114,33 +116,38 @@ func (r *Repository) LoadBlob(id backend.ID, t pack.BlobType, plaintextBuf []byt n, err := r.be.Load(h, ciphertextBuf, int64(blob.Offset)) if err != nil { debug.Log("Repo.LoadBlob", "error loading blob %v: %v", blob, err) - fmt.Fprintf(os.Stderr, "error loading blob %v: %v", id, err) + lastError = err continue } if uint(n) != blob.Length { - debug.Log("Repo.LoadBlob", "error loading blob %v: wrong length returned, want %d, got %d", - blob.Length, uint(n)) + lastError = errors.Errorf("error loading blob %v: wrong length returned, want %d, got %d", + id.Str(), blob.Length, uint(n)) + debug.Log("Repo.LoadBlob", "lastError: %v", lastError) continue } // decrypt plaintextBuf, err = r.decryptTo(plaintextBuf, ciphertextBuf) if err != nil { - fmt.Fprintf(os.Stderr, "decrypting blob %v failed: %v", id, err) + lastError = errors.Errorf("decrypting blob %v failed: %v", id, err) continue } // check hash if !backend.Hash(plaintextBuf).Equal(id) { - fmt.Fprintf(os.Stderr, "blob %v returned invalid hash", id) + lastError = errors.Errorf("blob %v returned invalid hash", id) continue } return plaintextBuf, nil } - return nil, fmt.Errorf("loading blob %v from %v packs failed", id.Str(), len(blobs)) + if lastError != nil { + return nil, lastError + } + + return nil, errors.Errorf("loading blob %v from %v packs failed", id.Str(), len(blobs)) } // closeOrErr calls cl.Close() and sets err to the returned error value if @@ -237,7 +244,7 @@ func (r *Repository) SaveJSON(t pack.BlobType, item interface{}) (backend.ID, er enc := json.NewEncoder(wr) err := enc.Encode(item) if err != nil { - return backend.ID{}, fmt.Errorf("json.Encode: %v", err) + return backend.ID{}, errors.Errorf("json.Encode: %v", err) } buf = wr.Bytes() @@ -250,7 +257,7 @@ func (r *Repository) SaveJSONUnpacked(t backend.Type, item interface{}) (backend debug.Log("Repo.SaveJSONUnpacked", "save new blob %v", t) plaintext, err := json.Marshal(item) if err != nil { - return backend.ID{}, fmt.Errorf("json.Encode: %v", err) + return backend.ID{}, errors.Wrap(err, "json.Marshal") } return r.SaveUnpacked(t, plaintext) @@ -396,7 +403,7 @@ func LoadIndex(repo *Repository, id backend.ID) (*Index, error) { return idx, nil } - if err == ErrOldIndexFormat { + if errors.Cause(err) == ErrOldIndexFormat { fmt.Fprintf(os.Stderr, "index %v has old format\n", id.Str()) return LoadIndexWithDecoder(repo, id, DecodeOldIndex) } diff --git a/src/restic/restorer.go b/src/restic/restorer.go index cb2f888cc..74cdfc34d 100644 --- a/src/restic/restorer.go +++ b/src/restic/restorer.go @@ -1,16 +1,15 @@ package restic import ( - "fmt" "os" "path/filepath" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/fs" "restic/repository" - - "github.com/juju/errors" ) // Restorer is used to restore a snapshot to a directory. @@ -35,7 +34,7 @@ func NewRestorer(repo *repository.Repository, id backend.ID) (*Restorer, error) r.sn, err = LoadSnapshot(repo, id) if err != nil { - return nil, errors.Annotate(err, "load snapshot for restorer") + return nil, err } return r, nil @@ -44,7 +43,7 @@ func NewRestorer(repo *repository.Repository, id backend.ID) (*Restorer, error) func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error { tree, err := LoadTree(res.repo, treeID) if err != nil { - return res.Error(dir, nil, errors.Annotate(err, "LoadTree")) + return res.Error(dir, nil, err) } for _, node := range tree.Nodes { @@ -61,13 +60,13 @@ func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error if node.Type == "dir" { if node.Subtree == nil { - return fmt.Errorf("Dir without subtree in tree %v", treeID.Str()) + return errors.Errorf("Dir without subtree in tree %v", treeID.Str()) } subp := filepath.Join(dir, node.Name) err = res.restoreTo(dst, subp, *node.Subtree) if err != nil { - err = res.Error(subp, node, errors.Annotate(err, "restore subtree")) + err = res.Error(subp, node, err) if err != nil { return err } @@ -101,14 +100,14 @@ func (res *Restorer) restoreNodeTo(node *Node, dir string, dst string) error { // Create parent directories and retry err = fs.MkdirAll(filepath.Dir(dstPath), 0700) - if err == nil || err == os.ErrExist { + if err == nil || os.IsExist(errors.Cause(err)) { err = node.CreateAt(dstPath, res.repo) } } if err != nil { debug.Log("Restorer.restoreNodeTo", "error %v", err) - err = res.Error(dstPath, node, errors.Annotate(err, "create node")) + err = res.Error(dstPath, node, err) if err != nil { return err } diff --git a/src/restic/snapshot.go b/src/restic/snapshot.go index 3eaa0b61f..2ce01b4d9 100644 --- a/src/restic/snapshot.go +++ b/src/restic/snapshot.go @@ -1,13 +1,14 @@ package restic import ( - "errors" "fmt" "os" "os/user" "path/filepath" "time" + "github.com/pkg/errors" + "restic/backend" "restic/repository" ) @@ -140,7 +141,7 @@ func FindLatestSnapshot(repo *repository.Repository, targets []string, source st for snapshotID := range repo.List(backend.Snapshot, make(chan struct{})) { snapshot, err := LoadSnapshot(repo, snapshotID) if err != nil { - return backend.ID{}, fmt.Errorf("Error listing snapshot: %v", err) + return backend.ID{}, errors.Errorf("Error listing snapshot: %v", err) } if snapshot.Time.After(latest) && SamePaths(snapshot.Paths, targets) && (source == "" || source == snapshot.Hostname) { latest = snapshot.Time diff --git a/src/restic/testing.go b/src/restic/testing.go index e1d6bf610..78783ee44 100644 --- a/src/restic/testing.go +++ b/src/restic/testing.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/pkg/errors" "github.com/restic/chunker" ) @@ -34,7 +35,7 @@ func (fs fakeFileSystem) saveFile(rd io.Reader) (blobs backend.IDs) { for { chunk, err := ch.Next(getBuf()) - if err == io.EOF { + if errors.Cause(err) == io.EOF { break } diff --git a/src/restic/tree.go b/src/restic/tree.go index 067dc6b7e..9bfcfd7ee 100644 --- a/src/restic/tree.go +++ b/src/restic/tree.go @@ -1,10 +1,11 @@ package restic import ( - "errors" "fmt" "sort" + "github.com/pkg/errors" + "restic/backend" "restic/debug" "restic/pack" diff --git a/src/restic/worker/pool_test.go b/src/restic/worker/pool_test.go index f70664419..329ce9a88 100644 --- a/src/restic/worker/pool_test.go +++ b/src/restic/worker/pool_test.go @@ -1,9 +1,10 @@ package worker_test import ( - "errors" "testing" + "github.com/pkg/errors" + "restic/worker" ) diff --git a/vendor/manifest b/vendor/manifest index b0953efaa..8cc1d2e4d 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -19,12 +19,6 @@ "revision": "1b89bf73cd2c3a911d7b2a279ab085c4a18cf539", "branch": "HEAD" }, - { - "importpath": "github.com/juju/errors", - "repository": "https://github.com/juju/errors", - "revision": "4567a5e69fd3130ca0d89f69478e7ac025b67452", - "branch": "HEAD" - }, { "importpath": "github.com/kr/fs", "repository": "https://github.com/kr/fs", diff --git a/vendor/src/github.com/juju/errors/LICENSE b/vendor/src/github.com/juju/errors/LICENSE deleted file mode 100644 index ade9307b3..000000000 --- a/vendor/src/github.com/juju/errors/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -All files in this repository are licensed as follows. If you contribute -to this repository, it is assumed that you license your contribution -under the same license unless you state otherwise. - -All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file. - -This software is licensed under the LGPLv3, included below. - -As a special exception to the GNU Lesser General Public License version 3 -("LGPL3"), the copyright holders of this Library give you permission to -convey to a third party a Combined Work that links statically or dynamically -to this Library without providing any Minimal Corresponding Source or -Minimal Application Code as set out in 4d or providing the installation -information set out in section 4e, provided that you comply with the other -provisions of LGPL3 and provided that you meet, for the Application the -terms and conditions of the license(s) which apply to the Application. - -Except as stated in this special exception, the provisions of LGPL3 will -continue to comply in full to this Library. If you modify this Library, you -may apply this exception to your version of this Library, but you are not -obliged to do so. If you do not wish to do so, delete this exception -statement from your version. This exception does not (and cannot) modify any -license terms which apply to the Application, with which you must still -comply. - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/vendor/src/github.com/juju/errors/Makefile b/vendor/src/github.com/juju/errors/Makefile deleted file mode 100644 index ab7c2e6cf..000000000 --- a/vendor/src/github.com/juju/errors/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -default: check - -check: - go test && go test -compiler gccgo - -docs: - godoc2md github.com/juju/errors > README.md - sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)|' README.md - - -.PHONY: default check docs diff --git a/vendor/src/github.com/juju/errors/README.md b/vendor/src/github.com/juju/errors/README.md deleted file mode 100644 index ee248911f..000000000 --- a/vendor/src/github.com/juju/errors/README.md +++ /dev/null @@ -1,536 +0,0 @@ - -# errors - import "github.com/juju/errors" - -[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors) - -The juju/errors provides an easy way to annotate errors without losing the -orginal error context. - -The exported `New` and `Errorf` functions are designed to replace the -`errors.New` and `fmt.Errorf` functions respectively. The same underlying -error is there, but the package also records the location at which the error -was created. - -A primary use case for this library is to add extra context any time an -error is returned from a function. - - - if err := SomeFunc(); err != nil { - return err - } - -This instead becomes: - - - if err := SomeFunc(); err != nil { - return errors.Trace(err) - } - -which just records the file and line number of the Trace call, or - - - if err := SomeFunc(); err != nil { - return errors.Annotate(err, "more context") - } - -which also adds an annotation to the error. - -When you want to check to see if an error is of a particular type, a helper -function is normally exported by the package that returned the error, like the -`os` package does. The underlying cause of the error is available using the -`Cause` function. - - - os.IsNotExist(errors.Cause(err)) - -The result of the `Error()` call on an annotated error is the annotations joined -with colons, then the result of the `Error()` method for the underlying error -that was the cause. - - - err := errors.Errorf("original") - err = errors.Annotatef(err, "context") - err = errors.Annotatef(err, "more context") - err.Error() -> "more context: context: original" - -Obviously recording the file, line and functions is not very useful if you -cannot get them back out again. - - - errors.ErrorStack(err) - -will return something like: - - - first error - github.com/juju/errors/annotation_test.go:193: - github.com/juju/errors/annotation_test.go:194: annotation - github.com/juju/errors/annotation_test.go:195: - github.com/juju/errors/annotation_test.go:196: more context - github.com/juju/errors/annotation_test.go:197: - -The first error was generated by an external system, so there was no location -associated. The second, fourth, and last lines were generated with Trace calls, -and the other two through Annotate. - -Sometimes when responding to an error you want to return a more specific error -for the situation. - - - if err := FindField(field); err != nil { - return errors.Wrap(err, errors.NotFoundf(field)) - } - -This returns an error where the complete error stack is still available, and -`errors.Cause()` will return the `NotFound` error. - - - - - - -## func AlreadyExistsf -``` go -func AlreadyExistsf(format string, args ...interface{}) error -``` -AlreadyExistsf returns an error which satisfies IsAlreadyExists(). - - -## func Annotate -``` go -func Annotate(other error, message string) error -``` -Annotate is used to add extra context to an existing error. The location of -the Annotate call is recorded with the annotations. The file, line and -function are also recorded. - -For example: - - - if err := SomeFunc(); err != nil { - return errors.Annotate(err, "failed to frombulate") - } - - -## func Annotatef -``` go -func Annotatef(other error, format string, args ...interface{}) error -``` -Annotatef is used to add extra context to an existing error. The location of -the Annotate call is recorded with the annotations. The file, line and -function are also recorded. - -For example: - - - if err := SomeFunc(); err != nil { - return errors.Annotatef(err, "failed to frombulate the %s", arg) - } - - -## func Cause -``` go -func Cause(err error) error -``` -Cause returns the cause of the given error. This will be either the -original error, or the result of a Wrap or Mask call. - -Cause is the usual way to diagnose errors that may have been wrapped by -the other errors functions. - - -## func DeferredAnnotatef -``` go -func DeferredAnnotatef(err *error, format string, args ...interface{}) -``` -DeferredAnnotatef annotates the given error (when it is not nil) with the given -format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef -does nothing. This method is used in a defer statement in order to annotate any -resulting error with the same message. - -For example: - - - defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg) - - -## func Details -``` go -func Details(err error) string -``` -Details returns information about the stack of errors wrapped by err, in -the format: - - - [{filename:99: error one} {otherfile:55: cause of error one}] - -This is a terse alternative to ErrorStack as it returns a single line. - - -## func ErrorStack -``` go -func ErrorStack(err error) string -``` -ErrorStack returns a string representation of the annotated error. If the -error passed as the parameter is not an annotated error, the result is -simply the result of the Error() method on that error. - -If the error is an annotated error, a multi-line string is returned where -each line represents one entry in the annotation stack. The full filename -from the call stack is used in the output. - - - first error - github.com/juju/errors/annotation_test.go:193: - github.com/juju/errors/annotation_test.go:194: annotation - github.com/juju/errors/annotation_test.go:195: - github.com/juju/errors/annotation_test.go:196: more context - github.com/juju/errors/annotation_test.go:197: - - -## func Errorf -``` go -func Errorf(format string, args ...interface{}) error -``` -Errorf creates a new annotated error and records the location that the -error is created. This should be a drop in replacement for fmt.Errorf. - -For example: - - - return errors.Errorf("validation failed: %s", message) - - -## func IsAlreadyExists -``` go -func IsAlreadyExists(err error) bool -``` -IsAlreadyExists reports whether the error was created with -AlreadyExistsf() or NewAlreadyExists(). - - -## func IsNotFound -``` go -func IsNotFound(err error) bool -``` -IsNotFound reports whether err was created with NotFoundf() or -NewNotFound(). - - -## func IsNotImplemented -``` go -func IsNotImplemented(err error) bool -``` -IsNotImplemented reports whether err was created with -NotImplementedf() or NewNotImplemented(). - - -## func IsNotSupported -``` go -func IsNotSupported(err error) bool -``` -IsNotSupported reports whether the error was created with -NotSupportedf() or NewNotSupported(). - - -## func IsNotValid -``` go -func IsNotValid(err error) bool -``` -IsNotValid reports whether the error was created with NotValidf() or -NewNotValid(). - - -## func IsUnauthorized -``` go -func IsUnauthorized(err error) bool -``` -IsUnauthorized reports whether err was created with Unauthorizedf() or -NewUnauthorized(). - - -## func Mask -``` go -func Mask(other error) error -``` -Mask hides the underlying error type, and records the location of the masking. - - -## func Maskf -``` go -func Maskf(other error, format string, args ...interface{}) error -``` -Mask masks the given error with the given format string and arguments (like -fmt.Sprintf), returning a new error that maintains the error stack, but -hides the underlying error type. The error string still contains the full -annotations. If you want to hide the annotations, call Wrap. - - -## func New -``` go -func New(message string) error -``` -New is a drop in replacement for the standard libary errors module that records -the location that the error is created. - -For example: - - - return errors.New("validation failed") - - -## func NewAlreadyExists -``` go -func NewAlreadyExists(err error, msg string) error -``` -NewAlreadyExists returns an error which wraps err and satisfies -IsAlreadyExists(). - - -## func NewNotFound -``` go -func NewNotFound(err error, msg string) error -``` -NewNotFound returns an error which wraps err that satisfies -IsNotFound(). - - -## func NewNotImplemented -``` go -func NewNotImplemented(err error, msg string) error -``` -NewNotImplemented returns an error which wraps err and satisfies -IsNotImplemented(). - - -## func NewNotSupported -``` go -func NewNotSupported(err error, msg string) error -``` -NewNotSupported returns an error which wraps err and satisfies -IsNotSupported(). - - -## func NewNotValid -``` go -func NewNotValid(err error, msg string) error -``` -NewNotValid returns an error which wraps err and satisfies IsNotValid(). - - -## func NewUnauthorized -``` go -func NewUnauthorized(err error, msg string) error -``` -NewUnauthorized returns an error which wraps err and satisfies -IsUnauthorized(). - - -## func NotFoundf -``` go -func NotFoundf(format string, args ...interface{}) error -``` -NotFoundf returns an error which satisfies IsNotFound(). - - -## func NotImplementedf -``` go -func NotImplementedf(format string, args ...interface{}) error -``` -NotImplementedf returns an error which satisfies IsNotImplemented(). - - -## func NotSupportedf -``` go -func NotSupportedf(format string, args ...interface{}) error -``` -NotSupportedf returns an error which satisfies IsNotSupported(). - - -## func NotValidf -``` go -func NotValidf(format string, args ...interface{}) error -``` -NotValidf returns an error which satisfies IsNotValid(). - - -## func Trace -``` go -func Trace(other error) error -``` -Trace adds the location of the Trace call to the stack. The Cause of the -resulting error is the same as the error parameter. If the other error is -nil, the result will be nil. - -For example: - - - if err := SomeFunc(); err != nil { - return errors.Trace(err) - } - - -## func Unauthorizedf -``` go -func Unauthorizedf(format string, args ...interface{}) error -``` -Unauthorizedf returns an error which satisfies IsUnauthorized(). - - -## func Wrap -``` go -func Wrap(other, newDescriptive error) error -``` -Wrap changes the Cause of the error. The location of the Wrap call is also -stored in the error stack. - -For example: - - - if err := SomeFunc(); err != nil { - newErr := &packageError{"more context", private_value} - return errors.Wrap(err, newErr) - } - - -## func Wrapf -``` go -func Wrapf(other, newDescriptive error, format string, args ...interface{}) error -``` -Wrapf changes the Cause of the error, and adds an annotation. The location -of the Wrap call is also stored in the error stack. - -For example: - - - if err := SomeFunc(); err != nil { - return errors.Wrapf(err, simpleErrorType, "invalid value %q", value) - } - - - -## type Err -``` go -type Err struct { - // contains filtered or unexported fields -} -``` -Err holds a description of an error along with information about -where the error was created. - -It may be embedded in custom error types to add extra information that -this errors package can understand. - - - - - - - - - -### func NewErr -``` go -func NewErr(format string, args ...interface{}) Err -``` -NewErr is used to return an Err for the purpose of embedding in other -structures. The location is not specified, and needs to be set with a call -to SetLocation. - -For example: - - - type FooError struct { - errors.Err - code int - } - - func NewFooError(code int) error { - err := &FooError{errors.NewErr("foo"), code} - err.SetLocation(1) - return err - } - - - - -### func (\*Err) Cause -``` go -func (e *Err) Cause() error -``` -The Cause of an error is the most recent error in the error stack that -meets one of these criteria: the original error that was raised; the new -error that was passed into the Wrap function; the most recently masked -error; or nil if the error itself is considered the Cause. Normally this -method is not invoked directly, but instead through the Cause stand alone -function. - - - -### func (\*Err) Error -``` go -func (e *Err) Error() string -``` -Error implements error.Error. - - - -### func (\*Err) Location -``` go -func (e *Err) Location() (filename string, line int) -``` -Location is the file and line of where the error was most recently -created or annotated. - - - -### func (\*Err) Message -``` go -func (e *Err) Message() string -``` -Message returns the message stored with the most recent location. This is -the empty string if the most recent call was Trace, or the message stored -with Annotate or Mask. - - - -### func (\*Err) SetLocation -``` go -func (e *Err) SetLocation(callDepth int) -``` -SetLocation records the source location of the error at callDepth stack -frames above the call. - - - -### func (\*Err) StackTrace -``` go -func (e *Err) StackTrace() []string -``` -StackTrace returns one string for each location recorded in the stack of -errors. The first value is the originating error, with a line for each -other annotation or tracing of the error. - - - -### func (\*Err) Underlying -``` go -func (e *Err) Underlying() error -``` -Underlying returns the previous error in the error stack, if any. A client -should not ever really call this method. It is used to build the error -stack and should not be introspected by client calls. Or more -specifically, clients should not depend on anything but the `Cause` of an -error. - - - - - - - - - -- - - -Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) \ No newline at end of file diff --git a/vendor/src/github.com/juju/errors/doc.go b/vendor/src/github.com/juju/errors/doc.go deleted file mode 100644 index 35b119aa3..000000000 --- a/vendor/src/github.com/juju/errors/doc.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -/* -[godoc-link-here] - -The juju/errors provides an easy way to annotate errors without losing the -orginal error context. - -The exported `New` and `Errorf` functions are designed to replace the -`errors.New` and `fmt.Errorf` functions respectively. The same underlying -error is there, but the package also records the location at which the error -was created. - -A primary use case for this library is to add extra context any time an -error is returned from a function. - - if err := SomeFunc(); err != nil { - return err - } - -This instead becomes: - - if err := SomeFunc(); err != nil { - return errors.Trace(err) - } - -which just records the file and line number of the Trace call, or - - if err := SomeFunc(); err != nil { - return errors.Annotate(err, "more context") - } - -which also adds an annotation to the error. - -When you want to check to see if an error is of a particular type, a helper -function is normally exported by the package that returned the error, like the -`os` package does. The underlying cause of the error is available using the -`Cause` function. - - os.IsNotExist(errors.Cause(err)) - -The result of the `Error()` call on an annotated error is the annotations joined -with colons, then the result of the `Error()` method for the underlying error -that was the cause. - - err := errors.Errorf("original") - err = errors.Annotatef(err, "context") - err = errors.Annotatef(err, "more context") - err.Error() -> "more context: context: original" - -Obviously recording the file, line and functions is not very useful if you -cannot get them back out again. - - errors.ErrorStack(err) - -will return something like: - - first error - github.com/juju/errors/annotation_test.go:193: - github.com/juju/errors/annotation_test.go:194: annotation - github.com/juju/errors/annotation_test.go:195: - github.com/juju/errors/annotation_test.go:196: more context - github.com/juju/errors/annotation_test.go:197: - -The first error was generated by an external system, so there was no location -associated. The second, fourth, and last lines were generated with Trace calls, -and the other two through Annotate. - -Sometimes when responding to an error you want to return a more specific error -for the situation. - - if err := FindField(field); err != nil { - return errors.Wrap(err, errors.NotFoundf(field)) - } - -This returns an error where the complete error stack is still available, and -`errors.Cause()` will return the `NotFound` error. - -*/ -package errors diff --git a/vendor/src/github.com/juju/errors/error.go b/vendor/src/github.com/juju/errors/error.go deleted file mode 100644 index 4799acb02..000000000 --- a/vendor/src/github.com/juju/errors/error.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors - -import ( - "fmt" - "reflect" - "runtime" -) - -// Err holds a description of an error along with information about -// where the error was created. -// -// It may be embedded in custom error types to add extra information that -// this errors package can understand. -type Err struct { - // message holds an annotation of the error. - message string - - // cause holds the cause of the error as returned - // by the Cause method. - cause error - - // previous holds the previous error in the error stack, if any. - previous error - - // file and line hold the source code location where the error was - // created. - file string - line int -} - -// NewErr is used to return an Err for the purpose of embedding in other -// structures. The location is not specified, and needs to be set with a call -// to SetLocation. -// -// For example: -// type FooError struct { -// errors.Err -// code int -// } -// -// func NewFooError(code int) error { -// err := &FooError{errors.NewErr("foo"), code} -// err.SetLocation(1) -// return err -// } -func NewErr(format string, args ...interface{}) Err { - return Err{ - message: fmt.Sprintf(format, args...), - } -} - -// Location is the file and line of where the error was most recently -// created or annotated. -func (e *Err) Location() (filename string, line int) { - return e.file, e.line -} - -// Underlying returns the previous error in the error stack, if any. A client -// should not ever really call this method. It is used to build the error -// stack and should not be introspected by client calls. Or more -// specifically, clients should not depend on anything but the `Cause` of an -// error. -func (e *Err) Underlying() error { - return e.previous -} - -// The Cause of an error is the most recent error in the error stack that -// meets one of these criteria: the original error that was raised; the new -// error that was passed into the Wrap function; the most recently masked -// error; or nil if the error itself is considered the Cause. Normally this -// method is not invoked directly, but instead through the Cause stand alone -// function. -func (e *Err) Cause() error { - return e.cause -} - -// Message returns the message stored with the most recent location. This is -// the empty string if the most recent call was Trace, or the message stored -// with Annotate or Mask. -func (e *Err) Message() string { - return e.message -} - -// Error implements error.Error. -func (e *Err) Error() string { - // We want to walk up the stack of errors showing the annotations - // as long as the cause is the same. - err := e.previous - if !sameError(Cause(err), e.cause) && e.cause != nil { - err = e.cause - } - switch { - case err == nil: - return e.message - case e.message == "": - return err.Error() - } - return fmt.Sprintf("%s: %v", e.message, err) -} - -// SetLocation records the source location of the error at callDepth stack -// frames above the call. -func (e *Err) SetLocation(callDepth int) { - _, file, line, _ := runtime.Caller(callDepth + 1) - e.file = trimGoPath(file) - e.line = line -} - -// StackTrace returns one string for each location recorded in the stack of -// errors. The first value is the originating error, with a line for each -// other annotation or tracing of the error. -func (e *Err) StackTrace() []string { - return errorStack(e) -} - -// Ideally we'd have a way to check identity, but deep equals will do. -func sameError(e1, e2 error) bool { - return reflect.DeepEqual(e1, e2) -} diff --git a/vendor/src/github.com/juju/errors/error_test.go b/vendor/src/github.com/juju/errors/error_test.go deleted file mode 100644 index ac1d2b423..000000000 --- a/vendor/src/github.com/juju/errors/error_test.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - "fmt" - "runtime" - - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" - - "github.com/juju/errors" -) - -type errorsSuite struct{} - -var _ = gc.Suite(&errorsSuite{}) - -var someErr = errors.New("some error") //err varSomeErr - -func (*errorsSuite) TestErrorString(c *gc.C) { - for i, test := range []struct { - message string - generator func() error - expected string - }{ - { - message: "uncomparable errors", - generator: func() error { - err := errors.Annotatef(newNonComparableError("uncomparable"), "annotation") - return errors.Annotatef(err, "another") - }, - expected: "another: annotation: uncomparable", - }, { - message: "Errorf", - generator: func() error { - return errors.Errorf("first error") - }, - expected: "first error", - }, { - message: "annotated error", - generator: func() error { - err := errors.Errorf("first error") - return errors.Annotatef(err, "annotation") - }, - expected: "annotation: first error", - }, { - message: "test annotation format", - generator: func() error { - err := errors.Errorf("first %s", "error") - return errors.Annotatef(err, "%s", "annotation") - }, - expected: "annotation: first error", - }, { - message: "wrapped error", - generator: func() error { - err := newError("first error") - return errors.Wrap(err, newError("detailed error")) - }, - expected: "detailed error", - }, { - message: "wrapped annotated error", - generator: func() error { - err := errors.Errorf("first error") - err = errors.Annotatef(err, "annotated") - return errors.Wrap(err, fmt.Errorf("detailed error")) - }, - expected: "detailed error", - }, { - message: "annotated wrapped error", - generator: func() error { - err := errors.Errorf("first error") - err = errors.Wrap(err, fmt.Errorf("detailed error")) - return errors.Annotatef(err, "annotated") - }, - expected: "annotated: detailed error", - }, { - message: "traced, and annotated", - generator: func() error { - err := errors.New("first error") - err = errors.Trace(err) - err = errors.Annotate(err, "some context") - err = errors.Trace(err) - err = errors.Annotate(err, "more context") - return errors.Trace(err) - }, - expected: "more context: some context: first error", - }, { - message: "traced, and annotated, masked and annotated", - generator: func() error { - err := errors.New("first error") - err = errors.Trace(err) - err = errors.Annotate(err, "some context") - err = errors.Maskf(err, "masked") - err = errors.Annotate(err, "more context") - return errors.Trace(err) - }, - expected: "more context: masked: some context: first error", - }, - } { - c.Logf("%v: %s", i, test.message) - err := test.generator() - ok := c.Check(err.Error(), gc.Equals, test.expected) - if !ok { - c.Logf("%#v", test.generator()) - } - } -} - -type embed struct { - errors.Err -} - -func newEmbed(format string, args ...interface{}) *embed { - err := &embed{errors.NewErr(format, args...)} - err.SetLocation(1) - return err -} - -func (*errorsSuite) TestNewErr(c *gc.C) { - if runtime.Compiler == "gccgo" { - c.Skip("gccgo can't determine the location") - } - err := newEmbed("testing %d", 42) //err embedErr - c.Assert(err.Error(), gc.Equals, "testing 42") - c.Assert(errors.Cause(err), gc.Equals, err) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["embedErr"].String()) -} - -var _ error = (*embed)(nil) - -// This is an uncomparable error type, as it is a struct that supports the -// error interface (as opposed to a pointer type). -type error_ struct { - info string - slice []string -} - -// Create a non-comparable error -func newNonComparableError(message string) error { - return error_{info: message} -} - -func (e error_) Error() string { - return e.info -} - -func newError(message string) error { - return testError{message} -} - -// The testError is a value type error for ease of seeing results -// when the test fails. -type testError struct { - message string -} - -func (e testError) Error() string { - return e.message -} diff --git a/vendor/src/github.com/juju/errors/errortypes.go b/vendor/src/github.com/juju/errors/errortypes.go deleted file mode 100644 index aa970e99c..000000000 --- a/vendor/src/github.com/juju/errors/errortypes.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors - -import ( - "fmt" -) - -// wrap is a helper to construct an *wrapper. -func wrap(err error, format, suffix string, args ...interface{}) Err { - newErr := Err{ - message: fmt.Sprintf(format+suffix, args...), - previous: err, - } - newErr.SetLocation(2) - return newErr -} - -// notFound represents an error when something has not been found. -type notFound struct { - Err -} - -// NotFoundf returns an error which satisfies IsNotFound(). -func NotFoundf(format string, args ...interface{}) error { - return ¬Found{wrap(nil, format, " not found", args...)} -} - -// NewNotFound returns an error which wraps err that satisfies -// IsNotFound(). -func NewNotFound(err error, msg string) error { - return ¬Found{wrap(err, msg, "")} -} - -// IsNotFound reports whether err was created with NotFoundf() or -// NewNotFound(). -func IsNotFound(err error) bool { - err = Cause(err) - _, ok := err.(*notFound) - return ok -} - -// userNotFound represents an error when an inexistent user is looked up. -type userNotFound struct { - Err -} - -// UserNotFoundf returns an error which satisfies IsUserNotFound(). -func UserNotFoundf(format string, args ...interface{}) error { - return &userNotFound{wrap(nil, format, " user not found", args...)} -} - -// NewUserNotFound returns an error which wraps err and satisfies -// IsUserNotFound(). -func NewUserNotFound(err error, msg string) error { - return &userNotFound{wrap(err, msg, "")} -} - -// IsUserNotFound reports whether err was created with UserNotFoundf() or -// NewUserNotFound(). -func IsUserNotFound(err error) bool { - err = Cause(err) - _, ok := err.(*userNotFound) - return ok -} - -// unauthorized represents an error when an operation is unauthorized. -type unauthorized struct { - Err -} - -// Unauthorizedf returns an error which satisfies IsUnauthorized(). -func Unauthorizedf(format string, args ...interface{}) error { - return &unauthorized{wrap(nil, format, "", args...)} -} - -// NewUnauthorized returns an error which wraps err and satisfies -// IsUnauthorized(). -func NewUnauthorized(err error, msg string) error { - return &unauthorized{wrap(err, msg, "")} -} - -// IsUnauthorized reports whether err was created with Unauthorizedf() or -// NewUnauthorized(). -func IsUnauthorized(err error) bool { - err = Cause(err) - _, ok := err.(*unauthorized) - return ok -} - -// notImplemented represents an error when something is not -// implemented. -type notImplemented struct { - Err -} - -// NotImplementedf returns an error which satisfies IsNotImplemented(). -func NotImplementedf(format string, args ...interface{}) error { - return ¬Implemented{wrap(nil, format, " not implemented", args...)} -} - -// NewNotImplemented returns an error which wraps err and satisfies -// IsNotImplemented(). -func NewNotImplemented(err error, msg string) error { - return ¬Implemented{wrap(err, msg, "")} -} - -// IsNotImplemented reports whether err was created with -// NotImplementedf() or NewNotImplemented(). -func IsNotImplemented(err error) bool { - err = Cause(err) - _, ok := err.(*notImplemented) - return ok -} - -// alreadyExists represents and error when something already exists. -type alreadyExists struct { - Err -} - -// AlreadyExistsf returns an error which satisfies IsAlreadyExists(). -func AlreadyExistsf(format string, args ...interface{}) error { - return &alreadyExists{wrap(nil, format, " already exists", args...)} -} - -// NewAlreadyExists returns an error which wraps err and satisfies -// IsAlreadyExists(). -func NewAlreadyExists(err error, msg string) error { - return &alreadyExists{wrap(err, msg, "")} -} - -// IsAlreadyExists reports whether the error was created with -// AlreadyExistsf() or NewAlreadyExists(). -func IsAlreadyExists(err error) bool { - err = Cause(err) - _, ok := err.(*alreadyExists) - return ok -} - -// notSupported represents an error when something is not supported. -type notSupported struct { - Err -} - -// NotSupportedf returns an error which satisfies IsNotSupported(). -func NotSupportedf(format string, args ...interface{}) error { - return ¬Supported{wrap(nil, format, " not supported", args...)} -} - -// NewNotSupported returns an error which wraps err and satisfies -// IsNotSupported(). -func NewNotSupported(err error, msg string) error { - return ¬Supported{wrap(err, msg, "")} -} - -// IsNotSupported reports whether the error was created with -// NotSupportedf() or NewNotSupported(). -func IsNotSupported(err error) bool { - err = Cause(err) - _, ok := err.(*notSupported) - return ok -} - -// notValid represents an error when something is not valid. -type notValid struct { - Err -} - -// NotValidf returns an error which satisfies IsNotValid(). -func NotValidf(format string, args ...interface{}) error { - return ¬Valid{wrap(nil, format, " not valid", args...)} -} - -// NewNotValid returns an error which wraps err and satisfies IsNotValid(). -func NewNotValid(err error, msg string) error { - return ¬Valid{wrap(err, msg, "")} -} - -// IsNotValid reports whether the error was created with NotValidf() or -// NewNotValid(). -func IsNotValid(err error) bool { - err = Cause(err) - _, ok := err.(*notValid) - return ok -} - -// notProvisioned represents an error when something is not yet provisioned. -type notProvisioned struct { - Err -} - -// NotProvisionedf returns an error which satisfies IsNotProvisioned(). -func NotProvisionedf(format string, args ...interface{}) error { - return ¬Provisioned{wrap(nil, format, " not provisioned", args...)} -} - -// NewNotProvisioned returns an error which wraps err that satisfies -// IsNotProvisioned(). -func NewNotProvisioned(err error, msg string) error { - return ¬Provisioned{wrap(err, msg, "")} -} - -// IsNotProvisioned reports whether err was created with NotProvisionedf() or -// NewNotProvisioned(). -func IsNotProvisioned(err error) bool { - err = Cause(err) - _, ok := err.(*notProvisioned) - return ok -} - -// notAssigned represents an error when something is not yet assigned to -// something else. -type notAssigned struct { - Err -} - -// NotAssignedf returns an error which satisfies IsNotAssigned(). -func NotAssignedf(format string, args ...interface{}) error { - return ¬Assigned{wrap(nil, format, " not assigned", args...)} -} - -// NewNotAssigned returns an error which wraps err that satisfies -// IsNotAssigned(). -func NewNotAssigned(err error, msg string) error { - return ¬Assigned{wrap(err, msg, "")} -} - -// IsNotAssigned reports whether err was created with NotAssignedf() or -// NewNotAssigned(). -func IsNotAssigned(err error) bool { - err = Cause(err) - _, ok := err.(*notAssigned) - return ok -} diff --git a/vendor/src/github.com/juju/errors/errortypes_test.go b/vendor/src/github.com/juju/errors/errortypes_test.go deleted file mode 100644 index 943772b5d..000000000 --- a/vendor/src/github.com/juju/errors/errortypes_test.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - stderrors "errors" - "fmt" - "reflect" - "runtime" - - "github.com/juju/errors" - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" -) - -// errorInfo holds information about a single error type: a satisfier -// function, wrapping and variable arguments constructors and message -// suffix. -type errorInfo struct { - satisfier func(error) bool - argsConstructor func(string, ...interface{}) error - wrapConstructor func(error, string) error - suffix string -} - -// allErrors holds information for all defined errors. When adding new -// errors, add them here as well to include them in tests. -var allErrors = []*errorInfo{ - &errorInfo{errors.IsNotFound, errors.NotFoundf, errors.NewNotFound, " not found"}, - &errorInfo{errors.IsUserNotFound, errors.UserNotFoundf, errors.NewUserNotFound, " user not found"}, - &errorInfo{errors.IsUnauthorized, errors.Unauthorizedf, errors.NewUnauthorized, ""}, - &errorInfo{errors.IsNotImplemented, errors.NotImplementedf, errors.NewNotImplemented, " not implemented"}, - &errorInfo{errors.IsAlreadyExists, errors.AlreadyExistsf, errors.NewAlreadyExists, " already exists"}, - &errorInfo{errors.IsNotSupported, errors.NotSupportedf, errors.NewNotSupported, " not supported"}, - &errorInfo{errors.IsNotValid, errors.NotValidf, errors.NewNotValid, " not valid"}, - &errorInfo{errors.IsNotProvisioned, errors.NotProvisionedf, errors.NewNotProvisioned, " not provisioned"}, - &errorInfo{errors.IsNotAssigned, errors.NotAssignedf, errors.NewNotAssigned, " not assigned"}, -} - -type errorTypeSuite struct{} - -var _ = gc.Suite(&errorTypeSuite{}) - -func (t *errorInfo) satisfierName() string { - value := reflect.ValueOf(t.satisfier) - f := runtime.FuncForPC(value.Pointer()) - return f.Name() -} - -func (t *errorInfo) equal(t0 *errorInfo) bool { - if t0 == nil { - return false - } - return t.satisfierName() == t0.satisfierName() -} - -type errorTest struct { - err error - message string - errInfo *errorInfo -} - -func deferredAnnotatef(err error, format string, args ...interface{}) error { - errors.DeferredAnnotatef(&err, format, args...) - return err -} - -func mustSatisfy(c *gc.C, err error, errInfo *errorInfo) { - if errInfo != nil { - msg := fmt.Sprintf("%#v must satisfy %v", err, errInfo.satisfierName()) - c.Check(err, jc.Satisfies, errInfo.satisfier, gc.Commentf(msg)) - } -} - -func mustNotSatisfy(c *gc.C, err error, errInfo *errorInfo) { - if errInfo != nil { - msg := fmt.Sprintf("%#v must not satisfy %v", err, errInfo.satisfierName()) - c.Check(err, gc.Not(jc.Satisfies), errInfo.satisfier, gc.Commentf(msg)) - } -} - -func checkErrorMatches(c *gc.C, err error, message string, errInfo *errorInfo) { - if message == "" { - c.Check(err, gc.IsNil) - c.Check(errInfo, gc.IsNil) - } else { - c.Check(err, gc.ErrorMatches, message) - } -} - -func runErrorTests(c *gc.C, errorTests []errorTest, checkMustSatisfy bool) { - for i, t := range errorTests { - c.Logf("test %d: %T: %v", i, t.err, t.err) - checkErrorMatches(c, t.err, t.message, t.errInfo) - if checkMustSatisfy { - mustSatisfy(c, t.err, t.errInfo) - } - - // Check all other satisfiers to make sure none match. - for _, otherErrInfo := range allErrors { - if checkMustSatisfy && otherErrInfo.equal(t.errInfo) { - continue - } - mustNotSatisfy(c, t.err, otherErrInfo) - } - } -} - -func (*errorTypeSuite) TestDeferredAnnotatef(c *gc.C) { - // Ensure DeferredAnnotatef annotates the errors. - errorTests := []errorTest{} - for _, errInfo := range allErrors { - errorTests = append(errorTests, []errorTest{{ - deferredAnnotatef(nil, "comment"), - "", - nil, - }, { - deferredAnnotatef(stderrors.New("blast"), "comment"), - "comment: blast", - nil, - }, { - deferredAnnotatef(errInfo.argsConstructor("foo %d", 42), "comment %d", 69), - "comment 69: foo 42" + errInfo.suffix, - errInfo, - }, { - deferredAnnotatef(errInfo.argsConstructor(""), "comment"), - "comment: " + errInfo.suffix, - errInfo, - }, { - deferredAnnotatef(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "comment"), - "comment: woo: pow!", - errInfo, - }}...) - } - - runErrorTests(c, errorTests, true) -} - -func (*errorTypeSuite) TestAllErrors(c *gc.C) { - errorTests := []errorTest{} - for _, errInfo := range allErrors { - errorTests = append(errorTests, []errorTest{{ - nil, - "", - nil, - }, { - errInfo.argsConstructor("foo %d", 42), - "foo 42" + errInfo.suffix, - errInfo, - }, { - errInfo.argsConstructor(""), - errInfo.suffix, - errInfo, - }, { - errInfo.wrapConstructor(stderrors.New("pow!"), "prefix"), - "prefix: pow!", - errInfo, - }, { - errInfo.wrapConstructor(stderrors.New("pow!"), ""), - "pow!", - errInfo, - }, { - errInfo.wrapConstructor(nil, "prefix"), - "prefix", - errInfo, - }}...) - } - - runErrorTests(c, errorTests, true) -} diff --git a/vendor/src/github.com/juju/errors/example_test.go b/vendor/src/github.com/juju/errors/example_test.go deleted file mode 100644 index 2a79cf489..000000000 --- a/vendor/src/github.com/juju/errors/example_test.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - "fmt" - - "github.com/juju/errors" -) - -func ExampleTrace() { - var err1 error = fmt.Errorf("something wicked this way comes") - var err2 error = nil - - // Tracing a non nil error will return an error - fmt.Println(errors.Trace(err1)) - // Tracing nil will return nil - fmt.Println(errors.Trace(err2)) - - // Output: something wicked this way comes - // -} diff --git a/vendor/src/github.com/juju/errors/export_test.go b/vendor/src/github.com/juju/errors/export_test.go deleted file mode 100644 index db57ec81c..000000000 --- a/vendor/src/github.com/juju/errors/export_test.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors - -// Since variables are declared before the init block, in order to get the goPath -// we need to return it rather than just reference it. -func GoPath() string { - return goPath -} - -var TrimGoPath = trimGoPath diff --git a/vendor/src/github.com/juju/errors/functions.go b/vendor/src/github.com/juju/errors/functions.go deleted file mode 100644 index 994208d8d..000000000 --- a/vendor/src/github.com/juju/errors/functions.go +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors - -import ( - "fmt" - "strings" -) - -// New is a drop in replacement for the standard libary errors module that records -// the location that the error is created. -// -// For example: -// return errors.New("validation failed") -// -func New(message string) error { - err := &Err{message: message} - err.SetLocation(1) - return err -} - -// Errorf creates a new annotated error and records the location that the -// error is created. This should be a drop in replacement for fmt.Errorf. -// -// For example: -// return errors.Errorf("validation failed: %s", message) -// -func Errorf(format string, args ...interface{}) error { - err := &Err{message: fmt.Sprintf(format, args...)} - err.SetLocation(1) - return err -} - -// Trace adds the location of the Trace call to the stack. The Cause of the -// resulting error is the same as the error parameter. If the other error is -// nil, the result will be nil. -// -// For example: -// if err := SomeFunc(); err != nil { -// return errors.Trace(err) -// } -// -func Trace(other error) error { - if other == nil { - return nil - } - err := &Err{previous: other, cause: Cause(other)} - err.SetLocation(1) - return err -} - -// Annotate is used to add extra context to an existing error. The location of -// the Annotate call is recorded with the annotations. The file, line and -// function are also recorded. -// -// For example: -// if err := SomeFunc(); err != nil { -// return errors.Annotate(err, "failed to frombulate") -// } -// -func Annotate(other error, message string) error { - if other == nil { - return nil - } - err := &Err{ - previous: other, - cause: Cause(other), - message: message, - } - err.SetLocation(1) - return err -} - -// Annotatef is used to add extra context to an existing error. The location of -// the Annotate call is recorded with the annotations. The file, line and -// function are also recorded. -// -// For example: -// if err := SomeFunc(); err != nil { -// return errors.Annotatef(err, "failed to frombulate the %s", arg) -// } -// -func Annotatef(other error, format string, args ...interface{}) error { - if other == nil { - return nil - } - err := &Err{ - previous: other, - cause: Cause(other), - message: fmt.Sprintf(format, args...), - } - err.SetLocation(1) - return err -} - -// DeferredAnnotatef annotates the given error (when it is not nil) with the given -// format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef -// does nothing. This method is used in a defer statement in order to annotate any -// resulting error with the same message. -// -// For example: -// -// defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg) -// -func DeferredAnnotatef(err *error, format string, args ...interface{}) { - if *err == nil { - return - } - newErr := &Err{ - message: fmt.Sprintf(format, args...), - cause: Cause(*err), - previous: *err, - } - newErr.SetLocation(1) - *err = newErr -} - -// Wrap changes the Cause of the error. The location of the Wrap call is also -// stored in the error stack. -// -// For example: -// if err := SomeFunc(); err != nil { -// newErr := &packageError{"more context", private_value} -// return errors.Wrap(err, newErr) -// } -// -func Wrap(other, newDescriptive error) error { - err := &Err{ - previous: other, - cause: newDescriptive, - } - err.SetLocation(1) - return err -} - -// Wrapf changes the Cause of the error, and adds an annotation. The location -// of the Wrap call is also stored in the error stack. -// -// For example: -// if err := SomeFunc(); err != nil { -// return errors.Wrapf(err, simpleErrorType, "invalid value %q", value) -// } -// -func Wrapf(other, newDescriptive error, format string, args ...interface{}) error { - err := &Err{ - message: fmt.Sprintf(format, args...), - previous: other, - cause: newDescriptive, - } - err.SetLocation(1) - return err -} - -// Mask masks the given error with the given format string and arguments (like -// fmt.Sprintf), returning a new error that maintains the error stack, but -// hides the underlying error type. The error string still contains the full -// annotations. If you want to hide the annotations, call Wrap. -func Maskf(other error, format string, args ...interface{}) error { - if other == nil { - return nil - } - err := &Err{ - message: fmt.Sprintf(format, args...), - previous: other, - } - err.SetLocation(1) - return err -} - -// Mask hides the underlying error type, and records the location of the masking. -func Mask(other error) error { - if other == nil { - return nil - } - err := &Err{ - previous: other, - } - err.SetLocation(1) - return err -} - -// Cause returns the cause of the given error. This will be either the -// original error, or the result of a Wrap or Mask call. -// -// Cause is the usual way to diagnose errors that may have been wrapped by -// the other errors functions. -func Cause(err error) error { - var diag error - if err, ok := err.(causer); ok { - diag = err.Cause() - } - if diag != nil { - return diag - } - return err -} - -type causer interface { - Cause() error -} - -type wrapper interface { - // Message returns the top level error message, - // not including the message from the Previous - // error. - Message() string - - // Underlying returns the Previous error, or nil - // if there is none. - Underlying() error -} - -type locationer interface { - Location() (string, int) -} - -var ( - _ wrapper = (*Err)(nil) - _ locationer = (*Err)(nil) - _ causer = (*Err)(nil) -) - -// Details returns information about the stack of errors wrapped by err, in -// the format: -// -// [{filename:99: error one} {otherfile:55: cause of error one}] -// -// This is a terse alternative to ErrorStack as it returns a single line. -func Details(err error) string { - if err == nil { - return "[]" - } - var s []byte - s = append(s, '[') - for { - s = append(s, '{') - if err, ok := err.(locationer); ok { - file, line := err.Location() - if file != "" { - s = append(s, fmt.Sprintf("%s:%d", file, line)...) - s = append(s, ": "...) - } - } - if cerr, ok := err.(wrapper); ok { - s = append(s, cerr.Message()...) - err = cerr.Underlying() - } else { - s = append(s, err.Error()...) - err = nil - } - s = append(s, '}') - if err == nil { - break - } - s = append(s, ' ') - } - s = append(s, ']') - return string(s) -} - -// ErrorStack returns a string representation of the annotated error. If the -// error passed as the parameter is not an annotated error, the result is -// simply the result of the Error() method on that error. -// -// If the error is an annotated error, a multi-line string is returned where -// each line represents one entry in the annotation stack. The full filename -// from the call stack is used in the output. -// -// first error -// github.com/juju/errors/annotation_test.go:193: -// github.com/juju/errors/annotation_test.go:194: annotation -// github.com/juju/errors/annotation_test.go:195: -// github.com/juju/errors/annotation_test.go:196: more context -// github.com/juju/errors/annotation_test.go:197: -func ErrorStack(err error) string { - return strings.Join(errorStack(err), "\n") -} - -func errorStack(err error) []string { - if err == nil { - return nil - } - - // We want the first error first - var lines []string - for { - var buff []byte - if err, ok := err.(locationer); ok { - file, line := err.Location() - // Strip off the leading GOPATH/src path elements. - file = trimGoPath(file) - if file != "" { - buff = append(buff, fmt.Sprintf("%s:%d", file, line)...) - buff = append(buff, ": "...) - } - } - if cerr, ok := err.(wrapper); ok { - message := cerr.Message() - buff = append(buff, message...) - // If there is a cause for this error, and it is different to the cause - // of the underlying error, then output the error string in the stack trace. - var cause error - if err1, ok := err.(causer); ok { - cause = err1.Cause() - } - err = cerr.Underlying() - if cause != nil && !sameError(Cause(err), cause) { - if message != "" { - buff = append(buff, ": "...) - } - buff = append(buff, cause.Error()...) - } - } else { - buff = append(buff, err.Error()...) - err = nil - } - lines = append(lines, string(buff)) - if err == nil { - break - } - } - // reverse the lines to get the original error, which was at the end of - // the list, back to the start. - var result []string - for i := len(lines); i > 0; i-- { - result = append(result, lines[i-1]) - } - return result -} diff --git a/vendor/src/github.com/juju/errors/functions_test.go b/vendor/src/github.com/juju/errors/functions_test.go deleted file mode 100644 index 7b1e43b15..000000000 --- a/vendor/src/github.com/juju/errors/functions_test.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "strings" - - jc "github.com/juju/testing/checkers" - gc "gopkg.in/check.v1" - - "github.com/juju/errors" -) - -type functionSuite struct { -} - -var _ = gc.Suite(&functionSuite{}) - -func (*functionSuite) TestNew(c *gc.C) { - err := errors.New("testing") //err newTest - c.Assert(err.Error(), gc.Equals, "testing") - c.Assert(errors.Cause(err), gc.Equals, err) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["newTest"].String()) -} - -func (*functionSuite) TestErrorf(c *gc.C) { - err := errors.Errorf("testing %d", 42) //err errorfTest - c.Assert(err.Error(), gc.Equals, "testing 42") - c.Assert(errors.Cause(err), gc.Equals, err) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["errorfTest"].String()) -} - -func (*functionSuite) TestTrace(c *gc.C) { - first := errors.New("first") - err := errors.Trace(first) //err traceTest - c.Assert(err.Error(), gc.Equals, "first") - c.Assert(errors.Cause(err), gc.Equals, first) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["traceTest"].String()) - - c.Assert(errors.Trace(nil), gc.IsNil) -} - -func (*functionSuite) TestAnnotate(c *gc.C) { - first := errors.New("first") - err := errors.Annotate(first, "annotation") //err annotateTest - c.Assert(err.Error(), gc.Equals, "annotation: first") - c.Assert(errors.Cause(err), gc.Equals, first) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotateTest"].String()) - - c.Assert(errors.Annotate(nil, "annotate"), gc.IsNil) -} - -func (*functionSuite) TestAnnotatef(c *gc.C) { - first := errors.New("first") - err := errors.Annotatef(first, "annotation %d", 2) //err annotatefTest - c.Assert(err.Error(), gc.Equals, "annotation 2: first") - c.Assert(errors.Cause(err), gc.Equals, first) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotatefTest"].String()) - - c.Assert(errors.Annotatef(nil, "annotate"), gc.IsNil) -} - -func (*functionSuite) TestDeferredAnnotatef(c *gc.C) { - // NOTE: this test fails with gccgo - if runtime.Compiler == "gccgo" { - c.Skip("gccgo can't determine the location") - } - first := errors.New("first") - test := func() (err error) { - defer errors.DeferredAnnotatef(&err, "deferred %s", "annotate") - return first - } //err deferredAnnotate - err := test() - c.Assert(err.Error(), gc.Equals, "deferred annotate: first") - c.Assert(errors.Cause(err), gc.Equals, first) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["deferredAnnotate"].String()) - - err = nil - errors.DeferredAnnotatef(&err, "deferred %s", "annotate") - c.Assert(err, gc.IsNil) -} - -func (*functionSuite) TestWrap(c *gc.C) { - first := errors.New("first") //err wrapFirst - detailed := errors.New("detailed") - err := errors.Wrap(first, detailed) //err wrapTest - c.Assert(err.Error(), gc.Equals, "detailed") - c.Assert(errors.Cause(err), gc.Equals, detailed) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapFirst"].String()) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapTest"].String()) -} - -func (*functionSuite) TestWrapOfNil(c *gc.C) { - detailed := errors.New("detailed") - err := errors.Wrap(nil, detailed) //err nilWrapTest - c.Assert(err.Error(), gc.Equals, "detailed") - c.Assert(errors.Cause(err), gc.Equals, detailed) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapTest"].String()) -} - -func (*functionSuite) TestWrapf(c *gc.C) { - first := errors.New("first") //err wrapfFirst - detailed := errors.New("detailed") - err := errors.Wrapf(first, detailed, "value %d", 42) //err wrapfTest - c.Assert(err.Error(), gc.Equals, "value 42: detailed") - c.Assert(errors.Cause(err), gc.Equals, detailed) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfFirst"].String()) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfTest"].String()) -} - -func (*functionSuite) TestWrapfOfNil(c *gc.C) { - detailed := errors.New("detailed") - err := errors.Wrapf(nil, detailed, "value %d", 42) //err nilWrapfTest - c.Assert(err.Error(), gc.Equals, "value 42: detailed") - c.Assert(errors.Cause(err), gc.Equals, detailed) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapfTest"].String()) -} - -func (*functionSuite) TestMask(c *gc.C) { - first := errors.New("first") - err := errors.Mask(first) //err maskTest - c.Assert(err.Error(), gc.Equals, "first") - c.Assert(errors.Cause(err), gc.Equals, err) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskTest"].String()) - - c.Assert(errors.Mask(nil), gc.IsNil) -} - -func (*functionSuite) TestMaskf(c *gc.C) { - first := errors.New("first") - err := errors.Maskf(first, "masked %d", 42) //err maskfTest - c.Assert(err.Error(), gc.Equals, "masked 42: first") - c.Assert(errors.Cause(err), gc.Equals, err) - c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskfTest"].String()) - - c.Assert(errors.Maskf(nil, "mask"), gc.IsNil) -} - -func (*functionSuite) TestCause(c *gc.C) { - c.Assert(errors.Cause(nil), gc.IsNil) - c.Assert(errors.Cause(someErr), gc.Equals, someErr) - - fmtErr := fmt.Errorf("simple") - c.Assert(errors.Cause(fmtErr), gc.Equals, fmtErr) - - err := errors.Wrap(someErr, fmtErr) - c.Assert(errors.Cause(err), gc.Equals, fmtErr) - - err = errors.Annotate(err, "annotated") - c.Assert(errors.Cause(err), gc.Equals, fmtErr) - - err = errors.Maskf(err, "maksed") - c.Assert(errors.Cause(err), gc.Equals, err) - - // Look for a file that we know isn't there. - dir := c.MkDir() - _, err = os.Stat(filepath.Join(dir, "not-there")) - c.Assert(os.IsNotExist(err), jc.IsTrue) - - err = errors.Annotatef(err, "wrap it") - // Now the error itself isn't a 'IsNotExist'. - c.Assert(os.IsNotExist(err), jc.IsFalse) - // However if we use the Check method, it is. - c.Assert(os.IsNotExist(errors.Cause(err)), jc.IsTrue) -} - -func (s *functionSuite) TestDetails(c *gc.C) { - if runtime.Compiler == "gccgo" { - c.Skip("gccgo can't determine the location") - } - c.Assert(errors.Details(nil), gc.Equals, "[]") - - otherErr := fmt.Errorf("other") - checkDetails(c, otherErr, "[{other}]") - - err0 := newEmbed("foo") //err TestStack#0 - checkDetails(c, err0, "[{$TestStack#0$: foo}]") - - err1 := errors.Annotate(err0, "bar") //err TestStack#1 - checkDetails(c, err1, "[{$TestStack#1$: bar} {$TestStack#0$: foo}]") - - err2 := errors.Trace(err1) //err TestStack#2 - checkDetails(c, err2, "[{$TestStack#2$: } {$TestStack#1$: bar} {$TestStack#0$: foo}]") -} - -type tracer interface { - StackTrace() []string -} - -func (*functionSuite) TestErrorStack(c *gc.C) { - for i, test := range []struct { - message string - generator func() error - expected string - tracer bool - }{ - { - message: "nil", - generator: func() error { - return nil - }, - }, { - message: "raw error", - generator: func() error { - return fmt.Errorf("raw") - }, - expected: "raw", - }, { - message: "single error stack", - generator: func() error { - return errors.New("first error") //err single - }, - expected: "$single$: first error", - tracer: true, - }, { - message: "annotated error", - generator: func() error { - err := errors.New("first error") //err annotated-0 - return errors.Annotate(err, "annotation") //err annotated-1 - }, - expected: "" + - "$annotated-0$: first error\n" + - "$annotated-1$: annotation", - tracer: true, - }, { - message: "wrapped error", - generator: func() error { - err := errors.New("first error") //err wrapped-0 - return errors.Wrap(err, newError("detailed error")) //err wrapped-1 - }, - expected: "" + - "$wrapped-0$: first error\n" + - "$wrapped-1$: detailed error", - tracer: true, - }, { - message: "annotated wrapped error", - generator: func() error { - err := errors.Errorf("first error") //err ann-wrap-0 - err = errors.Wrap(err, fmt.Errorf("detailed error")) //err ann-wrap-1 - return errors.Annotatef(err, "annotated") //err ann-wrap-2 - }, - expected: "" + - "$ann-wrap-0$: first error\n" + - "$ann-wrap-1$: detailed error\n" + - "$ann-wrap-2$: annotated", - tracer: true, - }, { - message: "traced, and annotated", - generator: func() error { - err := errors.New("first error") //err stack-0 - err = errors.Trace(err) //err stack-1 - err = errors.Annotate(err, "some context") //err stack-2 - err = errors.Trace(err) //err stack-3 - err = errors.Annotate(err, "more context") //err stack-4 - return errors.Trace(err) //err stack-5 - }, - expected: "" + - "$stack-0$: first error\n" + - "$stack-1$: \n" + - "$stack-2$: some context\n" + - "$stack-3$: \n" + - "$stack-4$: more context\n" + - "$stack-5$: ", - tracer: true, - }, { - message: "uncomparable, wrapped with a value error", - generator: func() error { - err := newNonComparableError("first error") //err mixed-0 - err = errors.Trace(err) //err mixed-1 - err = errors.Wrap(err, newError("value error")) //err mixed-2 - err = errors.Maskf(err, "masked") //err mixed-3 - err = errors.Annotate(err, "more context") //err mixed-4 - return errors.Trace(err) //err mixed-5 - }, - expected: "" + - "first error\n" + - "$mixed-1$: \n" + - "$mixed-2$: value error\n" + - "$mixed-3$: masked\n" + - "$mixed-4$: more context\n" + - "$mixed-5$: ", - tracer: true, - }, - } { - c.Logf("%v: %s", i, test.message) - err := test.generator() - expected := replaceLocations(test.expected) - stack := errors.ErrorStack(err) - ok := c.Check(stack, gc.Equals, expected) - if !ok { - c.Logf("%#v", err) - } - tracer, ok := err.(tracer) - c.Check(ok, gc.Equals, test.tracer) - if ok { - stackTrace := tracer.StackTrace() - c.Check(stackTrace, gc.DeepEquals, strings.Split(stack, "\n")) - } - } -} diff --git a/vendor/src/github.com/juju/errors/package_test.go b/vendor/src/github.com/juju/errors/package_test.go deleted file mode 100644 index 5bbb8f04e..000000000 --- a/vendor/src/github.com/juju/errors/package_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - "fmt" - "io/ioutil" - "strings" - "testing" - - gc "gopkg.in/check.v1" - - "github.com/juju/errors" -) - -func Test(t *testing.T) { - gc.TestingT(t) -} - -func checkDetails(c *gc.C, err error, details string) { - c.Assert(err, gc.NotNil) - expectedDetails := replaceLocations(details) - c.Assert(errors.Details(err), gc.Equals, expectedDetails) -} - -func checkErr(c *gc.C, err, cause error, msg string, details string) { - c.Assert(err, gc.NotNil) - c.Assert(err.Error(), gc.Equals, msg) - c.Assert(errors.Cause(err), gc.Equals, cause) - expectedDetails := replaceLocations(details) - c.Assert(errors.Details(err), gc.Equals, expectedDetails) -} - -func replaceLocations(line string) string { - result := "" - for { - i := strings.Index(line, "$") - if i == -1 { - break - } - result += line[0:i] - line = line[i+1:] - i = strings.Index(line, "$") - if i == -1 { - panic("no second $") - } - result += location(line[0:i]).String() - line = line[i+1:] - } - result += line - return result -} - -func location(tag string) Location { - loc, ok := tagToLocation[tag] - if !ok { - panic(fmt.Sprintf("tag %q not found", tag)) - } - return loc -} - -type Location struct { - file string - line int -} - -func (loc Location) String() string { - return fmt.Sprintf("%s:%d", loc.file, loc.line) -} - -var tagToLocation = make(map[string]Location) - -func setLocationsForErrorTags(filename string) { - data, err := ioutil.ReadFile(filename) - if err != nil { - panic(err) - } - filename = "github.com/juju/errors/" + filename - lines := strings.Split(string(data), "\n") - for i, line := range lines { - if j := strings.Index(line, "//err "); j >= 0 { - tag := line[j+len("//err "):] - if _, found := tagToLocation[tag]; found { - panic(fmt.Sprintf("tag %q already processed previously", tag)) - } - tagToLocation[tag] = Location{file: filename, line: i + 1} - } - } -} - -func init() { - setLocationsForErrorTags("error_test.go") - setLocationsForErrorTags("functions_test.go") -} diff --git a/vendor/src/github.com/juju/errors/path.go b/vendor/src/github.com/juju/errors/path.go deleted file mode 100644 index 3ec517c81..000000000 --- a/vendor/src/github.com/juju/errors/path.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors - -import ( - "runtime" - "strings" -) - -// prefixSize is used internally to trim the user specific path from the -// front of the returned filenames from the runtime call stack. -var prefixSize int - -// goPath is the deduced path based on the location of this file as compiled. -var goPath string - -func init() { - _, file, _, ok := runtime.Caller(0) - if ok { - // We know that the end of the file should be: - // github.com/juju/errors/path.go - size := len(file) - suffix := len("github.com/juju/errors/path.go") - goPath = file[:size-suffix] - prefixSize = len(goPath) - } -} - -func trimGoPath(filename string) string { - if strings.HasPrefix(filename, goPath) { - return filename[prefixSize:] - } - return filename -} diff --git a/vendor/src/github.com/juju/errors/path_test.go b/vendor/src/github.com/juju/errors/path_test.go deleted file mode 100644 index ef4f34f82..000000000 --- a/vendor/src/github.com/juju/errors/path_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013, 2014 Canonical Ltd. -// Licensed under the LGPLv3, see LICENCE file for details. - -package errors_test - -import ( - "path" - - gc "gopkg.in/check.v1" - - "github.com/juju/errors" -) - -type pathSuite struct{} - -var _ = gc.Suite(&pathSuite{}) - -func (*pathSuite) TestGoPathSet(c *gc.C) { - c.Assert(errors.GoPath(), gc.Not(gc.Equals), "") -} - -func (*pathSuite) TestTrimGoPath(c *gc.C) { - relativeImport := "github.com/foo/bar/baz.go" - filename := path.Join(errors.GoPath(), relativeImport) - c.Assert(errors.TrimGoPath(filename), gc.Equals, relativeImport) - - absoluteImport := "/usr/share/foo/bar/baz.go" - c.Assert(errors.TrimGoPath(absoluteImport), gc.Equals, absoluteImport) -}