diff --git a/.golangci.yml b/.golangci.yml index cc07e1d28..2609645ad 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -44,6 +44,9 @@ linters: - whitespace - nlreturn - testpackage + - exhaustivestruct + - paralleltest + - tparallel run: skip-dirs: @@ -52,7 +55,7 @@ run: issues: exclude-use-default: false exclude-rules: - - path: _test\.go|testing|test_env + - path: _test\.go|testing|tests|test_env|fshasher linters: - gomnd - gocognit @@ -60,14 +63,16 @@ issues: - errcheck - gosec - nestif - - goerr113 + - wrapcheck - text: "Magic number: 1e" linters: - gomnd - text: "unnecessaryDefer" - linters: gocritic + linters: + - gocritic - text: "filepathJoin" - linters: gocritic + linters: + - gocritic - text: "weak cryptographic primitive" linters: - gosec @@ -86,9 +91,3 @@ issues: - path: cli linters: - gochecknoglobals - -# golangci.com configuration -# https://github.com/golangci/golangci/wiki/Configuration -service: - golangci-lint-version: 1.24.x # use the fixed version to not introduce new linters unexpectedly - diff --git a/cli/app.go b/cli/app.go index 3267d5e09..683a0b468 100644 --- a/cli/app.go +++ b/cli/app.go @@ -176,12 +176,14 @@ func maybeRunMaintenance(ctx context.Context, rep repo.Repository) error { return nil } - if _, ok := err.(maintenance.NotOwnedError); ok { + var noe maintenance.NotOwnedError + + if errors.As(err, &noe) { // do not report the NotOwnedError to the user since this is automatic maintenance. return nil } - return err + return errors.Wrap(err, "error running maintenance") } func advancedCommand(ctx context.Context) { diff --git a/cli/command_benchmark_compression.go b/cli/command_benchmark_compression.go index f0168009f..1f3b950c8 100644 --- a/cli/command_benchmark_compression.go +++ b/cli/command_benchmark_compression.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "sort" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/clock" "github.com/kopia/kopia/internal/units" "github.com/kopia/kopia/repo" @@ -36,7 +38,7 @@ func runBenchmarkCompressionAction(ctx context.Context, rep repo.Repository) err if *benchmarkCompressionDataFile != "" { d, err := ioutil.ReadFile(*benchmarkCompressionDataFile) if err != nil { - return err + return errors.Wrap(err, "error reading compression data file") } data = d diff --git a/cli/command_benchmark_splitters.go b/cli/command_benchmark_splitters.go index 003b97de0..b0d2da408 100644 --- a/cli/command_benchmark_splitters.go +++ b/cli/command_benchmark_splitters.go @@ -6,6 +6,8 @@ import ( "sort" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/clock" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/splitter" @@ -42,7 +44,7 @@ func runBenchmarkSplitterAction(ctx context.Context, rep repo.Repository) error for i := 0; i < *benchmarkSplitterBlockCount; i++ { b := make([]byte, *benchmarkSplitterBlockSize) if _, err := rnd.Read(b); err != nil { - return err + return errors.Wrap(err, "error generating random data") } dataBlocks = append(dataBlocks, b) diff --git a/cli/command_blob_gc.go b/cli/command_blob_gc.go index 103798a40..cf8d7c14d 100644 --- a/cli/command_blob_gc.go +++ b/cli/command_blob_gc.go @@ -3,6 +3,8 @@ package cli import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/maintenance" @@ -28,14 +30,14 @@ func runBlobGarbageCollectCommand(ctx context.Context, rep *repo.DirectRepositor n, err := maintenance.DeleteUnreferencedBlobs(ctx, rep, opts) if err != nil { - return err + return errors.Wrap(err, "error deleting unreferenced blobs") } if opts.DryRun && n > 0 { log(ctx).Infof("Pass --delete=yes to delete.") } - return err + return nil } func init() { diff --git a/cli/command_blob_show.go b/cli/command_blob_show.go index 1ce237b05..0a8a45580 100644 --- a/cli/command_blob_show.go +++ b/cli/command_blob_show.go @@ -56,9 +56,11 @@ func maybeDecryptBlob(ctx context.Context, w io.Writer, rep *repo.DirectReposito return errors.Wrapf(err, "error getting %v", blobID) } - _, err = iocopy.Copy(w, bytes.NewReader(d)) + if _, err := iocopy.Copy(w, bytes.NewReader(d)); err != nil { + return errors.Wrap(err, "error copying data") + } - return err + return nil } func canDecryptBlob(b blob.ID) bool { diff --git a/cli/command_blob_stats.go b/cli/command_blob_stats.go index 435539f79..1a26cb916 100644 --- a/cli/command_blob_stats.go +++ b/cli/command_blob_stats.go @@ -5,6 +5,8 @@ import ( "fmt" "strconv" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/units" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/blob" @@ -49,7 +51,7 @@ func runBlobStatsCommand(ctx context.Context, rep *repo.DirectRepository) error } return nil }); err != nil { - return err + return errors.Wrap(err, "error listing blobs") } sizeToString := units.BytesStringBase10 diff --git a/cli/command_cache_clear.go b/cli/command_cache_clear.go index e0fd8f61b..d775cc30d 100644 --- a/cli/command_cache_clear.go +++ b/cli/command_cache_clear.go @@ -25,11 +25,11 @@ func runCacheClearCommand(ctx context.Context, rep *repo.DirectRepository) error return os.RemoveAll(d) }, retry.Always) if err != nil { - return err + return errors.Wrap(err, "error removing cache directory") } if err := os.MkdirAll(d, 0o700); err != nil { - return err + return errors.Wrap(err, "error creating cache directory") } log(ctx).Infof("Cache cleared.") diff --git a/cli/command_content_rm.go b/cli/command_content_rm.go index 4a352efd2..34d25aefb 100644 --- a/cli/command_content_rm.go +++ b/cli/command_content_rm.go @@ -3,6 +3,8 @@ package cli import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" ) @@ -17,7 +19,7 @@ func runContentRemoveCommand(ctx context.Context, rep *repo.DirectRepository) er for _, contentID := range toContentIDs(*contentRemoveIDs) { if err := rep.Content.DeleteContent(ctx, contentID); err != nil { - return err + return errors.Wrapf(err, "error deleting content %v", contentID) } } diff --git a/cli/command_content_show.go b/cli/command_content_show.go index 63a86d1c3..f02ffbd81 100644 --- a/cli/command_content_show.go +++ b/cli/command_content_show.go @@ -4,6 +4,8 @@ import ( "bytes" "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/content" ) @@ -27,7 +29,7 @@ func runContentShowCommand(ctx context.Context, rep *repo.DirectRepository) erro func contentShow(ctx context.Context, r *repo.DirectRepository, contentID content.ID) error { data, err := r.Content.GetContent(ctx, contentID) if err != nil { - return err + return errors.Wrapf(err, "error getting content %v", contentID) } return showContent(bytes.NewReader(data)) diff --git a/cli/command_content_stats.go b/cli/command_content_stats.go index d39f37a38..8d49873e2 100644 --- a/cli/command_content_stats.go +++ b/cli/command_content_stats.go @@ -5,6 +5,8 @@ import ( "fmt" "strconv" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/units" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/content" @@ -47,7 +49,7 @@ func runContentStatsCommand(ctx context.Context, rep *repo.DirectRepository) err } return nil }); err != nil { - return err + return errors.Wrap(err, "error iterating contents") } sizeToString := units.BytesStringBase10 diff --git a/cli/command_diff.go b/cli/command_diff.go index 91ed14cc4..6129f696a 100644 --- a/cli/command_diff.go +++ b/cli/command_diff.go @@ -24,12 +24,12 @@ var ( func runDiffCommand(ctx context.Context, rep repo.Repository) error { ent1, err := snapshotfs.FilesystemEntryFromIDWithPath(ctx, rep, *diffFirstObjectPath, false) if err != nil { - return err + return errors.Wrapf(err, "error getting filesystem entry for %v", *diffFirstObjectPath) } ent2, err := snapshotfs.FilesystemEntryFromIDWithPath(ctx, rep, *diffSecondObjectPath, false) if err != nil { - return err + return errors.Wrapf(err, "error getting filesystem entry for %v", *diffSecondObjectPath) } _, isDir1 := ent1.(fs.Directory) @@ -41,7 +41,7 @@ func runDiffCommand(ctx context.Context, rep repo.Repository) error { d, err := diff.NewComparer(os.Stdout) if err != nil { - return err + return errors.Wrap(err, "error creating comparer") } defer d.Close() //nolint:errcheck diff --git a/cli/command_index_list.go b/cli/command_index_list.go index 1e280493c..8ef7d2fd8 100644 --- a/cli/command_index_list.go +++ b/cli/command_index_list.go @@ -5,6 +5,8 @@ import ( "fmt" "sort" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" ) @@ -18,7 +20,7 @@ var ( func runListBlockIndexesAction(ctx context.Context, rep *repo.DirectRepository) error { blks, err := rep.Content.IndexBlobs(ctx, *blockIndexListIncludeSuperseded) if err != nil { - return err + return errors.Wrap(err, "error listing index blobs") } switch *blockIndexListSort { diff --git a/cli/command_ls.go b/cli/command_ls.go index 153e32eea..1196fdec6 100644 --- a/cli/command_ls.go +++ b/cli/command_ls.go @@ -6,6 +6,8 @@ import ( "os" "strings" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/object" @@ -25,7 +27,7 @@ var ( func runLSCommand(ctx context.Context, rep repo.Repository) error { dir, err := snapshotfs.FilesystemDirectoryFromIDWithPath(ctx, rep, *lsCommandPath, false) if err != nil { - return err + return errors.Wrap(err, "unable to get filesystem directory entry") } var prefix string @@ -46,12 +48,12 @@ func init() { func listDirectory(ctx context.Context, d fs.Directory, prefix, indent string) error { entries, err := d.Readdir(ctx) if err != nil { - return err + return errors.Wrap(err, "error reading directory") } for _, e := range entries { if err := printDirectoryEntry(ctx, e, prefix, indent); err != nil { - return err + return errors.Wrap(err, "unable to print directory entry") } } diff --git a/cli/command_manifest_ls.go b/cli/command_manifest_ls.go index 79d63c4cd..334da6883 100644 --- a/cli/command_manifest_ls.go +++ b/cli/command_manifest_ls.go @@ -35,7 +35,7 @@ func listManifestItems(ctx context.Context, rep repo.Repository) error { items, err := rep.FindManifests(ctx, filter) if err != nil { - return err + return errors.Wrap(err, "unable to find manifests") } sort.Slice(items, func(i, j int) bool { diff --git a/cli/command_manifest_rm.go b/cli/command_manifest_rm.go index cfbb07067..4c2bc7aac 100644 --- a/cli/command_manifest_rm.go +++ b/cli/command_manifest_rm.go @@ -3,6 +3,8 @@ package cli import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" ) @@ -16,7 +18,7 @@ func runManifestRemoveCommand(ctx context.Context, rep repo.Repository) error { for _, it := range toManifestIDs(*manifestRemoveItems) { if err := rep.DeleteManifest(ctx, it); err != nil { - return err + return errors.Wrapf(err, "unable to delete manifest %v", it) } } diff --git a/cli/command_mount.go b/cli/command_mount.go index 4e3f7b796..59ffaa20f 100644 --- a/cli/command_mount.go +++ b/cli/command_mount.go @@ -35,7 +35,7 @@ func runMountCommand(ctx context.Context, rep repo.Repository) error { var err error entry, err = snapshotfs.FilesystemDirectoryFromIDWithPath(ctx, rep, *mountObjectID, false) if err != nil { - return err + return errors.Wrapf(err, "unable to get directory entry for %v", *mountObjectID) } } @@ -83,7 +83,7 @@ func runMountCommand(ctx context.Context, rep repo.Repository) error { // "unmount error: exit status 1: fusermount: failed to unmount /tmp/kopia-mount719819963: Device or resource busy, try --help" err := ctrl.Unmount(ctx) if err != nil { - return err + return errors.Wrap(err, "unmount error") } case <-ctrl.Done(): diff --git a/cli/command_policy.go b/cli/command_policy.go index 0d981e276..5f045b5f5 100644 --- a/cli/command_policy.go +++ b/cli/command_policy.go @@ -33,7 +33,7 @@ func policyTargets(ctx context.Context, rep repo.Repository, globalFlag *bool, t target, err := snapshot.ParseSourceInfo(ts, rep.ClientOptions().Hostname, rep.ClientOptions().Username) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to parse source info: %q", ts) } res = append(res, target) diff --git a/cli/command_policy_edit.go b/cli/command_policy_edit.go index 0c497f56a..c118e61c1 100644 --- a/cli/command_policy_edit.go +++ b/cli/command_policy_edit.go @@ -86,7 +86,7 @@ func editPolicy(ctx context.Context, rep repo.Repository) error { d.DisallowUnknownFields() return d.Decode(updated) }); err != nil { - return err + return errors.Wrap(err, "unable to launch editor") } if jsonEqual(updated, original) { diff --git a/cli/command_policy_ls.go b/cli/command_policy_ls.go index b321820fd..c7e285295 100644 --- a/cli/command_policy_ls.go +++ b/cli/command_policy_ls.go @@ -5,6 +5,8 @@ import ( "fmt" "sort" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot/policy" ) @@ -18,7 +20,7 @@ func init() { func listPolicies(ctx context.Context, rep repo.Repository) error { policies, err := policy.ListPolicies(ctx, rep) if err != nil { - return err + return errors.Wrap(err, "error listing policies") } sort.Slice(policies, func(i, j int) bool { diff --git a/cli/command_policy_remove.go b/cli/command_policy_remove.go index daf32b40d..70b30ade6 100644 --- a/cli/command_policy_remove.go +++ b/cli/command_policy_remove.go @@ -3,6 +3,8 @@ package cli import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot/policy" ) @@ -32,7 +34,7 @@ func removePolicy(ctx context.Context, rep repo.Repository) error { } if err := policy.RemovePolicy(ctx, rep, target); err != nil { - return err + return errors.Wrapf(err, "error removing policy on %v", target) } } diff --git a/cli/command_policy_set_actions.go b/cli/command_policy_set_actions.go index b65137df3..a166a7f61 100644 --- a/cli/command_policy_set_actions.go +++ b/cli/command_policy_set_actions.go @@ -70,7 +70,7 @@ func setActionCommandFromFlags(ctx context.Context, actionName string, cmd **pol if *policySetPersistActionScript { script, err := ioutil.ReadFile(value) //nolint:gosec if err != nil { - return err + return errors.Wrap(err, "unable to read script file") } if len(script) > maxScriptLength { diff --git a/cli/command_repository_connect.go b/cli/command_repository_connect.go index 64460c55b..4c866aade 100644 --- a/cli/command_repository_connect.go +++ b/cli/command_repository_connect.go @@ -78,7 +78,7 @@ func runConnectCommandWithStorage(ctx context.Context, st blob.Storage) error { func runConnectCommandWithStorageAndPassword(ctx context.Context, st blob.Storage, password string) error { configFile := repositoryConfigFileName() if err := repo.Connect(ctx, configFile, st, password, connectOptions()); err != nil { - return err + return errors.Wrap(err, "error connecting to repository") } log(ctx).Infof("Connected to repository.") diff --git a/cli/command_repository_connect_server.go b/cli/command_repository_connect_server.go index d632f9ee0..9e68b414b 100644 --- a/cli/command_repository_connect_server.go +++ b/cli/command_repository_connect_server.go @@ -29,7 +29,7 @@ func runConnectAPIServerCommand(ctx context.Context) error { configFile := repositoryConfigFileName() if err := repo.ConnectAPIServer(ctx, configFile, as, password, connectOptions()); err != nil { - return err + return errors.Wrap(err, "error connecting to API server") } log(ctx).Infof("Connected to repository API Server.") diff --git a/cli/command_repository_create.go b/cli/command_repository_create.go index afa425914..3946f9204 100644 --- a/cli/command_repository_create.go +++ b/cli/command_repository_create.go @@ -47,13 +47,15 @@ func ensureEmpty(ctx context.Context, s blob.Storage) error { hasDataError := errors.Errorf("has data") err := s.ListBlobs(ctx, "", func(cb blob.Metadata) error { + // nolint:wrapcheck return hasDataError }) - if err == hasDataError { //nolint:goerr113 + + if errors.Is(err, hasDataError) { return errors.New("found existing data in storage location") } - return err + return errors.Wrap(err, "error listing blobs") } func runCreateCommandWithStorage(ctx context.Context, st blob.Storage) error { diff --git a/cli/command_repository_repair.go b/cli/command_repository_repair.go index 1ee69324d..e451adbfe 100644 --- a/cli/command_repository_repair.go +++ b/cli/command_repository_repair.go @@ -68,24 +68,26 @@ func recoverFormatBlob(ctx context.Context, st blob.Storage, prefixes []string) if b, err := repo.RecoverFormatBlob(ctx, st, bi.BlobID, bi.Length); err == nil { if !*repairDryDrun { if puterr := st.PutBlob(ctx, repo.FormatBlobID, gather.FromSlice(b)); puterr != nil { - return puterr + return errors.Wrap(puterr, "error writing format blob") } } log(ctx).Infof("recovered replica block from %v", bi.BlobID) + + // nolint:wrapcheck return errSuccess } return nil }) - switch err { - case errSuccess: - return nil - case nil: + switch { + case err == nil: // do nothing + case errors.Is(err, errSuccess): + return nil default: - return err + return errors.Wrap(err, "unexpected error when listing blobs") } } diff --git a/cli/command_repository_status.go b/cli/command_repository_status.go index b63a63202..466a0b06f 100644 --- a/cli/command_repository_status.go +++ b/cli/command_repository_status.go @@ -68,7 +68,7 @@ func runStatusCommand(ctx context.Context, rep repo.Repository) error { tok, err := dr.Token(pass) if err != nil { - return err + return errors.Wrap(err, "error computing repository token") } fmt.Printf("\nTo reconnect to the repository use:\n\n$ kopia repository connect from-config --token %v\n\n", tok) diff --git a/cli/command_repository_sync.go b/cli/command_repository_sync.go index fee790f12..8ea36f5c3 100644 --- a/cli/command_repository_sync.go +++ b/cli/command_repository_sync.go @@ -92,7 +92,7 @@ func runSyncWithStorage(ctx context.Context, src, dst blob.Storage) error { return nil }); err != nil { - return err + return errors.Wrap(err, "error listing blobs") } finishSyncProcess() @@ -296,7 +296,7 @@ func syncDeleteBlob(ctx context.Context, m blob.Metadata, dst blob.Storage) erro return nil } - return err + return errors.Wrap(err, "error deleting blob") } func ensureRepositoriesHaveSameFormatBlob(ctx context.Context, src, dst blob.Storage) error { diff --git a/cli/command_restore.go b/cli/command_restore.go index f64ad9a68..6da830e5d 100644 --- a/cli/command_restore.go +++ b/cli/command_restore.go @@ -91,7 +91,7 @@ func addRestoreFlags(cmd *kingpin.CmdClause) { func restoreOutput(ctx context.Context) (restore.Output, error) { p, err := filepath.Abs(restoreTargetPath) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to resolve path") } m := detectRestoreMode(ctx, restoreMode) @@ -214,7 +214,7 @@ func runRestoreCommand(ctx context.Context, rep repo.Repository) error { }, }) if err != nil { - return err + return errors.Wrap(err, "error restoring") } printRestoreStats(ctx, st) diff --git a/cli/command_server_start.go b/cli/command_server_start.go index c0792842e..a77effe20 100644 --- a/cli/command_server_start.go +++ b/cli/command_server_start.go @@ -198,7 +198,7 @@ func requireCredentials(handler http.Handler) (*http.ServeMux, error) { case *serverStartHtpasswdFile != "": f, err := htpasswd.New(*serverStartHtpasswdFile, htpasswd.DefaultSystems, nil) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error initializing htpasswd") } handler = requireAuth{inner: handler, htpasswdFile: f} diff --git a/cli/command_server_status.go b/cli/command_server_status.go index 16e8372fc..bd0a6b007 100644 --- a/cli/command_server_status.go +++ b/cli/command_server_status.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/apiclient" "github.com/kopia/kopia/internal/serverapi" ) @@ -17,7 +19,7 @@ func init() { func runServerStatus(ctx context.Context, cli *apiclient.KopiaAPIClient) error { var status serverapi.SourcesResponse if err := cli.Get(ctx, "sources", nil, &status); err != nil { - return err + return errors.Wrap(err, "unable to list sources") } for _, src := range status.Sources { diff --git a/cli/command_server_upload.go b/cli/command_server_upload.go index 6d62d5581..974f21a56 100644 --- a/cli/command_server_upload.go +++ b/cli/command_server_upload.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/apiclient" "github.com/kopia/kopia/internal/serverapi" ) @@ -22,7 +24,7 @@ func triggerActionOnMatchingSources(ctx context.Context, cli *apiclient.KopiaAPI var resp serverapi.MultipleSourceActionResponse if err := cli.Post(ctx, path, &serverapi.Empty{}, &resp); err != nil { - return err + return errors.Wrapf(err, "unable to start upload on %v", path) } for src, resp := range resp.Sources { diff --git a/cli/command_show.go b/cli/command_show.go index e5b8d8bf5..88f01ccdc 100644 --- a/cli/command_show.go +++ b/cli/command_show.go @@ -4,6 +4,8 @@ import ( "context" "os" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/iocopy" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot/snapshotfs" @@ -17,19 +19,19 @@ var ( func runCatCommand(ctx context.Context, rep repo.Repository) error { oid, err := snapshotfs.ParseObjectIDWithPath(ctx, rep, *catCommandPath) if err != nil { - return err + return errors.Wrapf(err, "unable to parse ID: %v", *catCommandPath) } r, err := rep.OpenObject(ctx, oid) if err != nil { - return err + return errors.Wrapf(err, "error opening object %v", oid) } defer r.Close() //nolint:errcheck _, err = iocopy.Copy(os.Stdout, r) - return err + return errors.Wrap(err, "unable to copy data") } func init() { diff --git a/cli/command_snapshot_create.go b/cli/command_snapshot_create.go index 7e8043188..8a8149fc6 100644 --- a/cli/command_snapshot_create.go +++ b/cli/command_snapshot_create.go @@ -176,7 +176,7 @@ func snapshotSingleSource(ctx context.Context, rep repo.Repository, u *snapshotf manifest, err := u.Upload(ctx, localEntry, policyTree, sourceInfo, previous...) if err != nil { - return err + return errors.Wrap(err, "upload error") } manifest.Description = *snapshotCreateDescription @@ -230,7 +230,7 @@ func snapshotSingleSource(ctx context.Context, rep repo.Repository, u *snapshotf log(ctx).Infof("Created%v snapshot with root %v and ID %v in %v", maybePartial, manifest.RootObjectID(), snapID, clock.Since(t0).Truncate(time.Second)) - return err + return errors.Wrap(err, "error snapshotting") } // findPreviousSnapshotManifest returns the list of previous snapshots for a given source, including diff --git a/cli/command_snapshot_delete.go b/cli/command_snapshot_delete.go index ba71dcf9c..04949767b 100644 --- a/cli/command_snapshot_delete.go +++ b/cli/command_snapshot_delete.go @@ -52,7 +52,7 @@ func deleteSnapshot(ctx context.Context, rep repo.Repository, m *snapshot.Manife func deleteSnapshotsByRootObjectID(ctx context.Context, rep repo.Repository, rootID object.ID) error { manifests, err := snapshot.FindSnapshotsByRootObjectID(ctx, rep, rootID) if err != nil { - return err + return errors.Wrapf(err, "unable to find snapshots by root %v", rootID) } if len(manifests) == 0 { diff --git a/cli/command_snapshot_estimate.go b/cli/command_snapshot_estimate.go index d21b445cb..0d506364e 100644 --- a/cli/command_snapshot_estimate.go +++ b/cli/command_snapshot_estimate.go @@ -103,7 +103,7 @@ func runSnapshotEstimateCommand(ctx context.Context, rep repo.Repository) error if dir, ok := entry.(fs.Directory); ok { policyTree, err := policy.TreeForSource(ctx, rep, sourceInfo) if err != nil { - return err + return errors.Wrapf(err, "error creating policy tree for %v", sourceInfo) } entry = ignorefs.New(dir, policyTree, ignorefs.ReportIgnoredFiles(onIgnoredFile)) @@ -154,7 +154,7 @@ func estimate(ctx context.Context, relativePath string, entry fs.Entry, stats *s children, err := entry.Readdir(ctx) if err != nil { - return err + return errors.Wrap(err, "unable to read directory") } for _, child := range children { diff --git a/cli/command_snapshot_expire.go b/cli/command_snapshot_expire.go index 91ee818bd..3465f85e9 100644 --- a/cli/command_snapshot_expire.go +++ b/cli/command_snapshot_expire.go @@ -4,6 +4,8 @@ import ( "context" "sort" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot" "github.com/kopia/kopia/snapshot/policy" @@ -27,7 +29,7 @@ func getSnapshotSourcesToExpire(ctx context.Context, rep repo.Repository) ([]sna for _, p := range *snapshotExpirePaths { src, err := snapshot.ParseSourceInfo(p, rep.ClientOptions().Hostname, rep.ClientOptions().Username) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to parse %q", p) } result = append(result, src) @@ -49,7 +51,7 @@ func runExpireCommand(ctx context.Context, rep repo.Repository) error { for _, src := range sources { deleted, err := policy.ApplyRetentionPolicy(ctx, rep, src, *snapshotExpireDelete) if err != nil { - return err + return errors.Wrapf(err, "error applying retention policy to %v", src) } if len(deleted) == 0 { diff --git a/cli/command_snapshot_gc.go b/cli/command_snapshot_gc.go index 68867d02d..0db27aac8 100644 --- a/cli/command_snapshot_gc.go +++ b/cli/command_snapshot_gc.go @@ -3,6 +3,8 @@ package cli import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/units" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/repo/maintenance" @@ -25,7 +27,7 @@ func runSnapshotGCCommand(ctx context.Context, rep *repo.DirectRepository) error log(ctx).Infof("GC found %v in-use contents (%v bytes)", st.InUseCount, units.BytesStringBase2(st.InUseBytes)) log(ctx).Infof("GC found %v in-use system-contents (%v bytes)", st.SystemCount, units.BytesStringBase2(st.SystemBytes)) - return err + return errors.Wrap(err, "error running snapshot GC") } func init() { diff --git a/cli/command_snapshot_list.go b/cli/command_snapshot_list.go index 223f510bd..49a5f535a 100644 --- a/cli/command_snapshot_list.go +++ b/cli/command_snapshot_list.go @@ -39,7 +39,7 @@ func findSnapshotsForSource(ctx context.Context, rep repo.Repository, sourceInfo for len(sourceInfo.Path) > 0 { list, err := snapshot.ListSnapshotManifests(ctx, rep, &sourceInfo) if err != nil { - return nil, "", err + return nil, "", errors.Wrapf(err, "error listing manifests for %v", sourceInfo) } if len(list) > 0 { @@ -68,7 +68,7 @@ func findSnapshotsForSource(ctx context.Context, rep repo.Repository, sourceInfo func findManifestIDs(ctx context.Context, rep repo.Repository, source string) ([]manifest.ID, string, error) { if source == "" { man, err := snapshot.ListSnapshotManifests(ctx, rep, nil) - return man, "", err + return man, "", errors.Wrap(err, "error listing all snapshot manifests") } si, err := snapshot.ParseSourceInfo(source, rep.ClientOptions().Hostname, rep.ClientOptions().Username) @@ -92,7 +92,7 @@ func runSnapshotsCommand(ctx context.Context, rep repo.Repository) error { manifests, err := snapshot.LoadSnapshots(ctx, rep, manifestIDs) if err != nil { - return err + return errors.Wrap(err, "unable to load snapshots") } return outputManifestGroups(ctx, rep, manifests, strings.Split(relPath, "/")) diff --git a/cli/command_snapshot_migrate.go b/cli/command_snapshot_migrate.go index f1eb211de..e9c5cd4d8 100644 --- a/cli/command_snapshot_migrate.go +++ b/cli/command_snapshot_migrate.go @@ -201,7 +201,7 @@ func findPreviousSnapshotManifestWithStartTime(ctx context.Context, rep repo.Rep func migrateSingleSource(ctx context.Context, uploader *snapshotfs.Uploader, sourceRepo, destRepo repo.Repository, s snapshot.SourceInfo) error { manifests, err := snapshot.ListSnapshotManifests(ctx, sourceRepo, &s) if err != nil { - return err + return errors.Wrapf(err, "error listing snapshot manifests for %v", s) } snapshots, err := snapshot.LoadSnapshots(ctx, sourceRepo, manifests) @@ -234,7 +234,7 @@ func migrateSingleSourceSnapshot(ctx context.Context, uploader *snapshotfs.Uploa sourceEntry, err := snapshotfs.SnapshotRoot(sourceRepo, m) if err != nil { - return err + return errors.Wrap(err, "error getting snapshot root entry") } existing, err := findPreviousSnapshotManifestWithStartTime(ctx, destRepo, m.Source, m.StartTime) @@ -289,7 +289,7 @@ func getSourcesToMigrate(ctx context.Context, rep repo.Repository) ([]snapshot.S for _, s := range *migrateSources { si, err := snapshot.ParseSourceInfo(s, rep.ClientOptions().Hostname, rep.ClientOptions().Username) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to parse %q", s) } result = append(result, si) diff --git a/cli/command_snapshot_verify.go b/cli/command_snapshot_verify.go index 1caf17592..a967b0f75 100644 --- a/cli/command_snapshot_verify.go +++ b/cli/command_snapshot_verify.go @@ -188,13 +188,13 @@ func (v *verifier) readEntireObject(ctx context.Context, oid object.ID, path str // also read the entire file r, err := v.rep.OpenObject(ctx, oid) if err != nil { - return err + return errors.Wrapf(err, "unable to open object %v", oid) } defer r.Close() //nolint:errcheck _, err = iocopy.Copy(ioutil.Discard, r) - return err + return errors.Wrap(err, "unable to read data") } func runVerifyCommand(ctx context.Context, rep repo.Repository) error { @@ -257,7 +257,7 @@ func enqueueRootsToVerify(ctx context.Context, v *verifier, rep repo.Repository) for _, oidStr := range *verifyCommandDirObjectIDs { oid, err := snapshotfs.ParseObjectIDWithPath(ctx, rep, oidStr) if err != nil { - return err + return errors.Wrapf(err, "unable to parse: %q", oidStr) } v.enqueueVerifyDirectory(ctx, oid, oidStr) @@ -266,7 +266,7 @@ func enqueueRootsToVerify(ctx context.Context, v *verifier, rep repo.Repository) for _, oidStr := range *verifyCommandFileObjectIDs { oid, err := snapshotfs.ParseObjectIDWithPath(ctx, rep, oidStr) if err != nil { - return err + return errors.Wrapf(err, "unable to parse %q", oidStr) } v.enqueueVerifyObject(ctx, oid, oidStr) @@ -281,7 +281,7 @@ func loadSourceManifests(ctx context.Context, rep repo.Repository, sources []str if len(sources)+len(*verifyCommandDirObjectIDs)+len(*verifyCommandFileObjectIDs) == 0 { man, err := snapshot.ListSnapshotManifests(ctx, rep, nil) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to list snapshot manifests") } manifestIDs = append(manifestIDs, man...) @@ -293,7 +293,7 @@ func loadSourceManifests(ctx context.Context, rep repo.Repository, sources []str } man, err := snapshot.ListSnapshotManifests(ctx, rep, &src) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to list snapshot manifests for %v", src) } manifestIDs = append(manifestIDs, man...) } diff --git a/cli/config.go b/cli/config.go index 821d24569..e88845bb1 100644 --- a/cli/config.go +++ b/cli/config.go @@ -67,7 +67,7 @@ func openRepository(ctx context.Context, opts *repo.Options, required bool) (rep return nil, errors.New("not connected to a repository, use 'kopia connect'") } - return r, err + return r, errors.Wrap(err, "unable to open repository") } func applyOptionsFromFlags(ctx context.Context, opts *repo.Options) *repo.Options { diff --git a/cli/password.go b/cli/password.go index 52f219307..fd93f9052 100644 --- a/cli/password.go +++ b/cli/password.go @@ -74,7 +74,7 @@ func askPass(prompt string) (string, error) { for i := 0; i < 5; i++ { p, err := speakeasy.Ask(prompt) if err != nil { - return "", err + return "", errors.Wrap(err, "password prompt error") } if p == "" { diff --git a/cli/show_utils.go b/cli/show_utils.go index a5f4ebf00..29a866ad0 100644 --- a/cli/show_utils.go +++ b/cli/show_utils.go @@ -47,18 +47,18 @@ func showContentWithFlags(rd io.Reader, unzip, indentJSON bool) error { if indentJSON { if _, err := iocopy.Copy(&buf1, rd); err != nil { - return err + return errors.Wrap(err, "error copying data") } if err := json.Indent(&buf2, buf1.Bytes(), "", " "); err != nil { - return err + return errors.Wrap(err, "errors indenting JSON") } rd = ioutil.NopCloser(&buf2) } if _, err := iocopy.Copy(os.Stdout, rd); err != nil { - return err + return errors.Wrap(err, "error copying data") } return nil diff --git a/cli/storage_gcs.go b/cli/storage_gcs.go index c7c14b23a..dd7e9305c 100644 --- a/cli/storage_gcs.go +++ b/cli/storage_gcs.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "github.com/alecthomas/kingpin" + "github.com/pkg/errors" "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/blob/gcs" @@ -32,7 +33,7 @@ func init() { if embedCredentials { data, err := ioutil.ReadFile(options.ServiceAccountCredentialsFile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to open service account credentials file") } options.ServiceAccountCredentialJSON = json.RawMessage(data) diff --git a/cli/storage_rclone.go b/cli/storage_rclone.go index c801595f0..54338352a 100644 --- a/cli/storage_rclone.go +++ b/cli/storage_rclone.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "github.com/alecthomas/kingpin" + "github.com/pkg/errors" "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/blob/rclone" @@ -36,7 +37,7 @@ func init() { if embedRCloneConfigFile != "" { cfg, err := ioutil.ReadFile(embedRCloneConfigFile) //nolint:gosec if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to read rclone config file") } opt.EmbeddedConfig = string(cfg) diff --git a/cli/storage_sftp.go b/cli/storage_sftp.go index b6b200768..7ae15dce7 100644 --- a/cli/storage_sftp.go +++ b/cli/storage_sftp.go @@ -47,7 +47,7 @@ func init() { if sftpo.KeyData == "" { d, err := ioutil.ReadFile(sftpo.Keyfile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to read key file") } sftpo.KeyData = string(d) @@ -57,7 +57,7 @@ func init() { if sftpo.KnownHostsData == "" && sftpo.KnownHostsFile != "" { d, err := ioutil.ReadFile(sftpo.KnownHostsFile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to read known hosts file") } sftpo.KnownHostsData = string(d) diff --git a/fs/cachefs/cache_test.go b/fs/cachefs/cache_test.go index 662706071..250130cf5 100644 --- a/fs/cachefs/cache_test.go +++ b/fs/cachefs/cache_test.go @@ -2,7 +2,6 @@ package cachefs import ( "context" - "errors" "fmt" "path/filepath" "reflect" @@ -12,6 +11,8 @@ import ( "testing" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/internal/testlogging" ) diff --git a/fs/cachefs/cachefs.go b/fs/cachefs/cachefs.go index e0c2a036e..5147513b2 100644 --- a/fs/cachefs/cachefs.go +++ b/fs/cachefs/cachefs.go @@ -24,6 +24,7 @@ type directory struct { func (d *directory) Child(ctx context.Context, name string) (fs.Entry, error) { e, err := d.Directory.Child(ctx, name) if err != nil { + // nolint:wrapcheck return nil, err } @@ -33,6 +34,7 @@ func (d *directory) Child(ctx context.Context, name string) (fs.Entry, error) { func (d *directory) Readdir(ctx context.Context) (fs.Entries, error) { entries, err := d.ctx.cacher.Readdir(ctx, d.Directory) if err != nil { + // nolint:wrapcheck return entries, err } @@ -41,6 +43,7 @@ func (d *directory) Readdir(ctx context.Context) (fs.Entries, error) { wrapped[i] = wrapWithContext(entry, d.ctx) } + // nolint:wrapcheck return wrapped, err } diff --git a/fs/entry.go b/fs/entry.go index 8f1b70715..f557b553d 100644 --- a/fs/entry.go +++ b/fs/entry.go @@ -2,11 +2,12 @@ package fs import ( "context" - "errors" "io" "os" "sort" "time" + + "github.com/pkg/errors" ) // Entry represents a filesystem entry, which can be Directory, File, or Symlink. @@ -66,11 +67,12 @@ var ErrEntryNotFound = errors.New("entry not found") func ReadDirAndFindChild(ctx context.Context, d Directory, name string) (Entry, error) { children, err := d.Readdir(ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading directory") } e := children.FindByName(name) if e == nil { + // nolint:wrapcheck return nil, ErrEntryNotFound } diff --git a/fs/ignorefs/ignorefs.go b/fs/ignorefs/ignorefs.go index ab6cd904f..103b5aca1 100644 --- a/fs/ignorefs/ignorefs.go +++ b/fs/ignorefs/ignorefs.go @@ -78,7 +78,7 @@ func isCorrectCacheDirSignature(ctx context.Context, f fs.File) (bool, error) { r, err := f.Open(ctx) if err != nil { - return false, err + return false, errors.Wrap(err, "unable to open cache dir marker file") } defer r.Close() //nolint:errcheck @@ -86,7 +86,7 @@ func isCorrectCacheDirSignature(ctx context.Context, f fs.File) (bool, error) { sig := make([]byte, validSignatureLen) if _, err := r.Read(sig); err != nil { - return false, err + return false, errors.Wrap(err, "unable to read cache dir marker file") } return string(sig) == validSignature, nil @@ -121,6 +121,7 @@ func (d *ignoreDirectory) skipCacheDirectory(ctx context.Context, entries fs.Ent func (d *ignoreDirectory) Readdir(ctx context.Context) (fs.Entries, error) { entries, err := d.Directory.Readdir(ctx) if err != nil { + // nolint:wrapcheck return nil, err } diff --git a/fs/localfs/local_fs.go b/fs/localfs/local_fs.go index 15102aac8..9d3708adb 100644 --- a/fs/localfs/local_fs.go +++ b/fs/localfs/local_fs.go @@ -137,7 +137,7 @@ func (fsd *filesystemDirectory) Readdir(ctx context.Context) (fs.Entries, error) f, direrr := os.Open(fullPath) //nolint:gosec if direrr != nil { - return nil, direrr + return nil, errors.Wrap(direrr, "unable to read directory") } defer f.Close() //nolint:errcheck,gosec @@ -159,7 +159,7 @@ func (fsd *filesystemDirectory) Readdir(ctx context.Context) (fs.Entries, error) continue } - if err == io.EOF { + if errors.Is(err, io.EOF) { break } @@ -239,7 +239,7 @@ type fileWithMetadata struct { func (f *fileWithMetadata) Entry() (fs.Entry, error) { fi, err := f.Stat() if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to stat() local file") } return &filesystemFile{newEntry(fi, filepath.Dir(f.Name()))}, nil @@ -248,7 +248,7 @@ func (f *fileWithMetadata) Entry() (fs.Entry, error) { func (fsf *filesystemFile) Open(ctx context.Context) (fs.Reader, error) { f, err := os.Open(fsf.fullPath()) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to open local file") } return &fileWithMetadata{f}, nil @@ -262,7 +262,7 @@ func (fsl *filesystemSymlink) Readlink(ctx context.Context) (string, error) { func NewEntry(path string) (fs.Entry, error) { fi, err := os.Lstat(path) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to determine entry type") } switch fi.Mode() & os.ModeType { diff --git a/fs/localfs/local_fs_test.go b/fs/localfs/local_fs_test.go index cdfd52a20..aa7ad15a3 100644 --- a/fs/localfs/local_fs_test.go +++ b/fs/localfs/local_fs_test.go @@ -7,6 +7,8 @@ import ( "path/filepath" "testing" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/internal/clock" "github.com/kopia/kopia/internal/testlogging" @@ -108,7 +110,7 @@ func verifyChild(t *testing.T, dir fs.Directory) { t.Errorf("child error: %v", err) } - if _, err = dir.Child(ctx, "f4"); err != fs.ErrEntryNotFound { + if _, err = dir.Child(ctx, "f4"); !errors.Is(err, fs.ErrEntryNotFound) { t.Errorf("unexpected child error: %v", err) } @@ -120,7 +122,7 @@ func verifyChild(t *testing.T, dir fs.Directory) { t.Errorf("unexpected child size: %v, want %v", got, want) } - if _, err = fs.ReadDirAndFindChild(ctx, dir, "f4"); err != fs.ErrEntryNotFound { + if _, err = fs.ReadDirAndFindChild(ctx, dir, "f4"); !errors.Is(err, fs.ErrEntryNotFound) { t.Errorf("unexpected child error: %v", err) } diff --git a/fs/loggingfs/loggingfs.go b/fs/loggingfs/loggingfs.go index 5714a8bad..819d587a9 100644 --- a/fs/loggingfs/loggingfs.go +++ b/fs/loggingfs/loggingfs.go @@ -26,6 +26,7 @@ func (ld *loggingDirectory) Child(ctx context.Context, name string) (fs.Entry, e ld.options.printf(ld.options.prefix+"Child(%v) took %v and returned %v", ld.relativePath, dt, err) if err != nil { + // nolint:wrapcheck return nil, err } @@ -43,6 +44,7 @@ func (ld *loggingDirectory) Readdir(ctx context.Context) (fs.Entries, error) { loggingEntries[i] = wrapWithOptions(entry, ld.options, ld.relativePath+"/"+entry.Name()) } + // nolint:wrapcheck return loggingEntries, err } diff --git a/go.sum b/go.sum index 3c76af141..626b4f95d 100644 --- a/go.sum +++ b/go.sum @@ -814,6 +814,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03i golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/internal/apiclient/apiclient.go b/internal/apiclient/apiclient.go index ffb6276c1..4628a459e 100644 --- a/internal/apiclient/apiclient.go +++ b/internal/apiclient/apiclient.go @@ -51,12 +51,12 @@ func (c *KopiaAPIClient) Delete(ctx context.Context, urlSuffix string, reqPayloa func (c *KopiaAPIClient) runRequest(ctx context.Context, method, url string, notFoundError error, reqPayload, respPayload interface{}) error { payload, contentType, err := requestReader(reqPayload) if err != nil { - return err + return errors.Wrap(err, "error getting reader") } req, err := http.NewRequestWithContext(ctx, method, url, payload) if err != nil { - return err + return errors.Wrap(err, "error creating request") } if contentType != "" { @@ -65,7 +65,7 @@ func (c *KopiaAPIClient) runRequest(ctx context.Context, method, url string, not resp, err := c.HTTPClient.Do(req) if err != nil { - return err + return errors.Wrap(err, "error running http request") } defer resp.Body.Close() //nolint:errcheck @@ -180,7 +180,7 @@ func (t loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) { resp, err := t.base.RoundTrip(req) if err != nil { log(req.Context()).Debugf("%v %v took %v and failed with %v", req.Method, req.URL, clock.Since(t0), err) - return nil, err + return nil, errors.Wrap(err, "round-trip error") } log(req.Context()).Debugf("%v %v took %v and returned %v", req.Method, req.URL, clock.Since(t0), resp.Status) diff --git a/internal/blobtesting/concurrent.go b/internal/blobtesting/concurrent.go index 45a36a8d4..b3fcba89e 100644 --- a/internal/blobtesting/concurrent.go +++ b/internal/blobtesting/concurrent.go @@ -64,13 +64,13 @@ func VerifyConcurrentAccess(t testingT, st blob.Storage, options ConcurrentAcces } data, err := st.GetBlob(ctx, blobID, offset, length) - switch err { - case nil: + switch { + case err == nil: if got, want := string(data), string(blobID); !strings.HasPrefix(got, want) { return errors.Wrapf(err, "GetBlob returned invalid data for %v: %v, want prefix of %v", blobID, got, want) } - case blob.ErrBlobNotFound: + case errors.Is(err, blob.ErrBlobNotFound): // clean error default: @@ -89,11 +89,7 @@ func VerifyConcurrentAccess(t testingT, st blob.Storage, options ConcurrentAcces blobID := randomBlobID() data := fmt.Sprintf("%v-%v", blobID, rand.Int63()) err := st.PutBlob(ctx, blobID, gather.FromSlice([]byte(data))) - switch err { - case nil: - // clean success - - default: + if err != nil { return errors.Wrapf(err, "PutBlob %v returned unexpected error", blobID) } } @@ -108,11 +104,11 @@ func VerifyConcurrentAccess(t testingT, st blob.Storage, options ConcurrentAcces for i := 0; i < options.Iterations; i++ { blobID := randomBlobID() err := st.DeleteBlob(ctx, blobID) - switch err { - case nil: + switch { + case err == nil: // clean success - case blob.ErrBlobNotFound: + case errors.Is(err, blob.ErrBlobNotFound): // clean error default: @@ -134,14 +130,9 @@ func VerifyConcurrentAccess(t testingT, st blob.Storage, options ConcurrentAcces prefix = "zzz" } - err := st.ListBlobs(ctx, prefix, func(blob.Metadata) error { + if err := st.ListBlobs(ctx, prefix, func(blob.Metadata) error { return nil - }) - switch err { - case nil: - // clean success - - default: + }); err != nil { return errors.Wrapf(err, "ListBlobs(%v) returned unexpected error", prefix) } } diff --git a/internal/diff/diff.go b/internal/diff/diff.go index 275ca05d4..b20f5819f 100644 --- a/internal/diff/diff.go +++ b/internal/diff/diff.go @@ -268,25 +268,25 @@ func (c *Comparer) compareFiles(ctx context.Context, f1, f2 fs.File, fname strin func downloadFile(ctx context.Context, f fs.File, fname string) error { if err := os.MkdirAll(filepath.Dir(fname), 0o700); err != nil { - return err + return errors.Wrap(err, "error making directory") } src, err := f.Open(ctx) if err != nil { - return err + return errors.Wrap(err, "error opening object") } defer src.Close() //nolint:errcheck dst, err := os.Create(fname) if err != nil { - return err + return errors.Wrap(err, "error creating file to edit") } defer dst.Close() //nolint:errcheck,gosec _, err = iocopy.Copy(dst, src) - return err + return errors.Wrap(err, "error downloading file") } func (c *Comparer) output(msg string, args ...interface{}) { @@ -297,7 +297,7 @@ func (c *Comparer) output(msg string, args ...interface{}) { func NewComparer(out io.Writer) (*Comparer, error) { tmp, err := ioutil.TempDir("", "kopia") if err != nil { - return nil, err + return nil, errors.Wrap(err, "error creating temp directory") } return &Comparer{out: out, tmpDir: tmp}, nil diff --git a/internal/editor/editor.go b/internal/editor/editor.go index c13705c6f..1368fb645 100644 --- a/internal/editor/editor.go +++ b/internal/editor/editor.go @@ -25,24 +25,24 @@ var log = logging.GetContextLoggerFunc("editor") func EditLoop(ctx context.Context, fname, initial string, parse func(updated string) error) error { tmpDir, err := ioutil.TempDir("", "kopia") if err != nil { - return err + return errors.Wrap(err, "unable to create temp directory") } tmpFile := filepath.Join(tmpDir, fname) defer os.RemoveAll(tmpDir) //nolint:errcheck if err := ioutil.WriteFile(tmpFile, []byte(initial), 0o600); err != nil { - return err + return errors.Wrap(err, "unable to write file to edit") } for { if err := editFile(ctx, tmpFile); err != nil { - return err + return errors.Wrap(err, "error launching editor") } txt, err := readAndStripComments(tmpFile) if err != nil { - return err + return errors.Wrap(err, "error parsing edited file") } err = parse(txt) @@ -66,7 +66,7 @@ func EditLoop(ctx context.Context, fname, initial string, parse func(updated str func readAndStripComments(fname string) (string, error) { f, err := os.Open(fname) //nolint:gosec if err != nil { - return "", err + return "", errors.Wrap(err, "error opening edited file") } defer f.Close() //nolint:errcheck,gosec @@ -101,7 +101,7 @@ func editFile(ctx context.Context, file string) error { err := cmd.Run() if err != nil { - log(ctx).Errorf("unable to launch editor: %v", err) + return errors.Wrap(err, "error running editor command") } return nil diff --git a/internal/fusemount/fusefs.go b/internal/fusemount/fusefs.go index 4b912fa0f..e22abad19 100644 --- a/internal/fusemount/fusefs.go +++ b/internal/fusemount/fusefs.go @@ -43,6 +43,7 @@ var _ fusefs.NodeOpener = (*fuseFileNode)(nil) func (f *fuseFileNode) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fusefs.Handle, error) { reader, err := f.entry.(fs.File).Open(ctx) if err != nil { + // nolint:wrapcheck return nil, err } @@ -61,11 +62,13 @@ func (f *fuseFileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp * _, err := f.reader.Seek(req.Offset, io.SeekStart) if err != nil { + // nolint:wrapcheck return err } n, err := f.reader.Read(resp.Data[:req.Size]) if err != nil { + // nolint:wrapcheck return err } @@ -86,6 +89,7 @@ var ( func (f *fuseFileNode) ReadAll(ctx context.Context) ([]byte, error) { reader, err := f.entry.(fs.File).Open(ctx) if err != nil { + // nolint:wrapcheck return nil, err } defer reader.Close() //nolint:errcheck @@ -108,6 +112,7 @@ func (dir *fuseDirectoryNode) Lookup(ctx context.Context, fileName string) (fuse return nil, fuse.ENOENT } + // nolint:wrapcheck return nil, err } @@ -122,6 +127,7 @@ func (dir *fuseDirectoryNode) Lookup(ctx context.Context, fileName string) (fuse func (dir *fuseDirectoryNode) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { entries, err := dir.directory().Readdir(ctx) if err != nil { + // nolint:wrapcheck return nil, err } diff --git a/internal/gather/gather_bytes.go b/internal/gather/gather_bytes.go index 5912ce47f..48e005bbd 100644 --- a/internal/gather/gather_bytes.go +++ b/internal/gather/gather_bytes.go @@ -116,6 +116,7 @@ func (b Bytes) WriteTo(w io.Writer) (int64, error) { totalN += int64(n) if err != nil { + // nolint:wrapcheck return totalN, err } } diff --git a/internal/mount/mount_fuse.go b/internal/mount/mount_fuse.go index def1a731c..46d1297aa 100644 --- a/internal/mount/mount_fuse.go +++ b/internal/mount/mount_fuse.go @@ -51,7 +51,7 @@ func Directory(ctx context.Context, entry fs.Directory, mountPoint string, mount mountPoint, err = ioutil.TempDir("", "kopia-mount") if err != nil { - return nil, err + return nil, errors.Wrap(err, "error creating temp directory") } isTempDir = true diff --git a/internal/mount/mount_net_use.go b/internal/mount/mount_net_use.go index 707e36b9b..e2f1e7df7 100644 --- a/internal/mount/mount_net_use.go +++ b/internal/mount/mount_net_use.go @@ -43,7 +43,7 @@ func netUse(ctx context.Context, args ...string) (string, error) { out, err := nu.Output() log(ctx).Debugf("net use finished with %v %v", string(out), err) - return string(out), err + return string(out), errors.Wrap(err, "error running 'net use'") } func netUseMount(ctx context.Context, driveLetter, webdavURL string) (string, error) { diff --git a/internal/retry/retry_test.go b/internal/retry/retry_test.go index 1369fb131..1a8d3eeca 100644 --- a/internal/retry/retry_test.go +++ b/internal/retry/retry_test.go @@ -12,7 +12,7 @@ import ( var errRetriable = errors.New("retriable") func isRetriable(e error) bool { - return e == errRetriable + return errors.Is(e, errRetriable) } func TestRetry(t *testing.T) { diff --git a/internal/server/api_content.go b/internal/server/api_content.go index 2584cfa42..852edbd35 100644 --- a/internal/server/api_content.go +++ b/internal/server/api_content.go @@ -37,11 +37,12 @@ func (s *Server) handleContentInfo(ctx context.Context, r *http.Request, body [] cid := content.ID(mux.Vars(r)["contentID"]) ci, err := dr.Content.ContentInfo(ctx, cid) - switch err { - case nil: + + switch { + case err == nil: return ci, nil - case content.ErrContentNotFound: + case errors.Is(err, content.ErrContentNotFound): return nil, notFoundError("content not found") default: diff --git a/internal/server/api_repo.go b/internal/server/api_repo.go index 5e22abc76..406fbfd7b 100644 --- a/internal/server/api_repo.go +++ b/internal/server/api_repo.go @@ -316,12 +316,12 @@ func (s *Server) handleRepoSync(ctx context.Context, r *http.Request, body []byt } func repoErrorToAPIError(err error) *apiError { - switch err { - case repo.ErrRepositoryNotInitialized: + switch { + case errors.Is(err, repo.ErrRepositoryNotInitialized): return requestError(serverapi.ErrorNotInitialized, "repository not initialized") - case repo.ErrInvalidPassword: + case errors.Is(err, repo.ErrInvalidPassword): return requestError(serverapi.ErrorInvalidPassword, "invalid password") - case repo.ErrAlreadyInitialized: + case errors.Is(err, repo.ErrAlreadyInitialized): return requestError(serverapi.ErrorAlreadyInitialized, "repository already initialized") default: return internalServerError(errors.Wrap(err, "connect error")) diff --git a/internal/server/api_sources.go b/internal/server/api_sources.go index fb13322e2..f06b84933 100644 --- a/internal/server/api_sources.go +++ b/internal/server/api_sources.go @@ -71,14 +71,15 @@ func (s *Server) handleSourcesCreate(ctx context.Context, r *http.Request, body // ensure we have the policy for this source, otherwise it will not show up in the // list of sources at all. _, err = policy.GetDefinedPolicy(ctx, s.rep, sourceInfo) - switch err { - case nil: + + switch { + case err == nil: // already have policy, do nothing log(ctx).Debugf("policy for %v already exists", sourceInfo) resp.Created = false - case policy.ErrPolicyNotFound: + case errors.Is(err, policy.ErrPolicyNotFound): resp.Created = true // don't have policy - create an empty one log(ctx).Debugf("policy for %v not found, creating empty one", sourceInfo) diff --git a/internal/serverapi/client_wrappers.go b/internal/serverapi/client_wrappers.go index 41536a312..e3b9ae417 100644 --- a/internal/serverapi/client_wrappers.go +++ b/internal/serverapi/client_wrappers.go @@ -4,6 +4,8 @@ import ( "context" "strings" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/apiclient" "github.com/kopia/kopia/repo/object" "github.com/kopia/kopia/snapshot" @@ -13,7 +15,7 @@ import ( func CreateSnapshotSource(ctx context.Context, c *apiclient.KopiaAPIClient, req *CreateSnapshotSourceRequest) (*CreateSnapshotSourceResponse, error) { resp := &CreateSnapshotSourceResponse{} if err := c.Post(ctx, "sources", req, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "CreateSnapshotSource") } return resp, nil @@ -23,7 +25,7 @@ func CreateSnapshotSource(ctx context.Context, c *apiclient.KopiaAPIClient, req func UploadSnapshots(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) (*MultipleSourceActionResponse, error) { resp := &MultipleSourceActionResponse{} if err := c.Post(ctx, "sources/upload"+matchSourceParameters(match), &Empty{}, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "UploadSnapshots") } return resp, nil @@ -33,7 +35,7 @@ func UploadSnapshots(ctx context.Context, c *apiclient.KopiaAPIClient, match *sn func CancelUpload(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) (*MultipleSourceActionResponse, error) { resp := &MultipleSourceActionResponse{} if err := c.Post(ctx, "sources/cancel"+matchSourceParameters(match), &Empty{}, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "CancelUpload") } return resp, nil @@ -63,7 +65,7 @@ func Shutdown(ctx context.Context, c *apiclient.KopiaAPIClient) { func Status(ctx context.Context, c *apiclient.KopiaAPIClient) (*StatusResponse, error) { resp := &StatusResponse{} if err := c.Get(ctx, "repo/status", nil, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "Status") } return resp, nil @@ -73,7 +75,7 @@ func Status(ctx context.Context, c *apiclient.KopiaAPIClient) (*StatusResponse, func ListSources(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) (*SourcesResponse, error) { resp := &SourcesResponse{} if err := c.Get(ctx, "sources"+matchSourceParameters(match), nil, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "ListSources") } return resp, nil @@ -83,7 +85,7 @@ func ListSources(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapsh func ListSnapshots(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) (*SnapshotsResponse, error) { resp := &SnapshotsResponse{} if err := c.Get(ctx, "snapshots"+matchSourceParameters(match), nil, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "ListSnapshots") } return resp, nil @@ -93,7 +95,7 @@ func ListSnapshots(ctx context.Context, c *apiclient.KopiaAPIClient, match *snap func ListPolicies(ctx context.Context, c *apiclient.KopiaAPIClient, match *snapshot.SourceInfo) (*PoliciesResponse, error) { resp := &PoliciesResponse{} if err := c.Get(ctx, "policies"+matchSourceParameters(match), nil, resp); err != nil { - return nil, err + return nil, errors.Wrap(err, "ListPolicies") } return resp, nil @@ -104,7 +106,7 @@ func GetObject(ctx context.Context, c *apiclient.KopiaAPIClient, objectID string var b []byte if err := c.Get(ctx, "objects/"+objectID, object.ErrObjectNotFound, &b); err != nil { - return nil, err + return nil, errors.Wrap(err, "GetObject") } return b, nil diff --git a/internal/throttle/round_tripper.go b/internal/throttle/round_tripper.go index f40a8f287..bfd995a61 100644 --- a/internal/throttle/round_tripper.go +++ b/internal/throttle/round_tripper.go @@ -4,6 +4,8 @@ package throttle import ( "io" "net/http" + + "github.com/pkg/errors" ) type throttlerPool interface { @@ -22,15 +24,20 @@ func (rt *throttlingRoundTripper) RoundTrip(req *http.Request) (*http.Response, req.Body, err = rt.uploadPool.AddReader(req.Body) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to attach request throttler") } } resp, err := rt.base.RoundTrip(req) + if resp != nil && resp.Body != nil && rt.downloadPool != nil { resp.Body, err = rt.downloadPool.AddReader(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "unable to attach response throttler") + } } + // nolint:wrapcheck return resp, err } diff --git a/internal/tlsutil/tlsutil.go b/internal/tlsutil/tlsutil.go index 3db6ba253..004c75e1f 100644 --- a/internal/tlsutil/tlsutil.go +++ b/internal/tlsutil/tlsutil.go @@ -83,7 +83,7 @@ func GenerateServerCertificate(ctx context.Context, keySize int, certValid time. func WritePrivateKeyToFile(fname string, priv *rsa.PrivateKey) error { f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) //nolint:gosec if err != nil { - return err + return errors.Wrap(err, "error opening private key file") } defer f.Close() //nolint:errcheck,gosec @@ -103,7 +103,7 @@ func WritePrivateKeyToFile(fname string, priv *rsa.PrivateKey) error { func WriteCertificateToFile(fname string, cert *x509.Certificate) error { f, err := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) //nolint:gosec if err != nil { - return err + return errors.Wrap(err, "error opening certificate file") } defer f.Close() //nolint:errcheck,gosec diff --git a/internal/webdavmount/webdavmount.go b/internal/webdavmount/webdavmount.go index 1e43d6665..cd5b47639 100644 --- a/internal/webdavmount/webdavmount.go +++ b/internal/webdavmount/webdavmount.go @@ -45,7 +45,7 @@ func (f *webdavFile) getReader() (fs.Reader, error) { if f.r == nil { r, err := f.entry.Open(f.ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error opening webdav file") } f.r = r @@ -98,7 +98,7 @@ type webdavDir struct { func (d *webdavDir) Readdir(n int) ([]os.FileInfo, error) { entries, err := d.entry.Readdir(d.ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading directory") } if n > 0 && n < len(entries) { @@ -192,7 +192,7 @@ func (w *webdavFS) findEntry(ctx context.Context, path string) (fs.Entry, error) entries, err := d.Readdir(ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading directory") } e = entries.FindByName(p) diff --git a/repo/api_server_repository.go b/repo/api_server_repository.go index ca431b322..bcfa977cf 100644 --- a/repo/api_server_repository.go +++ b/repo/api_server_repository.go @@ -70,7 +70,7 @@ func (r *apiServerRepository) GetManifest(ctx context.Context, id manifest.ID, d var mm remoterepoapi.ManifestWithMetadata if err := r.cli.Get(ctx, "manifests/"+string(id), manifest.ErrNotFound, &mm); err != nil { - return nil, err + return nil, errors.Wrap(err, "GetManifest") } return mm.Metadata, json.Unmarshal(mm.Payload, data) @@ -92,7 +92,7 @@ func (r *apiServerRepository) PutManifest(ctx context.Context, labels map[string resp := &manifest.EntryMetadata{} if err := r.cli.Post(ctx, "manifests", req, resp); err != nil { - return "", err + return "", errors.Wrap(err, "PutManifest") } return resp.ID, nil @@ -108,14 +108,14 @@ func (r *apiServerRepository) FindManifests(ctx context.Context, labels map[stri var mm []*manifest.EntryMetadata if err := r.cli.Get(ctx, "manifests?"+uv.Encode(), nil, &mm); err != nil { - return nil, err + return nil, errors.Wrap(err, "FindManifests") } return mm, nil } func (r *apiServerRepository) DeleteManifest(ctx context.Context, id manifest.ID) error { - return r.cli.Delete(ctx, "manifests/"+string(id), nil, nil) + return errors.Wrap(r.cli.Delete(ctx, "manifests/"+string(id), nil, nil), "DeleteManifest") } func (r *apiServerRepository) Time() time.Time { @@ -127,7 +127,7 @@ func (r *apiServerRepository) Refresh(ctx context.Context) error { } func (r *apiServerRepository) Flush(ctx context.Context) error { - return r.cli.Post(ctx, "flush", nil, nil) + return errors.Wrap(r.cli.Post(ctx, "flush", nil, nil), "Flush") } func (r *apiServerRepository) Close(ctx context.Context) error { @@ -135,14 +135,14 @@ func (r *apiServerRepository) Close(ctx context.Context) error { return errors.Wrap(err, "error closing object manager") } - return r.Flush(ctx) + return errors.Wrap(r.Flush(ctx), "Close") } func (r *apiServerRepository) ContentInfo(ctx context.Context, contentID content.ID) (content.Info, error) { var bi content.Info if err := r.cli.Get(ctx, "contents/"+string(contentID)+"?info=1", content.ErrContentNotFound, &bi); err != nil { - return content.Info{}, err + return content.Info{}, errors.Wrap(err, "ContentInfo") } return bi, nil @@ -152,7 +152,7 @@ func (r *apiServerRepository) GetContent(ctx context.Context, contentID content. var result []byte if err := r.cli.Get(ctx, "contents/"+string(contentID), content.ErrContentNotFound, &result); err != nil { - return nil, err + return nil, errors.Wrap(err, "GetContent") } return result, nil @@ -160,7 +160,7 @@ func (r *apiServerRepository) GetContent(ctx context.Context, contentID content. func (r *apiServerRepository) WriteContent(ctx context.Context, data []byte, prefix content.ID) (content.ID, error) { if err := content.ValidatePrefix(prefix); err != nil { - return "", err + return "", errors.Wrap(err, "invalid prefix") } var hashOutput [128]byte @@ -168,7 +168,7 @@ func (r *apiServerRepository) WriteContent(ctx context.Context, data []byte, pre contentID := prefix + content.ID(hex.EncodeToString(r.h(hashOutput[:0], data))) if err := r.cli.Put(ctx, "contents/"+string(contentID), data, nil); err != nil { - return "", err + return "", errors.Wrapf(err, "error writing content %v", contentID) } return contentID, nil @@ -232,7 +232,7 @@ func ConnectAPIServer(ctx context.Context, configFile string, si *APIServerInfo, d, err := json.MarshalIndent(&lc, "", " ") if err != nil { - return err + return errors.Wrap(err, "unable to marshal config JSON") } if err = os.MkdirAll(filepath.Dir(configFile), 0o700); err != nil { diff --git a/repo/blob/azure/azure_storage.go b/repo/blob/azure/azure_storage.go index c87831424..11d3f1095 100644 --- a/repo/blob/azure/azure_storage.go +++ b/repo/blob/azure/azure_storage.go @@ -44,14 +44,14 @@ func (az *azStorage) GetBlob(ctx context.Context, b blob.ID, offset, length int6 attempt := func() (interface{}, error) { reader, err := az.bucket.NewRangeReader(ctx, az.getObjectNameString(b), offset, length, nil) if err != nil { - return nil, err + return nil, errors.Wrap(err, "NewRangeReader") } defer reader.Close() //nolint:errcheck throttled, err := az.downloadThrottler.AddReader(reader) if err != nil { - return nil, err + return nil, errors.Wrap(err, "AddReader") } return ioutil.ReadAll(throttled) @@ -74,7 +74,7 @@ func (az *azStorage) GetMetadata(ctx context.Context, b blob.ID) (blob.Metadata, attempt := func() (interface{}, error) { fi, err := az.bucket.Attributes(ctx, az.getObjectNameString(b)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Attributes") } return blob.Metadata{ @@ -97,7 +97,9 @@ func exponentialBackoff(ctx context.Context, desc string, att retry.AttemptFunc) } func isRetriableError(err error) bool { - if me, ok := err.(azblob.ResponseError); ok { + var me azblob.ResponseError + + if errors.As(err, &me) { if me.Response() == nil { return true } @@ -133,12 +135,14 @@ func (az *azStorage) PutBlob(ctx context.Context, b blob.ID, data blob.Bytes) er throttled, err := az.uploadThrottler.AddReader(ioutil.NopCloser(data.Reader())) if err != nil { + // nolint:wrapcheck return err } // create azure Bucket writer writer, err := az.bucket.NewWriter(ctx, az.getObjectNameString(b), &gblob.WriterOptions{ContentType: "application/x-kopia"}) if err != nil { + // nolint:wrapcheck return err } @@ -188,11 +192,12 @@ func (az *azStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback fun // iterate over list iterator for { lo, err := li.Next(ctx) - if err == io.EOF { + if errors.Is(err, io.EOF) { break } if err != nil { + // nolint:wrapcheck return err } @@ -244,7 +249,7 @@ func New(ctx context.Context, opt *Options) (blob.Storage, error) { // create a credentials object. credential, err := azureblob.NewCredential(azureblob.AccountName(opt.StorageAccount), azureblob.AccountKey(opt.StorageKey)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to initialize credentials") } // create a Pipeline with credentials. @@ -253,7 +258,7 @@ func New(ctx context.Context, opt *Options) (blob.Storage, error) { // create a *blob.Bucket. bucket, err := azureblob.OpenBucket(ctx, pipeline, azureblob.AccountName(opt.StorageAccount), opt.Container, &azureblob.Options{Credential: credential}) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to open bucket") } downloadThrottler := iothrottler.NewIOThrottlerPool(toBandwidth(opt.MaxDownloadSpeedBytesPerSecond)) diff --git a/repo/blob/azure/azure_storage_test.go b/repo/blob/azure/azure_storage_test.go index afb0d432d..b3bafc357 100644 --- a/repo/blob/azure/azure_storage_test.go +++ b/repo/blob/azure/azure_storage_test.go @@ -9,6 +9,7 @@ import ( "testing" "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/pkg/errors" "github.com/kopia/kopia/internal/blobtesting" "github.com/kopia/kopia/internal/clock" @@ -53,7 +54,8 @@ func createContainer(t *testing.T, container, storageAccount, storageKey string) } // return if already exists - if stgErr, ok := err.(azblob.StorageError); ok { + var stgErr azblob.StorageError + if errors.As(err, &stgErr) { if stgErr.ServiceCode() == azblob.ServiceCodeContainerAlreadyExists { return } diff --git a/repo/blob/b2/b2_storage.go b/repo/blob/b2/b2_storage.go index 28d2eb8f3..52af15152 100644 --- a/repo/blob/b2/b2_storage.go +++ b/repo/blob/b2/b2_storage.go @@ -47,18 +47,18 @@ func (s *b2Storage) GetBlob(ctx context.Context, id blob.ID, offset, length int6 _, r, err := s.bucket.DownloadFileRangeByName(fileName, fileRange) if err != nil { - return nil, err + return nil, errors.Wrap(err, "DownloadFileRangeByName") } defer r.Close() //nolint:errcheck throttled, err := s.downloadThrottler.AddReader(r) if err != nil { - return nil, err + return nil, errors.Wrap(err, "DownloadFileRangeByName") } b, err := ioutil.ReadAll(throttled) if err != nil { - return nil, err + return nil, errors.Wrap(err, "ReadAll") } if len(b) != int(length) && length > 0 { @@ -83,7 +83,7 @@ func (s *b2Storage) GetBlob(ctx context.Context, id blob.ID, offset, length int6 func (s *b2Storage) resolveFileID(fileName string) (string, error) { resp, err := s.bucket.ListFileVersions(fileName, "", 1) if err != nil { - return "", err + return "", errors.Wrap(err, "ListFileVersions") } if len(resp.Files) > 0 { @@ -106,7 +106,7 @@ func (s *b2Storage) GetMetadata(ctx context.Context, id blob.ID) (blob.Metadata, fi, err := s.bucket.GetFileInfo(fileID) if err != nil { - return nil, err + return nil, errors.Wrap(err, "GetFileInfo") } return blob.Metadata{ @@ -125,7 +125,8 @@ func (s *b2Storage) GetMetadata(ctx context.Context, id blob.ID) (blob.Metadata, } func translateError(err error) error { - if b2err, ok := err.(*backblaze.B2Error); ok { + var b2err *backblaze.B2Error + if errors.As(err, &b2err) { if b2err.Status == http.StatusNotFound { // Normal "not found". That's fine. return blob.ErrBlobNotFound @@ -146,7 +147,9 @@ func exponentialBackoff(ctx context.Context, desc string, att retry.AttemptFunc) } func isRetriableError(err error) bool { - if b2err, ok := err.(*backblaze.B2Error); ok { + var b2err *backblaze.B2Error + + if errors.As(err, &b2err) { switch b2err.Status { case http.StatusRequestTimeout: return true @@ -174,12 +177,14 @@ func (s *b2Storage) PutBlob(ctx context.Context, id blob.ID, data blob.Bytes) er attempt := func() (interface{}, error) { throttled, err := s.uploadThrottler.AddReader(ioutil.NopCloser(data.Reader())) if err != nil { + // nolint:wrapcheck return nil, err } fileName := s.getObjectNameString(id) _, err = s.bucket.UploadFile(fileName, nil, throttled) + // nolint:wrapcheck return nil, err } @@ -224,6 +229,7 @@ func (s *b2Storage) ListBlobs(ctx context.Context, prefix blob.ID, callback func for { resp, err := s.bucket.ListFileNamesWithPrefix(nextFile, maxFileQuery, fullPrefix, "") if err != nil { + // nolint:wrapcheck return err } diff --git a/repo/blob/config.go b/repo/blob/config.go index ed1b09bbc..105818867 100644 --- a/repo/blob/config.go +++ b/repo/blob/config.go @@ -20,7 +20,7 @@ func (c *ConnectionInfo) UnmarshalJSON(b []byte) error { }{} if err := json.Unmarshal(b, &raw); err != nil { - return err + return errors.Wrap(err, "error unmarshaling connection info JSON") } c.Type = raw.Type diff --git a/repo/blob/filesystem/filesystem_storage.go b/repo/blob/filesystem/filesystem_storage.go index cff8b8a7e..b95ed6eb1 100644 --- a/repo/blob/filesystem/filesystem_storage.go +++ b/repo/blob/filesystem/filesystem_storage.go @@ -59,12 +59,14 @@ func isRetriable(err error) bool { } // retry errors during file operations - if _, ok := err.(*os.PathError); ok { + var pe *os.PathError + if errors.As(err, &pe) { return true } // retry errors during rename - if _, ok := err.(*os.LinkError); ok { + var le *os.LinkError + if errors.As(err, &le) { return true } @@ -75,6 +77,7 @@ func (fs *fsImpl) GetBlobFromPath(ctx context.Context, dirPath, path string, off val, err := retry.WithExponentialBackoff(ctx, "GetBlobFromPath:"+path, func() (interface{}, error) { f, err := os.Open(path) //nolint:gosec if err != nil { + //nolint:wrapcheck return nil, err } @@ -91,6 +94,7 @@ func (fs *fsImpl) GetBlobFromPath(ctx context.Context, dirPath, path string, off b, err := ioutil.ReadAll(io.LimitReader(f, length)) if err != nil { + //nolint:wrapcheck return nil, err } @@ -100,6 +104,7 @@ func (fs *fsImpl) GetBlobFromPath(ctx context.Context, dirPath, path string, off // this sometimes fails on macOS for unknown reasons, likely a bug in the filesystem // retry deals with this transient state. // see see https://github.com/kopia/kopia/issues/299 + // nolint:wrapcheck return nil, errRetriableInvalidLength } } @@ -114,6 +119,7 @@ func (fs *fsImpl) GetBlobFromPath(ctx context.Context, dirPath, path string, off return nil, blob.ErrBlobNotFound } + // nolint:wrapcheck return nil, err } @@ -123,6 +129,7 @@ func (fs *fsImpl) GetBlobFromPath(ctx context.Context, dirPath, path string, off func (fs *fsImpl) GetMetadataFromPath(ctx context.Context, dirPath, path string) (blob.Metadata, error) { fi, err := os.Stat(path) if err != nil { + // nolint:wrapcheck return blob.Metadata{}, err } @@ -131,6 +138,7 @@ func (fs *fsImpl) GetMetadataFromPath(ctx context.Context, dirPath, path string) return blob.Metadata{}, blob.ErrBlobNotFound } + // nolint:wrapcheck return blob.Metadata{}, err } @@ -177,6 +185,7 @@ func (fs *fsImpl) PutBlobInPath(ctx context.Context, dirPath, path string, data log(ctx).Warningf("can't remove temp file: %v", removeErr) } + // nolint:wrapcheck return err } @@ -202,6 +211,7 @@ func (fs *fsImpl) createTempFileAndDir(tempFile string) (*os.File, error) { return os.OpenFile(tempFile, flags, fs.fileMode()) //nolint:gosec } + // nolint:wrapcheck return f, err } @@ -212,6 +222,7 @@ func (fs *fsImpl) DeleteBlobInPath(ctx context.Context, dirPath, path string) er return nil } + // nolint:wrapcheck return err }, isRetriable) } @@ -219,9 +230,11 @@ func (fs *fsImpl) DeleteBlobInPath(ctx context.Context, dirPath, path string) er func (fs *fsImpl) ReadDir(ctx context.Context, dirname string) ([]os.FileInfo, error) { v, err := retry.WithExponentialBackoff(ctx, "ReadDir:"+dirname, func() (interface{}, error) { v, err := ioutil.ReadDir(dirname) + // nolint:wrapcheck return v, err }, isRetriable) if err != nil { + // nolint:wrapcheck return nil, err } @@ -241,6 +254,7 @@ func (fs *fsStorage) TouchBlob(ctx context.Context, blobID blob.ID, threshold ti st, err := os.Stat(path) if err != nil { + // nolint:wrapcheck return err } diff --git a/repo/blob/gcs/gcs_storage.go b/repo/blob/gcs/gcs_storage.go index 68740c8dd..a48bbe05a 100644 --- a/repo/blob/gcs/gcs_storage.go +++ b/repo/blob/gcs/gcs_storage.go @@ -48,7 +48,7 @@ func (gcs *gcsStorage) GetBlob(ctx context.Context, b blob.ID, offset, length in attempt := func() (interface{}, error) { reader, err := gcs.bucket.Object(gcs.getObjectNameString(b)).NewRangeReader(gcs.ctx, offset, length) if err != nil { - return nil, err + return nil, errors.Wrap(err, "NewRangeReader") } defer reader.Close() //nolint:errcheck @@ -72,7 +72,7 @@ func (gcs *gcsStorage) GetMetadata(ctx context.Context, b blob.ID) (blob.Metadat attempt := func() (interface{}, error) { attrs, err := gcs.bucket.Object(gcs.getObjectNameString(b)).Attrs(ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "Attrs") } return blob.Metadata{ @@ -95,16 +95,17 @@ func exponentialBackoff(ctx context.Context, desc string, att retry.AttemptFunc) } func isRetriableError(err error) bool { - if apiError, ok := err.(*googleapi.Error); ok { + var apiError *googleapi.Error + if errors.As(err, &apiError) { return apiError.Code >= 500 } - switch err { - case nil: + switch { + case err == nil: return false - case gcsclient.ErrObjectNotExist: + case errors.Is(err, gcsclient.ErrObjectNotExist): return false - case gcsclient.ErrBucketNotExist: + case errors.Is(err, gcsclient.ErrBucketNotExist): return false default: return true @@ -112,10 +113,10 @@ func isRetriableError(err error) bool { } func translateError(err error) error { - switch err { - case nil: + switch { + case err == nil: return nil - case gcsclient.ErrObjectNotExist: + case errors.Is(err, gcsclient.ErrObjectNotExist): return blob.ErrBlobNotFound default: return errors.Wrap(err, "unexpected GCS error") @@ -202,7 +203,7 @@ func (gcs *gcsStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback f } if !errors.Is(err, iterator.Done) { - return err + return errors.Wrap(err, "ListBlobs") } return nil @@ -234,7 +235,7 @@ func toBandwidth(bytesPerSecond int) iothrottler.Bandwidth { func tokenSourceFromCredentialsFile(ctx context.Context, fn string, scopes ...string) (oauth2.TokenSource, error) { data, err := ioutil.ReadFile(fn) //nolint:gosec if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading credentials file") } cfg, err := google.JWTConfigFromJSON(data, scopes...) @@ -279,7 +280,7 @@ func New(ctx context.Context, opt *Options) (blob.Storage, error) { } if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to initialize token source") } downloadThrottler := iothrottler.NewIOThrottlerPool(toBandwidth(opt.MaxDownloadSpeedBytesPerSecond)) @@ -290,7 +291,7 @@ func New(ctx context.Context, opt *Options) (blob.Storage, error) { cli, err := gcsclient.NewClient(ctx, option.WithHTTPClient(hc)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to create GCS client") } if opt.BucketName == "" { diff --git a/repo/blob/logging/logging_storage.go b/repo/blob/logging/logging_storage.go index b31c7f420..5762d3759 100644 --- a/repo/blob/logging/logging_storage.go +++ b/repo/blob/logging/logging_storage.go @@ -28,6 +28,7 @@ func (s *loggingStorage) GetBlob(ctx context.Context, id blob.ID, offset, length s.printf(s.prefix+"GetBlob(%q,%v,%v)=({%v bytes}, %#v) took %v", id, offset, length, len(result), err, dt) } + // nolint:wrapcheck return result, err } @@ -38,6 +39,7 @@ func (s *loggingStorage) GetMetadata(ctx context.Context, id blob.ID) (blob.Meta s.printf(s.prefix+"GetMetadata(%q)=(%v, %#v) took %v", id, result, err, dt) + // nolint:wrapcheck return result, err } @@ -47,6 +49,7 @@ func (s *loggingStorage) PutBlob(ctx context.Context, id blob.ID, data blob.Byte dt := clock.Since(t0) s.printf(s.prefix+"PutBlob(%q,len=%v)=%#v took %v", id, data.Length(), err, dt) + // nolint:wrapcheck return err } @@ -56,6 +59,7 @@ func (s *loggingStorage) SetTime(ctx context.Context, id blob.ID, t time.Time) e dt := clock.Since(t0) s.printf(s.prefix+"SetTime(%q,%v)=%#v took %v", id, t, err, dt) + // nolint:wrapcheck return err } @@ -65,6 +69,7 @@ func (s *loggingStorage) DeleteBlob(ctx context.Context, id blob.ID) error { dt := clock.Since(t0) s.printf(s.prefix+"DeleteBlob(%q)=%#v took %v", id, err, dt) + // nolint:wrapcheck return err } @@ -77,6 +82,7 @@ func (s *loggingStorage) ListBlobs(ctx context.Context, prefix blob.ID, callback }) s.printf(s.prefix+"ListBlobs(%q)=%v returned %v items and took %v", prefix, err, cnt, clock.Since(t0)) + // nolint:wrapcheck return err } @@ -86,6 +92,7 @@ func (s *loggingStorage) Close(ctx context.Context) error { dt := clock.Since(t0) s.printf(s.prefix+"Close()=%#v took %v", err, dt) + // nolint:wrapcheck return err } diff --git a/repo/blob/readonly/readonly_storage.go b/repo/blob/readonly/readonly_storage.go index f6ade4847..e9fe073ea 100644 --- a/repo/blob/readonly/readonly_storage.go +++ b/repo/blob/readonly/readonly_storage.go @@ -27,14 +27,17 @@ func (s readonlyStorage) GetMetadata(ctx context.Context, id blob.ID) (blob.Meta } func (s readonlyStorage) SetTime(ctx context.Context, id blob.ID, t time.Time) error { + // nolint:wrapcheck return ErrReadonly } func (s readonlyStorage) PutBlob(ctx context.Context, id blob.ID, data blob.Bytes) error { + // nolint:wrapcheck return ErrReadonly } func (s readonlyStorage) DeleteBlob(ctx context.Context, id blob.ID) error { + // nolint:wrapcheck return ErrReadonly } diff --git a/repo/blob/s3/s3_storage.go b/repo/blob/s3/s3_storage.go index 8f30969be..f513f42be 100644 --- a/repo/blob/s3/s3_storage.go +++ b/repo/blob/s3/s3_storage.go @@ -48,19 +48,19 @@ func (s *s3Storage) GetBlob(ctx context.Context, b blob.ID, offset, length int64 o, err := s.cli.GetObject(ctx, s.BucketName, s.getObjectNameString(b), opt) if err != nil { - return 0, err + return nil, errors.Wrap(err, "GetObject") } defer o.Close() //nolint:errcheck throttled, err := s.downloadThrottler.AddReader(o) if err != nil { - return nil, err + return nil, errors.Wrap(err, "AddReader") } b, err := ioutil.ReadAll(throttled) if err != nil { - return nil, err + return nil, errors.Wrap(err, "ReadAll") } if len(b) != int(length) && length > 0 { @@ -87,7 +87,9 @@ func exponentialBackoff(ctx context.Context, desc string, att retry.AttemptFunc) } func isRetriableError(err error) bool { - if me, ok := err.(minio.ErrorResponse); ok { + var me minio.ErrorResponse + + if errors.As(err, &me) { // retry on server errors, not on client errors return me.StatusCode >= 500 } @@ -101,7 +103,9 @@ func isRetriableError(err error) bool { } func translateError(err error) error { - if me, ok := err.(minio.ErrorResponse); ok { + var me minio.ErrorResponse + + if errors.As(err, &me) { if me.StatusCode == http.StatusOK { return nil } @@ -118,7 +122,7 @@ func (s *s3Storage) GetMetadata(ctx context.Context, b blob.ID) (blob.Metadata, v, err := retry.WithExponentialBackoff(ctx, fmt.Sprintf("GetMetadata(%v)", b), func() (interface{}, error) { oi, err := s.cli.StatObject(ctx, s.BucketName, s.getObjectNameString(b), minio.StatObjectOptions{}) if err != nil { - return blob.Metadata{}, err + return blob.Metadata{}, errors.Wrap(err, "StatObject") } return blob.Metadata{ @@ -135,7 +139,7 @@ func (s *s3Storage) PutBlob(ctx context.Context, b blob.ID, data blob.Bytes) err return translateError(retry.WithExponentialBackoffNoValue(ctx, fmt.Sprintf("PutBlob(%v)", b), func() error { throttled, err := s.uploadThrottler.AddReader(ioutil.NopCloser(data.Reader())) if err != nil { - return err + return errors.Wrap(err, "AddReader") } combinedLength := data.Length() @@ -151,13 +155,14 @@ func (s *s3Storage) PutBlob(ctx context.Context, b blob.ID, data blob.Bytes) err Progress: newProgressReader(progressCallback, string(b), int64(combinedLength)), }) - if err == io.EOF && uploadInfo.Size == 0 { + if errors.Is(err, io.EOF) && uploadInfo.Size == 0 { // special case empty stream _, err = s.cli.PutObject(ctx, s.BucketName, s.getObjectNameString(b), bytes.NewBuffer(nil), 0, minio.PutObjectOptions{ ContentType: "application/x-kopia", }) } + // nolint:wrapcheck return err }, isRetriableError)) } diff --git a/repo/blob/sftp/sftp_storage.go b/repo/blob/sftp/sftp_storage.go index 880460f5f..c7b82433c 100644 --- a/repo/blob/sftp/sftp_storage.go +++ b/repo/blob/sftp/sftp_storage.go @@ -55,7 +55,7 @@ func (s *sftpImpl) GetBlobFromPath(ctx context.Context, dirPath, fullPath string } if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unrecognized error when opening SFTP file %v", fullPath) } defer r.Close() //nolint:errcheck @@ -90,7 +90,7 @@ func (s *sftpImpl) GetMetadataFromPath(ctx context.Context, dirPath, fullPath st } if err != nil { - return blob.Metadata{}, err + return blob.Metadata{}, errors.Wrapf(err, "unrecognized error when calling stat() on SFTP file %v", fullPath) } return blob.Metadata{ @@ -134,7 +134,7 @@ func (s *sftpImpl) PutBlobInPath(ctx context.Context, dirPath, fullPath string, fmt.Printf("warning: can't remove temp file: %v", removeErr) } - return err + return errors.Wrap(err, "unexpected error renaming file on SFTP") } return nil @@ -157,7 +157,7 @@ func (s *sftpImpl) createTempFileAndDir(tempFile string) (*sftp.File, error) { return s.cli.OpenFile(tempFile, flags) } - return f, err + return f, errors.Wrapf(err, "unrecognized error when creating temp file on SFTP: %v", tempFile) } func isNotExist(err error) bool { @@ -178,7 +178,7 @@ func (s *sftpImpl) DeleteBlobInPath(ctx context.Context, dirPath, fullPath strin return nil } - return err + return errors.Wrapf(err, "error deleting SFTP file %v", fullPath) } func (s *sftpImpl) ReadDir(ctx context.Context, dirname string) ([]os.FileInfo, error) { @@ -212,7 +212,7 @@ func (s *sftpStorage) Close(ctx context.Context) error { func writeKnownHostsDataStringToTempFile(data string) (string, error) { tf, err := ioutil.TempFile("", "kopia-known-hosts") if err != nil { - return "", err + return "", errors.Wrap(err, "error creating temp file") } defer tf.Close() //nolint:errcheck,gosec @@ -259,13 +259,13 @@ func getSigner(opts *Options) (ssh.Signer, error) { privateKeyData, err = ioutil.ReadFile(opts.Keyfile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading private key file") } } key, err := ssh.ParsePrivateKey(privateKeyData) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error parsing private key") } return key, nil @@ -321,12 +321,12 @@ func getSFTPClientExternal(ctx context.Context, opt *Options) (*sftp.Client, clo // get stdin and stdout wr, err := cmd.StdinPipe() if err != nil { - return nil, nil, err + return nil, nil, errors.Wrap(err, "error opening SSH stdin pipe") } rd, err := cmd.StdoutPipe() if err != nil { - return nil, nil, err + return nil, nil, errors.Wrap(err, "error opening SSH stdout pipe") } if err = cmd.Start(); err != nil { @@ -347,7 +347,7 @@ func getSFTPClientExternal(ctx context.Context, opt *Options) (*sftp.Client, clo if err != nil { closeFunc() // nolint:errcheck - return nil, nil, err + return nil, nil, errors.Wrap(err, "error creating sftp client pipe") } return c, closeFunc, nil diff --git a/repo/blob/sharded/sharded.go b/repo/blob/sharded/sharded.go index 3becb01db..8e18edc18 100644 --- a/repo/blob/sharded/sharded.go +++ b/repo/blob/sharded/sharded.go @@ -8,6 +8,8 @@ import ( "strings" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo/blob" ) @@ -57,7 +59,7 @@ func (s Storage) ListBlobs(ctx context.Context, prefix blob.ID, callback func(bl walkDir = func(directory string, currentPrefix string) error { entries, err := s.Impl.ReadDir(ctx, directory) if err != nil { - return err + return errors.Wrap(err, "error reading directory") } for _, e := range entries { @@ -103,7 +105,7 @@ func (s Storage) GetMetadata(ctx context.Context, blobID blob.ID) (blob.Metadata m, err := s.Impl.GetMetadataFromPath(ctx, dirPath, filePath) m.BlobID = blobID - return m, err + return m, errors.Wrap(err, "error getting metadata") } // PutBlob implements blob.Storage. diff --git a/repo/blob/storage.go b/repo/blob/storage.go index d314a93b3..b13a3f78c 100644 --- a/repo/blob/storage.go +++ b/repo/blob/storage.go @@ -94,7 +94,7 @@ func ListAllBlobs(ctx context.Context, st Storage, prefix ID) ([]Metadata, error return nil }) - return result, err + return result, errors.Wrap(err, "error listing all blobs") } // IterateAllPrefixesInParallel invokes the provided callback and returns the first error returned by the callback or nil. diff --git a/repo/blob/webdav/webdav_storage.go b/repo/blob/webdav/webdav_storage.go index 3c3f89aa1..d0a191ba4 100644 --- a/repo/blob/webdav/webdav_storage.go +++ b/repo/blob/webdav/webdav_storage.go @@ -88,8 +88,10 @@ func (d *davStorageImpl) GetMetadataFromPath(ctx context.Context, dirPath, path } func httpErrorCode(err error) int { - if err, ok := err.(*os.PathError); ok { - code, err := strconv.Atoi(strings.Split(err.Err.Error(), " ")[0]) + var pe *os.PathError + + if errors.As(err, &pe) { + code, err := strconv.Atoi(strings.Split(pe.Err.Error(), " ")[0]) if err == nil { return code } @@ -99,9 +101,11 @@ func httpErrorCode(err error) int { } func (d *davStorageImpl) translateError(err error) error { - switch err := err.(type) { - case *os.PathError: - switch httpErrorCode(err) { + var pe *os.PathError + + switch { + case errors.As(err, &pe): + switch httpErrorCode(pe) { case http.StatusNotFound: return blob.ErrBlobNotFound default: @@ -120,7 +124,7 @@ func (d *davStorageImpl) ReadDir(ctx context.Context, dir string) ([]os.FileInfo return v.([]os.FileInfo), nil } - return nil, err + return nil, errors.Wrap(err, "error reading WebDAV dir") } func (d *davStorageImpl) PutBlobInPath(ctx context.Context, dirPath, filePath string, data blob.Bytes) error { @@ -180,12 +184,14 @@ func (d *davStorage) Close(ctx context.Context) error { } func isRetriable(err error) bool { - switch err := err.(type) { - case nil: + var pe *os.PathError + + switch { + case err == nil: return false - case *os.PathError: - httpCode := httpErrorCode(err) + case errors.As(err, &pe): + httpCode := httpErrorCode(pe) return httpCode == 429 || httpCode >= 500 default: diff --git a/repo/connect.go b/repo/connect.go index f643ae397..274b408c8 100644 --- a/repo/connect.go +++ b/repo/connect.go @@ -36,6 +36,7 @@ func Connect(ctx context.Context, configFile string, st blob.Storage, password s formatBytes, err := st.GetBlob(ctx, FormatBlobID, 0, -1) if err != nil { if errors.Is(err, blob.ErrBlobNotFound) { + // nolint:wrapcheck return ErrRepositoryNotInitialized } @@ -59,7 +60,7 @@ func Connect(ctx context.Context, configFile string, st blob.Storage, password s d, err := json.MarshalIndent(&lc, "", " ") if err != nil { - return err + return errors.Wrap(err, "unable to serialize JSON") } if err = os.MkdirAll(filepath.Dir(configFile), 0o700); err != nil { @@ -178,7 +179,7 @@ func SetClientOptions(ctx context.Context, configFile string, cliOpt ClientOptio d, err := json.MarshalIndent(lc, "", " ") if err != nil { - return err + return errors.Wrap(err, "error marshaling config JSON") } if err = ioutil.WriteFile(configFile, d, 0o600); err != nil { diff --git a/repo/content/committed_content_index.go b/repo/content/committed_content_index.go index b49c985ee..6b54e0b24 100644 --- a/repo/content/committed_content_index.go +++ b/repo/content/committed_content_index.go @@ -43,7 +43,7 @@ func (b *committedContentIndex) getContent(contentID ID) (Info, error) { func (b *committedContentIndex) addContent(ctx context.Context, indexBlobID blob.ID, data []byte, use bool) error { if err := b.cache.addContentToCache(ctx, indexBlobID, data); err != nil { - return err + return errors.Wrap(err, "error adding content to cache") } if !use { diff --git a/repo/content/committed_content_index_disk_cache.go b/repo/content/committed_content_index_disk_cache.go index 3e1655aa9..52f22339d 100644 --- a/repo/content/committed_content_index_disk_cache.go +++ b/repo/content/committed_content_index_disk_cache.go @@ -60,7 +60,7 @@ func mmapOpenWithRetry(ctx context.Context, path string) (*mmap.ReaderAt, error) f, err = mmap.Open(path) } - return f, err + return f, errors.Wrap(err, "mmap() error") } func (c *diskCommittedContentIndexCache) hasIndexBlobID(ctx context.Context, indexBlobID blob.ID) (bool, error) { @@ -73,7 +73,7 @@ func (c *diskCommittedContentIndexCache) hasIndexBlobID(ctx context.Context, ind return false, nil } - return false, err + return false, errors.Wrapf(err, "error checking %v", indexBlobID) } func (c *diskCommittedContentIndexCache) addContentToCache(ctx context.Context, indexBlobID blob.ID, data []byte) error { diff --git a/repo/content/content_cache.go b/repo/content/content_cache.go index 3c6c7c69c..1c43d0a04 100644 --- a/repo/content/content_cache.go +++ b/repo/content/content_cache.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/ctxutil" "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/blob/filesystem" @@ -27,7 +29,7 @@ func newCacheStorageOrNil(ctx context.Context, cacheDir string, maxBytes int64, if _, err = os.Stat(contentCacheDir); os.IsNotExist(err) { if mkdirerr := os.MkdirAll(contentCacheDir, 0o700); mkdirerr != nil { - return nil, mkdirerr + return nil, errors.Wrap(mkdirerr, "error creating cache directory") } } @@ -36,7 +38,7 @@ func newCacheStorageOrNil(ctx context.Context, cacheDir string, maxBytes int64, DirectoryShards: []int{2}, }) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error initializing filesystem cache") } } diff --git a/repo/content/content_cache_base.go b/repo/content/content_cache_base.go index 854e30a02..eb84202a0 100644 --- a/repo/content/content_cache_base.go +++ b/repo/content/content_cache_base.go @@ -177,8 +177,9 @@ func newContentCacheBase(ctx context.Context, cacheStorage blob.Storage, maxSize // verify that cache storage is functional by listing from it if err := c.cacheStorage.ListBlobs(ctx, "", func(it blob.Metadata) error { + // nolint:wrapcheck return errGood - }); err != nil && err != errGood { //nolint:goerr113 + }); err != nil && !errors.Is(err, errGood) { return nil, errors.Wrap(err, "unable to open cache") } diff --git a/repo/content/content_cache_data.go b/repo/content/content_cache_data.go index aaf25fb33..c1bb2cbe5 100644 --- a/repo/content/content_cache_data.go +++ b/repo/content/content_cache_data.go @@ -54,6 +54,7 @@ func (c *contentCacheForData) getContent(ctx context.Context, cacheKey cacheKey, if errors.Is(err, blob.ErrBlobNotFound) { // not found in underlying storage + // nolint:wrapcheck return nil, err } @@ -69,7 +70,7 @@ func (c *contentCacheForData) getContent(ctx context.Context, cacheKey cacheKey, } } - return b, err + return b, errors.Wrap(err, "error getting content from cache") } func (c *contentCacheForData) readAndVerifyCacheContent(ctx context.Context, cacheKey cacheKey) []byte { diff --git a/repo/content/content_cache_metadata.go b/repo/content/content_cache_metadata.go index abd86bea1..b76b40de5 100644 --- a/repo/content/content_cache_metadata.go +++ b/repo/content/content_cache_metadata.go @@ -81,10 +81,12 @@ func (c *contentCacheForMetadata) getContent(ctx context.Context, cacheKey cache if errors.Is(err, blob.ErrBlobNotFound) { // not found in underlying storage + // nolint:wrapcheck return nil, err } if err != nil { + // nolint:wrapcheck return nil, err } @@ -101,7 +103,7 @@ func (c *contentCacheForMetadata) getContent(ctx context.Context, cacheKey cache } if offset == 0 && length == -1 { - return blobData, err + return blobData, nil } if offset < 0 || offset+length > int64(len(blobData)) { diff --git a/repo/content/content_cache_test.go b/repo/content/content_cache_test.go index bfea4b07f..f99ae5dff 100644 --- a/repo/content/content_cache_test.go +++ b/repo/content/content_cache_test.go @@ -93,7 +93,7 @@ func TestCacheExpiration(t *testing.T) { for _, tc := range cases { _, got := cache.getContent(ctx, cacheKey(tc.blobID), "content-4k", 0, -1) - if want := tc.expectedError; got != want { + if want := tc.expectedError; !errors.Is(got, want) { t.Errorf("unexpected error when getting content %v: %v wanted %v", tc.blobID, got, want) } else { t.Logf("got correct error %v when reading content %v", tc.expectedError, tc.blobID) @@ -148,8 +148,8 @@ func verifyContentCache(t *testing.T, cache contentCache) { {"xf0f0f3", "no-such-content", 0, -1, nil, blob.ErrBlobNotFound}, {"xf0f0f4", "no-such-content", 10, 5, nil, blob.ErrBlobNotFound}, {"f0f0f5", "content-1", 7, 3, []byte{8, 9, 10}, nil}, - {"xf0f0f6", "content-1", 11, 10, nil, errors.Errorf("invalid offset: 11")}, - {"xf0f0f6", "content-1", -1, 5, nil, errors.Errorf("invalid offset: -1")}, + {"xf0f0f6", "content-1", 11, 10, nil, errors.Errorf("error getting content from cache: invalid offset: 11")}, + {"xf0f0f6", "content-1", -1, 5, nil, errors.Errorf("error getting content from cache: invalid offset: -1")}, } for _, tc := range cases { @@ -157,7 +157,7 @@ func verifyContentCache(t *testing.T, cache contentCache) { if (err != nil) != (tc.err != nil) { t.Errorf("unexpected error for %v: %+v, wanted %+v", tc.cacheKey, err, tc.err) } else if err != nil && err.Error() != tc.err.Error() { - t.Errorf("unexpected error for %v: %+v, wanted %+v", tc.cacheKey, err, tc.err) + t.Errorf("unexpected error for %v: %q, wanted %q", tc.cacheKey, err.Error(), tc.err.Error()) } if !bytes.Equal(v, tc.expected) { t.Errorf("unexpected data for %v: %x, wanted %x", tc.cacheKey, v, tc.expected) diff --git a/repo/content/content_index_recovery.go b/repo/content/content_index_recovery.go index a8eb92196..1e2320db0 100644 --- a/repo/content/content_index_recovery.go +++ b/repo/content/content_index_recovery.go @@ -36,7 +36,7 @@ func (bm *Manager) RecoverIndexFromPackBlob(ctx context.Context, packFile blob.I return nil }) - return recovered, err + return recovered, errors.Wrap(err, "error iterating index entries") } type packContentPostamble struct { @@ -180,7 +180,7 @@ func (bm *lockFreeManager) writePackFileIndexRecoveryData(buf *gather.WriteBuffe encryptedLocalIndex, err := bm.encryptor.Encrypt(nil, localIndex, localIndexIV) if err != nil { - return err + return errors.Wrap(err, "encryption error") } postamble := packContentPostamble{ @@ -207,7 +207,7 @@ func (bm *lockFreeManager) readPackFileLocalIndex(ctx context.Context, packFile payload, err := bm.st.GetBlob(ctx, packFile, 0, -1) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error getting blob %v", packFile) } postamble := findPostamble(payload) diff --git a/repo/content/content_manager.go b/repo/content/content_manager.go index bd6285117..fceed2186 100644 --- a/repo/content/content_manager.go +++ b/repo/content/content_manager.go @@ -311,7 +311,7 @@ func (bm *Manager) flushPackIndexesLocked(ctx context.Context) error { indexBlobMD, err := bm.indexBlobManager.writeIndexBlob(ctx, data) if err != nil { - return err + return errors.Wrap(err, "error writing index blob") } if err := bm.committedContents.addContent(ctx, indexBlobMD.BlobID, dataCopy, true); err != nil { @@ -565,12 +565,12 @@ func (bm *Manager) WriteContent(ctx context.Context, data []byte, prefix ID) (ID // GetContent gets the contents of a given content. If the content is not found returns ErrContentNotFound. func (bm *Manager) GetContent(ctx context.Context, contentID ID) (v []byte, err error) { defer func() { - switch err { - case nil: + switch { + case err == nil: stats.Record(ctx, metricContentGetCount.M(1), metricContentGetBytes.M(int64(len(v)))) - case ErrContentNotFound: + case errors.Is(err, ErrContentNotFound): stats.Record(ctx, metricContentGetNotFoundCount.M(1)) default: stats.Record(ctx, metricContentGetErrorCount.M(1)) diff --git a/repo/content/content_manager_indexes.go b/repo/content/content_manager_indexes.go index 98bfd7299..50d5ba425 100644 --- a/repo/content/content_manager_indexes.go +++ b/repo/content/content_manager_indexes.go @@ -192,7 +192,7 @@ func (bm *Manager) ParseIndexBlob(ctx context.Context, blobID blob.ID) ([]Info, return nil }) - return results, err + return results, errors.Wrap(err, "error iterating index entries") } func addBlobsToIndex(ndx map[blob.ID]*IndexBlobInfo, blobs []blob.Metadata) { diff --git a/repo/content/content_manager_lock_free.go b/repo/content/content_manager_lock_free.go index edee70b0c..6d05cf755 100644 --- a/repo/content/content_manager_lock_free.go +++ b/repo/content/content_manager_lock_free.go @@ -78,7 +78,7 @@ func writeRandomBytesToBuffer(b *gather.WriteBuffer, count int) error { var rnd [defaultPaddingUnit]byte if _, err := io.ReadFull(cryptorand.Reader, rnd[0:count]); err != nil { - return err + return errors.Wrap(err, "error getting random bytes") } b.Append(rnd[0:count]) @@ -91,6 +91,7 @@ func (bm *lockFreeManager) loadPackIndexesUnlocked(ctx context.Context) ([]Index for i := 0; i < indexLoadAttempts; i++ { if err := ctx.Err(); err != nil { + // nolint:wrapcheck return nil, false, err } @@ -103,7 +104,7 @@ func (bm *lockFreeManager) loadPackIndexesUnlocked(ctx context.Context) ([]Index indexBlobs, err := bm.indexBlobManager.listIndexBlobs(ctx, false) if err != nil { - return nil, false, err + return nil, false, errors.Wrap(err, "error listing index blobs") } err = bm.tryLoadPackIndexBlobsUnlocked(ctx, indexBlobs) @@ -193,7 +194,7 @@ func (bm *lockFreeManager) unprocessedIndexBlobsUnlocked(ctx context.Context, co for _, c := range contents { has, err := bm.committedContents.cache.hasIndexBlobID(ctx, c.BlobID) if err != nil { - return nil, 0, err + return nil, 0, errors.Wrapf(err, "error determining whether index blob %v has been downloaded", c.BlobID) } if has { @@ -240,7 +241,7 @@ func (bm *lockFreeManager) getContentDataUnlocked(ctx context.Context, pp *pendi payload, err = bm.getCacheForContentID(bi.ID).getContent(ctx, cacheKey(bi.ID), bi.PackBlobID, int64(bi.PackOffset), int64(bi.Length)) if err != nil { - return nil, err + return nil, errors.Wrap(err, "getCacheForContentID") } } @@ -330,7 +331,7 @@ func (bm *lockFreeManager) IndexBlobs(ctx context.Context, includeInactive bool) func getPackedContentIV(output []byte, contentID ID) ([]byte, error) { n, err := hex.Decode(output, []byte(contentID[len(contentID)-(aes.BlockSize*2):])) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error decoding content IV from %v", contentID) } return output[0:n], nil diff --git a/repo/content/content_manager_own_writes.go b/repo/content/content_manager_own_writes.go index d1982e67f..e45d81967 100644 --- a/repo/content/content_manager_own_writes.go +++ b/repo/content/content_manager_own_writes.go @@ -133,7 +133,7 @@ func (d *persistentOwnWritesCache) merge(ctx context.Context, prefix blob.ID, so return nil }) - return mergeOwnWrites(source, myWrites), err + return mergeOwnWrites(source, myWrites), errors.Wrap(err, "error listing blobs") } func (d *persistentOwnWritesCache) delete(ctx context.Context, blobID blob.ID) error { diff --git a/repo/content/content_manager_test.go b/repo/content/content_manager_test.go index 2d2d8984d..5d0e2068e 100644 --- a/repo/content/content_manager_test.go +++ b/repo/content/content_manager_test.go @@ -188,12 +188,12 @@ func TestContentManagerEmpty(t *testing.T) { noSuchContentID := ID(hashValue([]byte("foo"))) b, err := bm.GetContent(ctx, noSuchContentID) - if err != ErrContentNotFound { + if !errors.Is(err, ErrContentNotFound) { t.Errorf("unexpected error when getting non-existent content: %v, %v", b, err) } bi, err := bm.ContentInfo(ctx, noSuchContentID) - if err != ErrContentNotFound { + if !errors.Is(err, ErrContentNotFound) { t.Errorf("unexpected error when getting non-existent content info: %v, %v", bi, err) } @@ -1291,7 +1291,7 @@ func TestRewriteDeleted(t *testing.T) { assertNoError(t, bm.DeleteContent(ctx, content1)) applyStep(action2) - if got, want := bm.RewriteContent(ctx, content1), ErrContentNotFound; got != want && got != nil { + if got, want := bm.RewriteContent(ctx, content1), ErrContentNotFound; !errors.Is(got, want) && got != nil { t.Errorf("unexpected error %v, wanted %v", got, want) } applyStep(action3) @@ -1500,7 +1500,7 @@ func TestIterateContents(t *testing.T) { return nil }) - if tc.fail != err { + if !errors.Is(err, tc.fail) { t.Errorf("error iterating: %v", err) } @@ -1888,7 +1888,7 @@ func verifyContentNotFound(ctx context.Context, t *testing.T, bm *Manager, conte t.Helper() b, err := bm.GetContent(ctx, contentID) - if err != ErrContentNotFound { + if !errors.Is(err, ErrContentNotFound) { t.Fatalf("unexpected response from GetContent(%q), got %v,%v, expected %v", contentID, b, err, ErrContentNotFound) } } diff --git a/repo/content/index.go b/repo/content/index.go index 847f940b5..a69ec45e1 100644 --- a/repo/content/index.go +++ b/repo/content/index.go @@ -215,7 +215,7 @@ func (b *index) findEntry(output []byte, contentID ID) ([]byte, error) { } if _, err := b.readerAt.ReadAt(entryBuf, int64(packHeaderSize+stride*position)); err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading header") } if bytes.Equal(entryBuf[0:len(key)], key) { diff --git a/repo/content/index_blob_manager.go b/repo/content/index_blob_manager.go index 44e925fd7..a1ce76cc1 100644 --- a/repo/content/index_blob_manager.go +++ b/repo/content/index_blob_manager.go @@ -164,12 +164,12 @@ func (m *indexBlobManagerImpl) getIndexBlob(ctx context.Context, blobID blob.ID) func (m *indexBlobManagerImpl) getEncryptedBlob(ctx context.Context, blobID blob.ID) ([]byte, error) { payload, err := m.indexBlobCache.getContent(ctx, cacheKey(blobID), blobID, 0, -1) if err != nil { - return nil, err + return nil, errors.Wrap(err, "getContent") } iv, err := getIndexBlobIV(blobID) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to get index blob IV") } payload, err = m.encryptor.Decrypt(nil, payload, iv) @@ -217,7 +217,7 @@ func (m *indexBlobManagerImpl) encryptAndWriteBlob(ctx context.Context, data []b data2, err := m.encryptor.Encrypt(nil, data, iv) if err != nil { - return blob.Metadata{}, err + return blob.Metadata{}, errors.Wrapf(err, "error encrypting blob %v", blobID) } m.listCache.deleteListCache(prefix) @@ -225,7 +225,7 @@ func (m *indexBlobManagerImpl) encryptAndWriteBlob(ctx context.Context, data []b err = m.st.PutBlob(ctx, blobID, gather.FromSlice(data2)) if err != nil { formatLog(ctx).Debugf("write-index-blob %v failed %v", blobID, err) - return blob.Metadata{}, err + return blob.Metadata{}, errors.Wrapf(err, "error writing blob %v", blobID) } bm, err := m.st.GetMetadata(ctx, blobID) diff --git a/repo/content/index_blob_manager_test.go b/repo/content/index_blob_manager_test.go index 8a593ce75..305f1ee64 100644 --- a/repo/content/index_blob_manager_test.go +++ b/repo/content/index_blob_manager_test.go @@ -622,7 +622,7 @@ var errGetAllFakeContentsRetry = errors.New("retry") func getAllFakeContents(ctx context.Context, m indexBlobManager) (map[string]fakeContentIndexEntry, []IndexBlobInfo, error) { allContents, allBlobs, err := getAllFakeContentsInternal(ctx, m) - for err == errGetAllFakeContentsRetry { + for errors.Is(err, errGetAllFakeContentsRetry) { allContents, allBlobs, err = getAllFakeContentsInternal(ctx, m) } diff --git a/repo/content/list_cache.go b/repo/content/list_cache.go index a20b33701..5cce5251a 100644 --- a/repo/content/list_cache.go +++ b/repo/content/list_cache.go @@ -48,7 +48,7 @@ func (c *listCache) listBlobs(ctx context.Context, prefix blob.ID) ([]blob.Metad log(ctx).Debugf("listed %v index blobs with prefix %v from source", len(blobs), prefix) - return blobs, err + return blobs, errors.Wrap(err, "error listing blobs") } func (c *listCache) saveListToCache(ctx context.Context, prefix blob.ID, ci *cachedList) { @@ -87,7 +87,7 @@ func (c *listCache) readBlobsFromCache(ctx context.Context, prefix blob.ID) (*ca return nil, blob.ErrBlobNotFound } - return nil, err + return nil, errors.Wrap(err, "error reading blobs from cache") } data, err = hmac.VerifyAndStrip(data, c.hmacSecret) @@ -115,7 +115,7 @@ func newListCache(st blob.Storage, caching *CachingOptions) (*listCache, error) if _, err := os.Stat(caching.CacheDirectory); os.IsNotExist(err) { if err := os.MkdirAll(caching.CacheDirectory, 0o700); err != nil { - return nil, err + return nil, errors.Wrap(err, "error creating list cache directory") } } } diff --git a/repo/content/merged.go b/repo/content/merged.go index b4cf4b146..d455be999 100644 --- a/repo/content/merged.go +++ b/repo/content/merged.go @@ -2,7 +2,8 @@ package content import ( "container/heap" - "errors" + + "github.com/pkg/errors" ) const iterateParallelism = 16 @@ -14,7 +15,7 @@ type mergedIndex []packIndex func (m mergedIndex) Close() error { for _, ndx := range m { if err := ndx.Close(); err != nil { - return err + return errors.Wrap(err, "error closing index shard") } } @@ -28,7 +29,7 @@ func (m mergedIndex) GetInfo(id ID) (*Info, error) { for _, ndx := range m { i, err := ndx.GetInfo(id) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error getting id %v from index shard", id) } if i != nil { @@ -84,7 +85,7 @@ func iterateChan(r IDRange, ndx packIndex, done chan bool) <-chan Info { _ = ndx.Iterate(r, func(i Info) error { select { case <-done: - return errors.New("end of iteration") // nolint:goerr113 + return errors.New("end of iteration") case ch <- i: return nil } diff --git a/repo/format_block.go b/repo/format_block.go index d1f2a26b7..99b362e0e 100644 --- a/repo/format_block.go +++ b/repo/format_block.go @@ -103,13 +103,14 @@ func recoverFormatBlobWithLength(ctx context.Context, st blob.Storage, blobID bl } if chunkLength <= minRecoverableChunkLength { + // nolint:wrapcheck return nil, errFormatBlobNotFound } // try prefix prefixChunk, err := st.GetBlob(ctx, blobID, 0, chunkLength) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error getting blob %v prefix", blobID) } l := decodeInt16(prefixChunk) @@ -122,7 +123,7 @@ func recoverFormatBlobWithLength(ctx context.Context, st blob.Storage, blobID bl // try the suffix suffixChunk, err := st.GetBlob(ctx, blobID, length-chunkLength, chunkLength) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error getting blob %v suffix", blobID) } l = decodeInt16(suffixChunk[len(suffixChunk)-lengthOfRecoverBlockLength:]) @@ -132,6 +133,7 @@ func recoverFormatBlobWithLength(ctx context.Context, st blob.Storage, blobID bl } } + // nolint:wrapcheck return nil, errFormatBlobNotFound } @@ -249,7 +251,7 @@ func encryptFormatBytes(f *formatBlob, format *repositoryObjectFormat, masterKey // Store nonce at the beginning of ciphertext. nonce := cipherText[0:nonceLength] if _, err := io.ReadFull(rand.Reader, nonce); err != nil { - return err + return errors.Wrap(err, "error reading random bytes for nonce") } b := aead.Seal(cipherText[nonceLength:nonceLength], nonce, content, authData) diff --git a/repo/format_block_test.go b/repo/format_block_test.go index 9865cbdce..f54fd83a0 100644 --- a/repo/format_block_test.go +++ b/repo/format_block_test.go @@ -5,6 +5,8 @@ import ( "reflect" "testing" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/blobtesting" "github.com/kopia/kopia/internal/gather" "github.com/kopia/kopia/internal/testlogging" @@ -67,7 +69,7 @@ func TestFormatBlobRecovery(t *testing.T) { t.Errorf("unexpected result or error: v=%v err=%v, expected success", v, err) } } else { - if v != nil || err != tc.err { + if v != nil || !errors.Is(err, tc.err) { t.Errorf("unexpected result or error: v=%v err=%v, expected %v", v, err, tc.err) } } diff --git a/repo/initialize.go b/repo/initialize.go index 7ec5bacf3..5206d9740 100644 --- a/repo/initialize.go +++ b/repo/initialize.go @@ -48,11 +48,12 @@ func Initialize(ctx context.Context, st blob.Storage, opt *NewRepositoryOptions, // get the blob - expect ErrNotFound _, err := st.GetBlob(ctx, FormatBlobID, 0, -1) if err == nil { + // nolint:wrapcheck return ErrAlreadyInitialized } if !errors.Is(err, blob.ErrBlobNotFound) { - return err + return errors.Wrap(err, "unexpected error when checking for format blob") } format := formatBlobFromOptions(opt) diff --git a/repo/local_config.go b/repo/local_config.go index 5ab44a5cb..96990a6a9 100644 --- a/repo/local_config.go +++ b/repo/local_config.go @@ -6,6 +6,8 @@ import ( "io" "os" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo/blob" "github.com/kopia/kopia/repo/content" "github.com/kopia/kopia/repo/object" @@ -96,14 +98,14 @@ func (lc *LocalConfig) Save(w io.Writer) error { _, err = w.Write(b) - return err + return errors.Wrap(err, "error saving local config") } // loadConfigFromFile reads the local configuration from the specified file. func loadConfigFromFile(fileName string) (*LocalConfig, error) { f, err := os.Open(fileName) //nolint:gosec if err != nil { - return nil, err + return nil, errors.Wrap(err, "error loading config file") } defer f.Close() //nolint:errcheck,gosec diff --git a/repo/maintenance/blob_gc.go b/repo/maintenance/blob_gc.go index 1c2dd460e..87a1d3ed5 100644 --- a/repo/maintenance/blob_gc.go +++ b/repo/maintenance/blob_gc.go @@ -94,7 +94,7 @@ func DeleteUnreferencedBlobs(ctx context.Context, rep MaintainableRepository, op // wait for all delete workers to finish. if err := eg.Wait(); err != nil { - return 0, err + return 0, errors.Wrap(err, "worker error") } if opt.DryRun { diff --git a/repo/maintenance/maintenance_params.go b/repo/maintenance/maintenance_params.go index bda1df242..50b736108 100644 --- a/repo/maintenance/maintenance_params.go +++ b/repo/maintenance/maintenance_params.go @@ -117,5 +117,5 @@ func manifestIDs(ctx context.Context, rep MaintainableRepository) ([]*manifest.E return nil, errors.Wrap(err, "error looking for maintenance manifest") } - return md, err + return md, nil } diff --git a/repo/manifest/manifest_manager.go b/repo/manifest/manifest_manager.go index f048969cd..b61f1ff4a 100644 --- a/repo/manifest/manifest_manager.go +++ b/repo/manifest/manifest_manager.go @@ -112,6 +112,7 @@ func (m *Manager) GetMetadata(ctx context.Context, id ID) (*EntryMetadata, error } if e == nil || e.Deleted { + // nolint:wrapcheck return nil, ErrNotFound } @@ -139,6 +140,7 @@ func (m *Manager) Get(ctx context.Context, id ID, data interface{}) (*EntryMetad } if e == nil || e.Deleted { + // nolint:wrapcheck return nil, ErrNotFound } @@ -235,7 +237,7 @@ func (m *Manager) flushPendingEntriesLocked(ctx context.Context) (content.ID, er contentID, err := m.b.WriteContent(ctx, buf.Bytes(), ContentPrefix) if err != nil { - return "", err + return "", errors.Wrap(err, "unable to write content") } for _, e := range m.pendingEntries { @@ -357,9 +359,7 @@ func (m *Manager) loadManifestContent(ctx context.Context, contentID content.ID) blk, err := m.b.GetContent(ctx, contentID) if err != nil { - // do not wrap the error here, we want to propagate original ErrNotFound - // which causes a retry if we lose list/delete race. - return man, err + return man, errors.Wrap(err, "error loading manifest content") } gz, err := gzip.NewReader(bytes.NewReader(blk)) diff --git a/repo/manifest/manifest_manager_test.go b/repo/manifest/manifest_manager_test.go index 783ac89e1..aafb419fb 100644 --- a/repo/manifest/manifest_manager_test.go +++ b/repo/manifest/manifest_manager_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/blobtesting" "github.com/kopia/kopia/internal/testlogging" "github.com/kopia/kopia/repo/content" @@ -261,7 +263,7 @@ func verifyItemNotFound(ctx context.Context, t *testing.T, mgr *Manager, id ID) t.Helper() _, err := mgr.GetMetadata(ctx, id) - if got, want := err, ErrNotFound; got != want { + if got, want := err, ErrNotFound; !errors.Is(got, want) { t.Errorf("invalid error when getting %q %v, expected %v", id, err, ErrNotFound) return } diff --git a/repo/object/object_manager.go b/repo/object/object_manager.go index 01088d8b4..ca8708418 100644 --- a/repo/object/object_manager.go +++ b/repo/object/object_manager.go @@ -239,7 +239,7 @@ func (om *Manager) verifyObjectInternal(ctx context.Context, oid ID, tracker *co if contentID, _, ok := oid.ContentID(); ok { if _, err := om.contentMgr.ContentInfo(ctx, contentID); err != nil { - return err + return errors.Wrapf(err, "error getting content info for %v", contentID) } tracker.addContentID(contentID) @@ -336,7 +336,7 @@ func (om *Manager) newRawReader(ctx context.Context, objectID ID, assertLength i payload, err := om.contentMgr.GetContent(ctx, contentID) if errors.Is(err, content.ErrContentNotFound) { - return nil, ErrObjectNotFound + return nil, errors.Wrapf(ErrObjectNotFound, "content %v not found", contentID) } if err != nil { diff --git a/repo/object/object_manager_test.go b/repo/object/object_manager_test.go index 05c3ff951..02bede19d 100644 --- a/repo/object/object_manager_test.go +++ b/repo/object/object_manager_test.go @@ -585,7 +585,7 @@ func TestReaderStoredBlockNotFound(t *testing.T) { } reader, err := om.Open(ctx, objectID) - if err != ErrObjectNotFound || reader != nil { + if !errors.Is(err, ErrObjectNotFound) || reader != nil { t.Errorf("unexpected result: reader: %v err: %v", reader, err) } } @@ -787,7 +787,7 @@ func TestSeek(t *testing.T) { } buf := make([]byte, 5) - if n, err := r.Read(buf); n != 0 || err != io.EOF { + if n, err := r.Read(buf); n != 0 || !errors.Is(err, io.EOF) { t.Errorf("unexpected read result %v %v", n, err) } } diff --git a/repo/object/object_reader.go b/repo/object/object_reader.go index 67e27876d..0b41d7b47 100644 --- a/repo/object/object_reader.go +++ b/repo/object/object_reader.go @@ -88,7 +88,7 @@ func (r *objectReader) openCurrentChunk() error { b := make([]byte, st.Length) if _, err := io.ReadFull(rd, b); err != nil { - return err + return errors.Wrap(err, "error reading chunk") } r.currentChunkData = b diff --git a/repo/open.go b/repo/open.go index 212811a66..b3f1c1232 100644 --- a/repo/open.go +++ b/repo/open.go @@ -68,7 +68,7 @@ func Open(ctx context.Context, configFile, password string, options *Options) (r configFile, err = filepath.Abs(configFile) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error resolving config file path") } lc, err := loadConfigFromFile(configFile) @@ -149,6 +149,7 @@ func OpenWithConfig(ctx context.Context, st blob.Storage, lc *LocalConfig, passw repoConfig, err := f.decryptFormatBytes(masterKey) if err != nil { + // nolint:wrapcheck return nil, ErrInvalidPassword } @@ -214,12 +215,12 @@ func writeCacheMarker(cacheDir string) error { } if !os.IsNotExist(err) { - return err + return errors.Wrap(err, "unexpected cache marker error") } f, err := os.Create(markerFile) if err != nil { - return err + return errors.Wrap(err, "error creating cache marker") } if _, err := f.WriteString(cacheDirMarkerContents); err != nil { @@ -242,7 +243,7 @@ func (r *DirectRepository) SetCachingConfig(ctx context.Context, opt *content.Ca d, err := json.MarshalIndent(&lc, "", " ") if err != nil { - return err + return errors.Wrap(err, "error marshaling JSON") } if err := ioutil.WriteFile(r.ConfigFile, d, 0o600); err != nil { @@ -269,7 +270,7 @@ func readAndCacheFormatBlobBytes(ctx context.Context, st blob.Storage, cacheDire b, err := st.GetBlob(ctx, FormatBlobID, 0, -1) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error getting format blob") } if cacheDirectory != "" { diff --git a/repo/password.go b/repo/password.go index 49817a3f4..2a78c5bcb 100644 --- a/repo/password.go +++ b/repo/password.go @@ -55,7 +55,7 @@ func persistPassword(ctx context.Context, configFile, password string) error { return nil } - return err + return errors.Wrap(err, "error saving password in key ring") } fn := passwordFileName(configFile) diff --git a/repo/repository.go b/repo/repository.go index 24737b783..e8a8bbbed 100644 --- a/repo/repository.go +++ b/repo/repository.go @@ -158,7 +158,7 @@ func (r *DirectRepository) Close(ctx context.Context) error { // Flush waits for all in-flight writes to complete. func (r *DirectRepository) Flush(ctx context.Context) error { if err := r.Manifests.Flush(ctx); err != nil { - return err + return errors.Wrap(err, "error flushing manifests") } return r.Content.Flush(ctx) diff --git a/repo/repository_test.go b/repo/repository_test.go index e2d57fe33..4e2aaf36b 100644 --- a/repo/repository_test.go +++ b/repo/repository_test.go @@ -8,6 +8,8 @@ import ( "runtime/debug" "testing" + "github.com/pkg/errors" + "github.com/kopia/kopia/internal/repotesting" "github.com/kopia/kopia/internal/testlogging" "github.com/kopia/kopia/repo" @@ -190,7 +192,7 @@ func TestReaderStoredBlockNotFound(t *testing.T) { } reader, err := env.Repository.OpenObject(ctx, objectID) - if err != object.ErrObjectNotFound || reader != nil { + if !errors.Is(err, object.ErrObjectNotFound) || reader != nil { t.Errorf("unexpected result: reader: %v err: %v", reader, err) } } diff --git a/site/cli2md/cli2md.go b/site/cli2md/cli2md.go index 6472dc08a..fbc7659b6 100644 --- a/site/cli2md/cli2md.go +++ b/site/cli2md/cli2md.go @@ -141,7 +141,7 @@ weight: 3 func generateCommands(app *kingpin.ApplicationModel, section string, weight int, advanced bool) error { dir := filepath.Join(baseDir, section) if err := os.MkdirAll(dir, 0o750); err != nil { - return err + return errors.Wrapf(err, "error creating section directory for %v", section) } f, err := os.Create(filepath.Join(dir, "_index.md")) diff --git a/snapshot/manager.go b/snapshot/manager.go index 2421b76c3..0c873cb44 100644 --- a/snapshot/manager.go +++ b/snapshot/manager.go @@ -86,6 +86,7 @@ func LoadSnapshot(ctx context.Context, rep repo.Repository, manifestID manifest. em, err := rep.GetManifest(ctx, manifestID, sm) if err != nil { if errors.Is(err, manifest.ErrNotFound) { + // nolint:wrapcheck return nil, ErrSnapshotNotFound } @@ -117,7 +118,7 @@ func SaveSnapshot(ctx context.Context, rep repo.Repository, man *Manifest) (mani id, err := rep.PutManifest(ctx, sourceInfoToLabels(man.Source), man) if err != nil { - return "", err + return "", errors.Wrap(err, "error putting manifest") } man.ID = id diff --git a/snapshot/manifest.go b/snapshot/manifest.go index 50cc79750..bb4a94aef 100644 --- a/snapshot/manifest.go +++ b/snapshot/manifest.go @@ -6,6 +6,8 @@ import ( "strconv" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo/manifest" "github.com/kopia/kopia/repo/object" @@ -58,12 +60,12 @@ func (p *Permissions) UnmarshalJSON(b []byte) error { var s string if err := json.Unmarshal(b, &s); err != nil { - return err + return errors.Wrap(err, "unable to unmarshal JSON") } v, err := strconv.ParseInt(s, 0, 32) if err != nil { - return err + return errors.Wrap(err, "unable to parse permission string") } *p = Permissions(v) diff --git a/snapshot/policy/expire.go b/snapshot/policy/expire.go index f4a84dab3..a16710d36 100644 --- a/snapshot/policy/expire.go +++ b/snapshot/policy/expire.go @@ -4,6 +4,8 @@ import ( "context" "strings" + "github.com/pkg/errors" + "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot" ) @@ -12,18 +14,18 @@ import ( func ApplyRetentionPolicy(ctx context.Context, rep repo.Repository, sourceInfo snapshot.SourceInfo, reallyDelete bool) ([]*snapshot.Manifest, error) { snapshots, err := snapshot.ListSnapshots(ctx, rep, sourceInfo) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error listing snapshots") } toDelete, err := getExpiredSnapshots(ctx, rep, snapshots) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to compute snapshots to delete") } if reallyDelete { for _, it := range toDelete { if err := rep.DeleteManifest(ctx, it.ID); err != nil { - return toDelete, err + return toDelete, errors.Wrapf(err, "error deleting manifest %v", it.ID) } } } diff --git a/snapshot/policy/policy_manager.go b/snapshot/policy/policy_manager.go index f41d47c82..fc8a73747 100644 --- a/snapshot/policy/policy_manager.go +++ b/snapshot/policy/policy_manager.go @@ -30,7 +30,7 @@ func GetEffectivePolicy(ctx context.Context, rep repo.Repository, si snapshot.So for tmp := si; len(si.Path) > 0; { manifests, err := rep.FindManifests(ctx, labelsForSource(tmp)) if err != nil { - return nil, nil, err + return nil, nil, errors.Wrapf(err, "unable to find manifest for source %v", tmp) } md = append(md, manifests...) @@ -46,7 +46,7 @@ func GetEffectivePolicy(ctx context.Context, rep repo.Repository, si snapshot.So // Try user@host policy userHostManifests, err := rep.FindManifests(ctx, labelsForSource(snapshot.SourceInfo{Host: si.Host, UserName: si.UserName})) if err != nil { - return nil, nil, err + return nil, nil, errors.Wrap(err, "unable to find user@host manifest") } md = append(md, userHostManifests...) @@ -54,7 +54,7 @@ func GetEffectivePolicy(ctx context.Context, rep repo.Repository, si snapshot.So // Try host-level policy. hostManifests, err := rep.FindManifests(ctx, labelsForSource(snapshot.SourceInfo{Host: si.Host})) if err != nil { - return nil, nil, err + return nil, nil, errors.Wrap(err, "unable to find host-level manifest") } md = append(md, hostManifests...) @@ -62,7 +62,7 @@ func GetEffectivePolicy(ctx context.Context, rep repo.Repository, si snapshot.So // Global policy. globalManifests, err := rep.FindManifests(ctx, labelsForSource(GlobalPolicySourceInfo)) if err != nil { - return nil, nil, err + return nil, nil, errors.Wrap(err, "unable to find global manifest") } md = append(md, globalManifests...) @@ -119,7 +119,7 @@ func SetPolicy(ctx context.Context, rep repo.Repository, si snapshot.SourceInfo, } if _, err := rep.PutManifest(ctx, labelsForSource(si), pol); err != nil { - return err + return errors.Wrap(err, "error writing policy manifest") } for _, em := range md { @@ -254,7 +254,7 @@ func loadPolicyFromManifest(ctx context.Context, rep repo.Repository, id manifes return ErrPolicyNotFound } - return err + return errors.Wrapf(err, "error loading policy for manifest %v", id) } pol.Labels = md.Labels diff --git a/snapshot/restore/local_fs_output.go b/snapshot/restore/local_fs_output.go index 2e4385a5c..da0d92db1 100644 --- a/snapshot/restore/local_fs_output.go +++ b/snapshot/restore/local_fs_output.go @@ -249,14 +249,14 @@ func (o *FilesystemOutput) copyFileContent(ctx context.Context, targetPath strin func isEmptyDirectory(name string) (bool, error) { f, err := os.Open(name) //nolint:gosec if err != nil { - return false, err + return false, errors.Wrap(err, "error opening directory") } defer f.Close() //nolint:errcheck,gosec - if _, err = f.Readdirnames(1); err == io.EOF { + if _, err = f.Readdirnames(1); errors.Is(err, io.EOF) { return true, nil } - return false, err // Either not empty or error + return false, errors.Wrap(err, "error reading directory") // Either not empty or error } diff --git a/snapshot/restore/local_fs_output_windows.go b/snapshot/restore/local_fs_output_windows.go index ce0862613..3e7b69034 100644 --- a/snapshot/restore/local_fs_output_windows.go +++ b/snapshot/restore/local_fs_output_windows.go @@ -31,7 +31,7 @@ func symlinkChtimes(linkPath string, atime, mtime time.Time) error { nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OPEN_REPARSE_POINT, 0) if err != nil { - return err + return errors.Wrap(err, "CreateFile error") } defer windows.CloseHandle(h) //nolint:errcheck diff --git a/snapshot/restore/restore.go b/snapshot/restore/restore.go index 6c725c54d..66f06f359 100644 --- a/snapshot/restore/restore.go +++ b/snapshot/restore/restore.go @@ -147,7 +147,7 @@ func (c *copier) copyDirectory(ctx context.Context, d fs.Directory, targetPath s func (c *copier) copyDirectoryContent(ctx context.Context, d fs.Directory, targetPath string, onCompletion parallelwork.CallbackFunc) error { entries, err := d.Readdir(ctx) if err != nil { - return err + return errors.Wrap(err, "error reading directory") } if len(entries) == 0 { diff --git a/snapshot/snapshotfs/all_sources.go b/snapshot/snapshotfs/all_sources.go index a2b4dfb2a..e0992af21 100644 --- a/snapshot/snapshotfs/all_sources.go +++ b/snapshot/snapshotfs/all_sources.go @@ -6,6 +6,8 @@ import ( "os" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot" @@ -58,7 +60,7 @@ func (s *repositoryAllSources) Child(ctx context.Context, name string) (fs.Entry func (s *repositoryAllSources) Readdir(ctx context.Context) (fs.Entries, error) { srcs, err := snapshot.ListSources(ctx, s.rep) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error listing sources") } users := map[string]bool{} diff --git a/snapshot/snapshotfs/objref.go b/snapshot/snapshotfs/objref.go index 4c360c238..3837851b4 100644 --- a/snapshot/snapshotfs/objref.go +++ b/snapshot/snapshotfs/objref.go @@ -47,7 +47,7 @@ func GetNestedEntry(ctx context.Context, startingDir fs.Entry, pathElements []st entries, err := dir.Readdir(ctx) if err != nil { - return nil, err + return nil, errors.Wrap(err, "error reading directory") } e := entries.FindByName(part) @@ -83,7 +83,7 @@ func findSnapshotByRootObjectIDOrManifestID(ctx context.Context, rep repo.Reposi mans, err := snapshot.FindSnapshotsByRootObjectID(ctx, rep, object.ID(rootID)) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to find shapshots by ID %v", rootID) } // no matching snapshots. diff --git a/snapshot/snapshotfs/repofs.go b/snapshot/snapshotfs/repofs.go index 857a3cfde..a57c12f55 100644 --- a/snapshot/snapshotfs/repofs.go +++ b/snapshot/snapshotfs/repofs.go @@ -103,7 +103,7 @@ func (rd *repositoryDirectory) Summary(ctx context.Context) (*fs.DirectorySummar r, err := rd.repo.OpenObject(ctx, rd.metadata.ObjectID) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to open object: %v", rd.metadata.ObjectID) } defer r.Close() //nolint:errcheck @@ -122,7 +122,7 @@ func (rd *repositoryDirectory) Child(ctx context.Context, name string) (fs.Entry func (rd *repositoryDirectory) Readdir(ctx context.Context) (fs.Entries, error) { r, err := rd.repo.OpenObject(ctx, rd.metadata.ObjectID) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to open object: %v", rd.metadata.ObjectID) } defer r.Close() //nolint:errcheck @@ -147,7 +147,7 @@ func (rd *repositoryDirectory) Readdir(ctx context.Context) (fs.Entries, error) func (rf *repositoryFile) Open(ctx context.Context) (fs.Reader, error) { r, err := rf.repo.OpenObject(ctx, rf.metadata.ObjectID) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "unable to open object: %v", rf.metadata.ObjectID) } return withFileInfo(r, rf), nil @@ -156,14 +156,14 @@ func (rf *repositoryFile) Open(ctx context.Context) (fs.Reader, error) { func (rsl *repositorySymlink) Readlink(ctx context.Context) (string, error) { r, err := rsl.repo.OpenObject(ctx, rsl.metadata.ObjectID) if err != nil { - return "", err + return "", errors.Wrapf(err, "unable to open object: %v", rsl.metadata.ObjectID) } defer r.Close() //nolint:errcheck b, err := ioutil.ReadAll(r) if err != nil { - return "", err + return "", errors.Wrapf(err, "unable to read object: %v", rsl.metadata.ObjectID) } return string(b), nil diff --git a/snapshot/snapshotfs/source_directories.go b/snapshot/snapshotfs/source_directories.go index 53fb8b1ab..6c8f0ccfd 100644 --- a/snapshot/snapshotfs/source_directories.go +++ b/snapshot/snapshotfs/source_directories.go @@ -5,6 +5,8 @@ import ( "os" "time" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" "github.com/kopia/kopia/repo" "github.com/kopia/kopia/snapshot" @@ -58,7 +60,7 @@ func (s *sourceDirectories) Child(ctx context.Context, name string) (fs.Entry, e func (s *sourceDirectories) Readdir(ctx context.Context) (fs.Entries, error) { sources, err := snapshot.ListSources(ctx, s.rep) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to list sources") } var result fs.Entries diff --git a/snapshot/snapshotfs/source_snapshots.go b/snapshot/snapshotfs/source_snapshots.go index f287330f8..b54d683b9 100644 --- a/snapshot/snapshotfs/source_snapshots.go +++ b/snapshot/snapshotfs/source_snapshots.go @@ -67,7 +67,7 @@ func (s *sourceSnapshots) Child(ctx context.Context, name string) (fs.Entry, err func (s *sourceSnapshots) Readdir(ctx context.Context) (fs.Entries, error) { manifests, err := snapshot.ListSnapshots(ctx, s.rep, s.src) if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to list snapshots") } var result fs.Entries diff --git a/snapshot/snapshotfs/upload.go b/snapshot/snapshotfs/upload.go index b167d7058..e63926386 100644 --- a/snapshot/snapshotfs/upload.go +++ b/snapshot/snapshotfs/upload.go @@ -127,7 +127,7 @@ func (u *Uploader) uploadFileInternal(ctx context.Context, parentCheckpointRegis // nolint:govet checkpointID, err := writer.Checkpoint() if err != nil { - return nil, err + return nil, errors.Wrap(err, "checkpoint error") } if checkpointID == "" { @@ -146,12 +146,12 @@ func (u *Uploader) uploadFileInternal(ctx context.Context, parentCheckpointRegis fi2, err := file.Entry() if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to get file entry after copying") } r, err := writer.Result() if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to get result") } de, err := newDirEntry(fi2, r) @@ -188,7 +188,7 @@ func (u *Uploader) uploadSymlinkInternal(ctx context.Context, relativePath strin r, err := writer.Result() if err != nil { - return nil, err + return nil, errors.Wrap(err, "unable to get result") } de, err := newDirEntry(f, r) @@ -211,7 +211,7 @@ func (u *Uploader) copyWithProgress(dst io.Writer, src io.Reader, completed, len for { if u.IsCanceled() { - return 0, errCanceled + return 0, errors.Wrap(errCanceled, "canceled when copying data") } readBytes, readErr := src.Read(uploadBuf) @@ -231,6 +231,7 @@ func (u *Uploader) copyWithProgress(dst io.Writer, src io.Reader, completed, len } if writeErr != nil { + // nolint:wrapcheck return written, writeErr } @@ -240,10 +241,11 @@ func (u *Uploader) copyWithProgress(dst io.Writer, src io.Reader, completed, len } if readErr != nil { - if readErr == io.EOF { + if errors.Is(readErr, io.EOF) { break } + // nolint:wrapcheck return written, readErr } } @@ -448,6 +450,7 @@ func (u *Uploader) foreachEntryUnlessCanceled(ctx context.Context, parallel int, eg.Go(func() error { for entry := range ch { if u.IsCanceled() { + // nolint:wrapcheck return errCanceled } @@ -466,7 +469,9 @@ func (u *Uploader) foreachEntryUnlessCanceled(ctx context.Context, parallel int, func rootCauseError(err error) error { err = errors.Cause(err) - if oserr, ok := err.(*os.PathError); ok { + + var oserr *os.PathError + if errors.As(err, &oserr) { err = oserr.Err } @@ -647,7 +652,9 @@ func (u *Uploader) processSubdirectories( // root itself. The intention is to always fail if the top level directory can't be read, // otherwise a meaningless, empty snapshot is created that can't be restored. ignoreDirErr := u.shouldIgnoreDirectoryReadErrors(policyTree) - if dre, ok := err.(dirReadError); ok && ignoreDirErr { + + var dre dirReadError + if errors.As(err, &dre) && ignoreDirErr { rc := rootCauseError(dre.error) u.Progress.IgnoredError(entryRelativePath, rc) diff --git a/snapshot/snapshotfs/upload_actions.go b/snapshot/snapshotfs/upload_actions.go index 9f4fc006b..d7d3c87b9 100644 --- a/snapshot/snapshotfs/upload_actions.go +++ b/snapshot/snapshotfs/upload_actions.go @@ -70,7 +70,7 @@ func (hc *actionContext) ensureInitialized(ctx context.Context, actionType, dirP wd, err := ioutil.TempDir("", "kopia-action") if err != nil { - return err + return errors.Wrap(err, "error temporary directory for action execution") } hc.WorkDir = wd @@ -105,7 +105,7 @@ func prepareCommandForAction(ctx context.Context, actionType string, h *policy.A if err := ioutil.WriteFile(scriptFile, []byte(h.Script), actionScriptPermissions); err != nil { cancel() - return nil, nil, err + return nil, nil, errors.Wrap(err, "error writing script for execution") } switch { @@ -161,7 +161,7 @@ func runActionCommand( v, err := cmd.Output() if err != nil { if h.Mode == "essential" { - return err + return errors.Wrap(err, "essential action failed") } log(ctx).Warningf("error running non-essential action command: %v", err) diff --git a/snapshot/snapshotfs/upload_scan.go b/snapshot/snapshotfs/upload_scan.go index 8dfa1f722..eaef54927 100644 --- a/snapshot/snapshotfs/upload_scan.go +++ b/snapshot/snapshotfs/upload_scan.go @@ -3,6 +3,8 @@ package snapshotfs import ( "context" + "github.com/pkg/errors" + "github.com/kopia/kopia/fs" ) @@ -22,12 +24,13 @@ func (u *Uploader) scanDirectory(ctx context.Context, dir fs.Directory) (scanRes entries, err := dir.Readdir(ctx) if err != nil { - return res, err + return res, errors.Wrap(err, "unable to read directory") } for _, e := range entries { if err := ctx.Err(); err != nil { // terminate early if context got canceled + // nolint:wrapcheck return res, err } diff --git a/snapshot/snapshotgc/gc.go b/snapshot/snapshotgc/gc.go index 26032efef..e0279e01e 100644 --- a/snapshot/snapshotgc/gc.go +++ b/snapshot/snapshotgc/gc.go @@ -82,7 +82,7 @@ func Run(ctx context.Context, rep *repo.DirectRepository, params maintenance.Sna return runInternal(ctx, rep, params, gcDelete, &st) }) - return st, err + return st, errors.Wrap(err, "error running snapshot gc") } func runInternal(ctx context.Context, rep *repo.DirectRepository, params maintenance.SnapshotGCParams, gcDelete bool, st *Stats) error { diff --git a/tests/end_to_end_test/restore_fail_test.go b/tests/end_to_end_test/restore_fail_test.go index 2fa9aeaa2..7d702e701 100644 --- a/tests/end_to_end_test/restore_fail_test.go +++ b/tests/end_to_end_test/restore_fail_test.go @@ -24,8 +24,8 @@ import ( // 7. Issue kopia blob delete on the ID of the found pack blob // 8. Attempt a snapshot restore on the snapshot, expecting failure // Pass Criteria: Kopia commands issue successfully, except the final restore -// command is expected to fail. Expect to find new blobs after a snapshot -// and expect one of them is a pack blob type prefixed with "p". +// command is expected to fail. Expect to find new blobs after a snapshot +// and expect one of them is a pack blob type prefixed with "p". func TestRestoreFail(t *testing.T) { t.Parallel() diff --git a/tests/end_to_end_test/restore_test.go b/tests/end_to_end_test/restore_test.go index afe036c7c..673e5b33c 100644 --- a/tests/end_to_end_test/restore_test.go +++ b/tests/end_to_end_test/restore_test.go @@ -4,6 +4,7 @@ import ( "archive/tar" "archive/zip" "compress/gzip" + "errors" "fmt" "io" "os" @@ -444,7 +445,7 @@ func verifyValidTarReader(t *testing.T, tr *tar.Reader) { _, err = tr.Next() } - if err != io.EOF { + if !errors.Is(err, io.EOF) { t.Fatalf("invalid tar file: %v", err) } } diff --git a/tests/perf_benchmark/process_results.go b/tests/perf_benchmark/process_results.go index 77d414ab3..ff9a330ce 100644 --- a/tests/perf_benchmark/process_results.go +++ b/tests/perf_benchmark/process_results.go @@ -108,7 +108,7 @@ func parseRepoSize(fname string) (int64, error) { s.Scan() fields := strings.Fields(s.Text()) - if len(fields) != 2 { // nolint:gomnd + if len(fields) != 2 { return 0, errors.Errorf("unvalid repo size format") } diff --git a/tests/robustness/engine/engine_test.go b/tests/robustness/engine/engine_test.go index b9b539f08..4b99711cf 100644 --- a/tests/robustness/engine/engine_test.go +++ b/tests/robustness/engine/engine_test.go @@ -44,7 +44,7 @@ var ( func TestEngineWritefilesBasicFS(t *testing.T) { eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -154,7 +154,7 @@ func TestWriteFilesBasicS3(t *testing.T) { defer cleanupCB() eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -196,7 +196,7 @@ func TestDeleteSnapshotS3(t *testing.T) { defer cleanupCB() eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -239,7 +239,7 @@ func TestSnapshotVerificationFail(t *testing.T) { defer cleanupCB() eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -304,7 +304,7 @@ func TestDataPersistency(t *testing.T) { defer os.RemoveAll(tempDir) eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -461,7 +461,7 @@ func TestPickActionWeighted(t *testing.T) { func TestActionsFilesystem(t *testing.T) { eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -495,7 +495,7 @@ func TestActionsFilesystem(t *testing.T) { numActions := 10 for loop := 0; loop < numActions; loop++ { err := eng.RandomAction(actionOpts) - if !(err == nil || err == ErrNoOp) { + if !(err == nil || errors.Is(err, ErrNoOp)) { t.Error("Hit error", err) } } @@ -506,7 +506,7 @@ func TestActionsS3(t *testing.T) { defer cleanupCB() eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } @@ -538,7 +538,7 @@ func TestActionsS3(t *testing.T) { numActions := 10 for loop := 0; loop < numActions; loop++ { err := eng.RandomAction(actionOpts) - if !(err == nil || err == ErrNoOp) { + if !(err == nil || errors.Is(err, ErrNoOp)) { t.Error("Hit error", err) } } @@ -553,7 +553,7 @@ func TestIOLimitPerWriteAction(t *testing.T) { const timeout = 10 * time.Second eng, err := NewEngine("") - if err == kopiarunner.ErrExeVariableNotSet || errors.Is(err, fio.ErrEnvNotSet) { + if errors.Is(err, kopiarunner.ErrExeVariableNotSet) || errors.Is(err, fio.ErrEnvNotSet) { t.Skip(err) } diff --git a/tests/robustness/robustness_test/main_test.go b/tests/robustness/robustness_test/main_test.go index 654a41d0e..5b95bafc4 100644 --- a/tests/robustness/robustness_test/main_test.go +++ b/tests/robustness/robustness_test/main_test.go @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { eng, err = engine.NewEngine("") switch { - case err == kopiarunner.ErrExeVariableNotSet: + case errors.Is(err, kopiarunner.ErrExeVariableNotSet): log.Println("Skipping robustness tests because KOPIA_EXE is not set") os.Exit(0) case errors.Is(err, fio.ErrEnvNotSet): @@ -65,7 +65,7 @@ func TestMain(m *testing.M) { // Restore a random snapshot into the data directory _, err = eng.ExecAction(engine.RestoreIntoDataDirectoryActionKey, nil) - if err != nil && err != engine.ErrNoOp { + if err != nil && !errors.Is(err, engine.ErrNoOp) { eng.Cleanup() log.Fatalln("error restoring into the data directory:", err) } diff --git a/tests/robustness/robustness_test/robustness_test.go b/tests/robustness/robustness_test/robustness_test.go index ab5e642ce..7aab3eac9 100644 --- a/tests/robustness/robustness_test/robustness_test.go +++ b/tests/robustness/robustness_test/robustness_test.go @@ -3,6 +3,7 @@ package robustness import ( + "errors" "fmt" "strconv" "testing" @@ -103,7 +104,7 @@ func TestRandomizedSmall(t *testing.T) { for time.Since(st) <= *randomizedTestDur { err := eng.RandomAction(opts) - if err == engine.ErrNoOp { + if errors.Is(err, engine.ErrNoOp) { t.Log("Random action resulted in no-op") err = nil diff --git a/tests/testenv/faketimeserver.go b/tests/testenv/faketimeserver.go index eb27619a5..0ff226210 100644 --- a/tests/testenv/faketimeserver.go +++ b/tests/testenv/faketimeserver.go @@ -52,7 +52,7 @@ func (s *FakeTimeServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { func NewFakeTimeServer(startTime time.Time, step time.Duration) *FakeTimeServer { return &FakeTimeServer{ nextTimeChunk: startTime, - timeChunkLength: 100 * step, // nolint:gomnd + timeChunkLength: 100 * step, step: step, } } diff --git a/tests/tools/fio/fio.go b/tests/tools/fio/fio.go index d0b0f5330..18c264bd0 100644 --- a/tests/tools/fio/fio.go +++ b/tests/tools/fio/fio.go @@ -238,7 +238,6 @@ func (fr *Runner) Run(args ...string) (stdout, stderr string, err error) { log.Printf("running '%s %v'", fr.Exe, argsStr) } - // nolint:gosec c := exec.Command(fr.Exe, args...) errOut := &bytes.Buffer{} diff --git a/tests/tools/fio/workload.go b/tests/tools/fio/workload.go index 502a93458..a002e32e7 100644 --- a/tests/tools/fio/workload.go +++ b/tests/tools/fio/workload.go @@ -68,7 +68,7 @@ func (fr *Runner) WriteFilesAtDepthRandomBranch(relBasePath string, depth int, o return errors.Wrapf(err, "unable to make base dir %v for writing at depth with a branch", fullBasePath) } - return fr.writeFilesAtDepth(fullBasePath, depth, rand.Intn(depth+1), opt) // nolint:gosec + return fr.writeFilesAtDepth(fullBasePath, depth, rand.Intn(depth+1), opt) } // DeleteRelDir deletes a relative directory in the runner's data directory. @@ -102,7 +102,7 @@ func (fr *Runner) DeleteContentsAtDepth(relBasePath string, depth int, prob floa } for _, fi := range fileInfoList { - if rand.Float32() < prob { // nolint:gosec + if rand.Float32() < prob { path := filepath.Join(dirPath, fi.Name()) err = os.RemoveAll(path) if err != nil { diff --git a/tests/tools/kopiarunner/kopia_snapshotter.go b/tests/tools/kopiarunner/kopia_snapshotter.go index d36166374..709c10c9e 100644 --- a/tests/tools/kopiarunner/kopia_snapshotter.go +++ b/tests/tools/kopiarunner/kopia_snapshotter.go @@ -299,7 +299,7 @@ func (ks *KopiaSnapshotter) createAndConnectServer(serverAddr string, args ...st return nil, tempDirErr } - defer os.RemoveAll(tempDir) // nolint:errcheck + defer os.RemoveAll(tempDir) tlsCertFile := filepath.Join(tempDir, "kopiaserver.cert") tlsKeyFile := filepath.Join(tempDir, "kopiaserver.key") diff --git a/tests/tools/kopiarunner/kopia_snapshotter_exe_test.go b/tests/tools/kopiarunner/kopia_snapshotter_exe_test.go index 932888124..2b81f14e3 100644 --- a/tests/tools/kopiarunner/kopia_snapshotter_exe_test.go +++ b/tests/tools/kopiarunner/kopia_snapshotter_exe_test.go @@ -1,6 +1,7 @@ package kopiarunner import ( + "errors" "fmt" "io/ioutil" "os" @@ -22,7 +23,7 @@ func TestParseSnapListAllExeTest(t *testing.T) { testenv.AssertNoError(t, err) ks, err := NewKopiaSnapshotter(repoDir) - if err == ErrExeVariableNotSet { + if errors.Is(err, ErrExeVariableNotSet) { t.Skip("KOPIA_EXE not set, skipping test") } diff --git a/tests/tools/kopiarunner/kopiarun.go b/tests/tools/kopiarunner/kopiarun.go index 3746dead0..e9df12dcb 100644 --- a/tests/tools/kopiarunner/kopiarun.go +++ b/tests/tools/kopiarunner/kopiarun.go @@ -13,7 +13,7 @@ import ( ) const ( - repoPassword = "qWQPJ2hiiLgWRRCr" // nolint:gosec + repoPassword = "qWQPJ2hiiLgWRRCr" ) // Runner is a helper for running kopia commands. @@ -64,7 +64,6 @@ func (kr *Runner) Run(args ...string) (stdout, stderr string, err error) { argsStr := strings.Join(args, " ") log.Printf("running '%s %v'", kr.Exe, argsStr) cmdArgs := append(append([]string(nil), kr.fixedArgs...), args...) - // nolint:gosec c := exec.Command(kr.Exe, cmdArgs...) c.Env = append(os.Environ(), kr.environment...) diff --git a/tools/tools.mk b/tools/tools.mk index 93e43891a..7cf305b19 100644 --- a/tools/tools.mk +++ b/tools/tools.mk @@ -108,7 +108,7 @@ SELF_DIR := $(subst /,$(slash),$(realpath $(dir $(lastword $(MAKEFILE_LIST))))) TOOLS_DIR:=$(SELF_DIR)$(slash).tools # tool versions -GOLANGCI_LINT_VERSION=1.30.0 +GOLANGCI_LINT_VERSION=1.33.0 NODE_VERSION=12.18.3 HUGO_VERSION=0.74.3 GOTESTSUM_VERSION=0.5.3