diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 04f2df367..63814fb93 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -10,6 +10,7 @@ import ( "path" "path/filepath" "runtime" + "slices" "strconv" "strings" "time" @@ -181,7 +182,7 @@ var ErrNoSourceData = errors.Fatal("all source directories/files do not exist") // filterExisting returns the items that exist and can be accessed. It returns // ErrNoSourceData if none remain, or ErrInvalidSourceData if some were skipped. -func filterExisting(items []string, warnf func(msg string, args ...interface{})) (result []string, err error) { +func filterExisting(items []string, warnf func(msg string, args ...any)) (result []string, err error) { for _, item := range items { _, err := fs.Lstat(item) if err != nil { @@ -304,10 +305,8 @@ func (opts BackupOptions) Check(gopts global.Options, args []string) error { } filesFrom := append(append(opts.FilesFrom, opts.FilesFromVerbatim...), opts.FilesFromRaw...) - for _, filename := range filesFrom { - if filename == "-" { - return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD") - } + if slices.Contains(filesFrom, "-") { + return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD") } } @@ -332,7 +331,7 @@ func (opts BackupOptions) Check(gopts global.Options, args []string) error { // collectRejectByNameFuncs returns a list of all functions which may reject data // from being saved in a snapshot based on path only -func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, warnf func(msg string, args ...interface{})) (fs []archiver.RejectByNameFunc, err error) { +func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, warnf func(msg string, args ...any)) (fs []archiver.RejectByNameFunc, err error) { // exclude restic cache if repo.Cache() != nil { f, err := rejectResticCache(repo) @@ -356,7 +355,7 @@ func collectRejectByNameFuncs(opts BackupOptions, repo *repository.Repository, w // collectRejectFuncs returns a list of all functions which may reject data // from being saved in a snapshot based on path and file info -func collectRejectFuncs(opts BackupOptions, targets []string, fs fs.FS, warnf func(msg string, args ...interface{})) (funcs []archiver.RejectFunc, err error) { +func collectRejectFuncs(opts BackupOptions, targets []string, fs fs.FS, warnf func(msg string, args ...any)) (funcs []archiver.RejectFunc, err error) { // allowed devices if opts.ExcludeOtherFS && !opts.Stdin && !opts.StdinCommand { f, err := archiver.RejectByDevice(targets, fs) @@ -404,7 +403,7 @@ func collectRejectFuncs(opts BackupOptions, targets []string, fs fs.FS, warnf fu } // collectTargets returns a list of target files/dirs from several sources. -func collectTargets(opts BackupOptions, args []string, warnf func(msg string, args ...interface{}), stdin io.ReadCloser) (targets []string, err error) { +func collectTargets(opts BackupOptions, args []string, warnf func(msg string, args ...any), stdin io.ReadCloser) (targets []string, err error) { if opts.Stdin || opts.StdinCommand { return nil, nil } @@ -589,7 +588,7 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts global.Options, te _ = progressReporter.Error(item, err) } - messageHandler := func(msg string, args ...interface{}) { + messageHandler := func(msg string, args ...any) { if !gopts.JSON { printer.P(msg, args...) } diff --git a/cmd/restic/cmd_backup_integration_test.go b/cmd/restic/cmd_backup_integration_test.go index cfca46ce1..190d9cc94 100644 --- a/cmd/restic/cmd_backup_integration_test.go +++ b/cmd/restic/cmd_backup_integration_test.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strings" "testing" "time" @@ -154,7 +155,7 @@ func (f *vssDeleteOriginalFS) Lstat(name string) (*fs.ExtendedFileInfo, error) { _, _ = f.FS.Lstat(name) // nuke testdata var err error - for i := 0; i < 3; i++ { + for range 3 { // The CI sometimes runs into "The process cannot access the file because it is being used by another process" errors // thus try a few times to remove the data err = os.RemoveAll(f.testdata) @@ -630,13 +631,7 @@ func linkEqual(source, dest []string) bool { } for i := range source { - found := false - for j := range dest { - if source[i] == dest[j] { - found = true - break - } - } + found := slices.Contains(dest, source[i]) if !found { return false } @@ -738,7 +733,7 @@ func TestBackupSkipIfUnchanged(t *testing.T) { testSetupBackupData(t, env) opts := BackupOptions{SkipIfUnchanged: true} - for i := 0; i < 3; i++ { + for range 3 { testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, opts, env.gopts) testListSnapshots(t, env.gopts, 1) } @@ -760,7 +755,7 @@ func TestBackupExcludeWithOutput(t *testing.T) { rtest.OK(t, err) foundExclude := false - for _, line := range bytes.Split(output, []byte("\n")) { + for line := range bytes.SplitSeq(output, []byte("\n")) { if len(line) == 0 { continue } diff --git a/cmd/restic/cmd_cat.go b/cmd/restic/cmd_cat.go index 71b9c2e71..f8a33cabd 100644 --- a/cmd/restic/cmd_cat.go +++ b/cmd/restic/cmd_cat.go @@ -3,6 +3,7 @@ package main import ( "context" "encoding/json" + "slices" "strings" "github.com/spf13/cobra" @@ -49,13 +50,7 @@ func validateCatArgs(args []string) error { return errors.Fatal("type not specified") } - validType := false - for _, v := range catAllowedCmds { - if v == args[0] { - validType = true - break - } - } + validType := slices.Contains(catAllowedCmds, args[0]) if !validType { return errors.Fatalf("invalid type %q, must be one of [%s]", args[0], strings.Join(catAllowedCmds, "|")) } diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index b0238c0a1..cdfcb8cbc 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -342,13 +342,11 @@ func runCheck(ctx context.Context, opts CheckOptions, gopts global.Options, args var brokenSnapshots []string var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { bar := printer.NewCounter("snapshots") defer bar.Done() chkr.Structure(ctx, bar, errChan) - }() + }) for err := range errChan { errorsFound = true @@ -570,15 +568,15 @@ func (*jsonErrorPrinter) NewCounterTerminalOnly(_ string) restic.Counter { return restic.NoopCounter } -func (p *jsonErrorPrinter) E(msg string, args ...interface{}) { +func (p *jsonErrorPrinter) E(msg string, args ...any) { status := checkError{ MessageType: "error", Message: fmt.Sprintf(msg, args...), } p.term.Error(ui.ToJSONString(status)) } -func (*jsonErrorPrinter) S(_ string, _ ...interface{}) {} -func (*jsonErrorPrinter) P(_ string, _ ...interface{}) {} -func (*jsonErrorPrinter) PT(_ string, _ ...interface{}) {} -func (*jsonErrorPrinter) V(_ string, _ ...interface{}) {} -func (*jsonErrorPrinter) VV(_ string, _ ...interface{}) {} +func (*jsonErrorPrinter) S(_ string, _ ...any) {} +func (*jsonErrorPrinter) P(_ string, _ ...any) {} +func (*jsonErrorPrinter) PT(_ string, _ ...any) {} +func (*jsonErrorPrinter) V(_ string, _ ...any) {} +func (*jsonErrorPrinter) VV(_ string, _ ...any) {} diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index bfecee989..1519b37c7 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -84,7 +84,7 @@ type Comparer struct { repo restic.BlobLoader opts DiffOptions printChange func(change *Change) - printError func(string, ...interface{}) + printError func(string, ...any) } type Change struct { @@ -158,7 +158,7 @@ type DiffStatsContainer struct { } // updateBlobs updates the blob counters in the stats struct. -func updateBlobs(repo restic.Loader, blobs restic.AssociatedBlobSet, stats *DiffStat, printError func(string, ...interface{})) { +func updateBlobs(repo restic.Loader, blobs restic.AssociatedBlobSet, stats *DiffStat, printError func(string, ...any)) { for h := range blobs.Keys() { switch h.Type { case restic.DataBlob: diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 8dbe35160..e3e5aa631 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -136,9 +136,9 @@ type statefulOutput struct { oldsn *data.Snapshot hits int printer interface { - S(string, ...interface{}) - P(string, ...interface{}) - E(string, ...interface{}) + S(string, ...any) + P(string, ...any) + E(string, ...any) } stdout io.Writer } @@ -214,7 +214,7 @@ func (s *statefulOutput) PrintObjectJSON(kind, id, nodepath, treeID string, sn * Path string `json:"path"` ParentTree string `json:"parent_tree,omitempty"` SnapshotID string `json:"snapshot"` - Time time.Time `json:"time,omitempty"` + Time time.Time `json:"time"` }{ ObjectType: kind, ID: id, @@ -281,9 +281,9 @@ type Finder struct { treeIDs map[string]struct{} itemsFound int printer interface { - S(string, ...interface{}) - P(string, ...interface{}) - E(string, ...interface{}) + S(string, ...any) + P(string, ...any) + E(string, ...any) } } diff --git a/cmd/restic/cmd_find_integration_test.go b/cmd/restic/cmd_find_integration_test.go index f8d54b164..1133de350 100644 --- a/cmd/restic/cmd_find_integration_test.go +++ b/cmd/restic/cmd_find_integration_test.go @@ -51,7 +51,7 @@ type testMatch struct { Path string `json:"path,omitempty"` Permissions string `json:"permissions,omitempty"` Size uint64 `json:"size,omitempty"` - Date time.Time `json:"date,omitempty"` + Date time.Time `json:"date"` UID uint32 `json:"uid,omitempty"` GID uint32 `json:"gid,omitempty"` } @@ -154,7 +154,7 @@ type JSONOutput struct { Path string `json:"path"` ParentTree string `json:"parent_tree,omitempty"` SnapshotID string `json:"snapshot"` - Time time.Time `json:"time,omitempty"` + Time time.Time `json:"time"` } func TestFindPackfile(t *testing.T) { diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index 93341ab65..2052a4271 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -130,9 +130,9 @@ type lsNodeOutput struct { Size *uint64 `json:"size,omitempty"` Mode os.FileMode `json:"mode,omitempty"` Permissions string `json:"permissions,omitempty"` - ModTime time.Time `json:"mtime,omitempty"` - AccessTime time.Time `json:"atime,omitempty"` - ChangeTime time.Time `json:"ctime,omitempty"` + ModTime time.Time `json:"mtime"` + AccessTime time.Time `json:"atime"` + ChangeTime time.Time `json:"ctime"` Inode uint64 `json:"inode,omitempty"` MessageType string `json:"message_type"` StructType string `json:"struct_type"` @@ -290,8 +290,8 @@ type textLsPrinter struct { ListLong bool HumanReadable bool termPrinter interface { - P(msg string, args ...interface{}) - S(msg string, args ...interface{}) + P(msg string, args ...any) + S(msg string, args ...any) } } diff --git a/cmd/restic/cmd_ls_test.go b/cmd/restic/cmd_ls_test.go index bbf92e6df..dc744883c 100644 --- a/cmd/restic/cmd_ls_test.go +++ b/cmd/restic/cmd_ls_test.go @@ -101,7 +101,7 @@ func TestLsNodeJSON(t *testing.T) { rtest.Equals(t, expect+"\n", buf.String()) // Sanity check: output must be valid JSON. - var v interface{} + var v any err = json.NewDecoder(buf).Decode(&v) rtest.OK(t, err) } @@ -121,7 +121,7 @@ func TestLsNcduNode(t *testing.T) { rtest.Equals(t, expect, string(out)) // Sanity check: output must be valid JSON. - var v interface{} + var v any err = json.Unmarshal(out, &v) rtest.OK(t, err) } diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 2c9decc7c..d47cbbb74 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -171,7 +171,7 @@ func runMount(ctx context.Context, opts MountOptions, gopts global.Options, args } } - systemFuse.Debug = func(msg interface{}) { + systemFuse.Debug = func(msg any) { debug.Log("fuse: %v", msg) } diff --git a/cmd/restic/cmd_mount_integration_test.go b/cmd/restic/cmd_mount_integration_test.go index 5aff2ef92..0ce0eab8a 100644 --- a/cmd/restic/cmd_mount_integration_test.go +++ b/cmd/restic/cmd_mount_integration_test.go @@ -46,7 +46,7 @@ func snapshotsDirExists(t testing.TB, dir string) bool { // waitForMount blocks (max mountWait * mountSleep) until the subdir // "snapshots" appears in the dir. func waitForMount(t testing.TB, dir string) { - for i := 0; i < mountWait; i++ { + for range mountWait { if snapshotsDirExists(t, dir) { t.Log("mounted directory is ready") return @@ -70,7 +70,7 @@ func testRunMount(t testing.TB, gopts global.Options, dir string, wg *sync.WaitG func testRunUmount(t testing.TB, dir string) { var err error - for i := 0; i < mountWait; i++ { + for range mountWait { if err = systemFuse.Unmount(dir); err == nil { t.Logf("directory %v umounted", dir) return diff --git a/cmd/restic/cmd_restore_integration_test.go b/cmd/restic/cmd_restore_integration_test.go index 303b4e7ca..1eea148d3 100644 --- a/cmd/restic/cmd_restore_integration_test.go +++ b/cmd/restic/cmd_restore_integration_test.go @@ -243,7 +243,7 @@ func TestRestore(t *testing.T) { testRunInit(t, env.gopts) - for i := 0; i < 10; i++ { + for i := range 10 { p := filepath.Join(env.testdata, fmt.Sprintf("foo/bar/testfile%v", i)) rtest.OK(t, os.MkdirAll(filepath.Dir(p), 0755)) rtest.OK(t, appendRandomData(p, uint(rand.Intn(2<<21)))) diff --git a/cmd/restic/cmd_rewrite_integration_test.go b/cmd/restic/cmd_rewrite_integration_test.go index e30f437b2..cc575cd3b 100644 --- a/cmd/restic/cmd_rewrite_integration_test.go +++ b/cmd/restic/cmd_rewrite_integration_test.go @@ -43,7 +43,7 @@ func testLsOutputContainsCount(t testing.TB, gopts global.Options, lsOpts LsOpti t.Helper() out := testRunLsWithOpts(t, gopts, lsOpts, lsArgs) count := 0 - for _, line := range strings.Split(string(out), "\n") { + for line := range strings.SplitSeq(string(out), "\n") { if strings.Contains(line, substring) { count++ } diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index a4e2175c1..06c5e3592 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -415,7 +415,7 @@ func statsDebugFileType(ctx context.Context, repo restic.Lister, tpe restic.File func statsDebugBlobs(ctx context.Context, repo restic.Repository) ([restic.NumBlobTypes]*sizeHistogram, error) { var hist [restic.NumBlobTypes]*sizeHistogram - for i := 0; i < len(hist); i++ { + for i := range len(hist) { hist[i] = newSizeHistogram(2 * chunker.MaxSize) } @@ -446,10 +446,7 @@ func newSizeHistogram(sizeLimit uint64) *sizeHistogram { growthFactor := uint64(10) for lowerBound < sizeLimit { - upperBound := lowerBound*growthFactor - 1 - if upperBound > sizeLimit { - upperBound = sizeLimit - } + upperBound := min(lowerBound*growthFactor-1, sizeLimit) h.buckets = append(h.buckets, sizeClass{lowerBound, upperBound, 0}) lowerBound *= growthFactor } diff --git a/cmd/restic/cmd_stats_test.go b/cmd/restic/cmd_stats_test.go index 02d37acd9..300a01ec2 100644 --- a/cmd/restic/cmd_stats_test.go +++ b/cmd/restic/cmd_stats_test.go @@ -24,7 +24,7 @@ func TestSizeHistogramNew(t *testing.T) { func TestSizeHistogramAdd(t *testing.T) { h := newSizeHistogram(42) - for i := uint64(0); i < 45; i++ { + for i := range uint64(45) { h.Add(i) } diff --git a/cmd/restic/integration_helpers_test.go b/cmd/restic/integration_helpers_test.go index b20f63208..e05c88976 100644 --- a/cmd/restic/integration_helpers_test.go +++ b/cmd/restic/integration_helpers_test.go @@ -9,6 +9,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strings" "testing" @@ -339,13 +340,7 @@ func removePacksExcept(gopts global.Options, t testing.TB, keep restic.IDSet, re } func includes(haystack []string, needle string) bool { - for _, s := range haystack { - if s == needle { - return true - } - } - - return false + return slices.Contains(haystack, needle) } func loadSnapshotMap(t testing.TB, gopts global.Options) map[string]struct{} { diff --git a/helpers/build-release-binaries/main.go b/helpers/build-release-binaries/main.go index d01bd93c1..5a0375200 100644 --- a/helpers/build-release-binaries/main.go +++ b/helpers/build-release-binaries/main.go @@ -39,7 +39,7 @@ func init() { pflag.Parse() } -func die(f string, args ...interface{}) { +func die(f string, args ...any) { if !strings.HasSuffix(f, "\n") { f += "\n" } @@ -48,7 +48,7 @@ func die(f string, args ...interface{}) { os.Exit(1) } -func msg(f string, args ...interface{}) { +func msg(f string, args ...any) { if !strings.HasSuffix(f, "\n") { f += "\n" } @@ -56,7 +56,7 @@ func msg(f string, args ...interface{}) { fmt.Printf(f, args...) } -func verbose(f string, args ...interface{}) { +func verbose(f string, args ...any) { if !opts.Verbose { return } @@ -207,10 +207,7 @@ func buildForTarget(sourceDir, outputDir, goos, goarch string) (filename string) func buildTargets(sourceDir, outputDir string, targets map[string][]string) { start := time.Now() // the go compiler is already parallelized, thus reduce the concurrency a bit - workers := runtime.GOMAXPROCS(0) / 4 - if workers < 1 { - workers = 1 - } + workers := max(runtime.GOMAXPROCS(0)/4, 1) msg("building with %d workers", workers) type Job struct{ GOOS, GOARCH string } @@ -218,7 +215,7 @@ func buildTargets(sourceDir, outputDir string, targets map[string][]string) { var wg errgroup.Group ch := make(chan Job) - for i := 0; i < workers; i++ { + for range workers { wg.Go(func() error { for job := range ch { start := time.Now() diff --git a/helpers/prepare-release/main.go b/helpers/prepare-release/main.go index b0a636c29..6fced3f7c 100644 --- a/helpers/prepare-release/main.go +++ b/helpers/prepare-release/main.go @@ -43,7 +43,7 @@ func init() { pflag.Parse() } -func die(f string, args ...interface{}) { +func die(f string, args ...any) { if !strings.HasSuffix(f, "\n") { f += "\n" } @@ -52,7 +52,7 @@ func die(f string, args ...interface{}) { os.Exit(1) } -func msg(f string, args ...interface{}) { +func msg(f string, args ...any) { if !strings.HasSuffix(f, "\n") { f += "\n" } @@ -428,11 +428,11 @@ func updateDocker(sourceDir, version string) string { buildCmd := fmt.Sprintf("docker buildx build --builder %s --platform linux/386,linux/amd64,linux/arm,linux/arm64 --pull -f docker/Dockerfile.release %q", builderName, sourceDir) run("sh", "-c", buildCmd+" --no-cache") - publishCmds := "" + var publishCmds strings.Builder for _, tag := range []string{"restic/restic:latest", "restic/restic:" + version} { - publishCmds += buildCmd + fmt.Sprintf(" --tag %q --push\n", tag) + publishCmds.WriteString(buildCmd + fmt.Sprintf(" --tag %q --push\n", tag)) } - return publishCmds + "\ndocker buildx rm " + builderName + return publishCmds.String() + "\ndocker buildx rm " + builderName } func tempdir(prefix string) string { diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index 6c238263e..99aafea3d 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -132,8 +132,7 @@ func TestArchiverSaveFile(t *testing.T) { for _, testfile := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, TestDir{"file": testfile}) node, stats := saveFile(t, repo, filepath.Join(tempdir, "file"), fs.Track{FS: fs.NewLocal()}) @@ -165,8 +164,7 @@ func TestArchiverSaveFileReaderFS(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() repo := repository.TestRepository(t) @@ -206,8 +204,7 @@ func TestArchiverSave(t *testing.T) { for _, testfile := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, TestDir{"file": testfile}) @@ -276,8 +273,7 @@ func TestArchiverSaveReaderFS(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() repo := repository.TestRepository(t) @@ -477,7 +473,7 @@ func TestArchiverSaveFileIncremental(t *testing.T) { data := rtest.Random(23, 512*1024+887898) testfile := filepath.Join(tempdir, "testfile") - for i := 0; i < 3; i++ { + for i := range 3 { appendToFile(t, testfile, data) node, _ := saveFile(t, repo, testfile, fs.Track{FS: fs.NewLocal()}) @@ -984,7 +980,7 @@ func TestArchiverSaveDirIncremental(t *testing.T) { // save the empty directory several times in a row, then have a look if the // archiver did save the same tree several times - for i := 0; i < 5; i++ { + for i := range 5 { testFS := fs.Track{FS: fs.NewLocal()} arch := New(repo, testFS, Options{}) arch.summary = &Summary{} @@ -1461,8 +1457,7 @@ func TestArchiverSnapshot(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -1682,8 +1677,7 @@ func TestArchiverSnapshotSelect(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -1790,8 +1784,7 @@ func TestArchiverExplicitBackupTarget(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -1956,8 +1949,7 @@ func TestArchiverParent(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -1982,7 +1974,7 @@ func TestArchiverParent(t *testing.T) { t.Logf("testfs: %v", testFS) // check that all files have been read exactly once - TestWalkFiles(t, ".", test.src, func(filename string, item interface{}) error { + TestWalkFiles(t, ".", test.src, func(filename string, item any) error { file, ok := item.(TestFile) if !ok { return nil @@ -2144,8 +2136,7 @@ func TestArchiverErrorReporting(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -2370,8 +2361,7 @@ func TestArchiverAbortEarlyOnError(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir, repo := prepareTempdirRepoSrc(t, test.src) @@ -2618,8 +2608,7 @@ func TestRacyFileTypeSwap(t *testing.T) { resetFIOnRead: true, } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _ = repo.WithBlobUploader(ctx, func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { wg, ctx := errgroup.WithContext(ctx) @@ -2717,8 +2706,7 @@ func TestIrregularFile(t *testing.T) { overrideErr: fmt.Errorf(`unsupported file type "irregular"`), } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() arch := New(repo, fs.Track{FS: override}, Options{}) _, excluded, err := arch.save(ctx, "/", tempfile, nil, false) @@ -2764,8 +2752,7 @@ func TestDisappearedFile(t *testing.T) { back := rtest.Chdir(t, tempdir) defer back() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() // depending on the underlying FS implementation a missing file may be detected by OpenFile or // the subsequent file.Stat() call. Thus test both cases. diff --git a/internal/archiver/buffer_test.go b/internal/archiver/buffer_test.go index 1b577fa2d..65263c5a2 100644 --- a/internal/archiver/buffer_test.go +++ b/internal/archiver/buffer_test.go @@ -7,7 +7,7 @@ import ( func TestBufferPoolReuse(t *testing.T) { success := false // retries to avoid flakiness. The test can fail depending on the GC. - for i := 0; i < 100; i++ { + for range 100 { // Test that buffers are actually reused from the pool pool := newBufferPool(1024) @@ -33,7 +33,7 @@ func TestBufferPoolReuse(t *testing.T) { func TestBufferPoolLargeBuffers(t *testing.T) { success := false // retries to avoid flakiness. The test can fail depending on the GC. - for i := 0; i < 100; i++ { + for range 100 { // Test that buffers larger than defaultSize are not returned to pool pool := newBufferPool(1024) buf := pool.Get() diff --git a/internal/archiver/exclude.go b/internal/archiver/exclude.go index a7e11d781..571680929 100644 --- a/internal/archiver/exclude.go +++ b/internal/archiver/exclude.go @@ -88,7 +88,7 @@ func (rc *rejectionCache) Store(dir string, rejected bool) { // non-nil if the filename component of excludeFileSpec is empty. If rc is // non-nil, it is going to be used in the RejectByNameFunc to expedite the evaluation // of a directory based on previous visits. -func RejectIfPresent(excludeFileSpec string, warnf func(msg string, args ...interface{})) (RejectFunc, error) { +func RejectIfPresent(excludeFileSpec string, warnf func(msg string, args ...any)) (RejectFunc, error) { if excludeFileSpec == "" { return nil, errors.New("name for exclusion tagfile is empty") } @@ -115,7 +115,7 @@ func RejectIfPresent(excludeFileSpec string, warnf func(msg string, args ...inte // tagfile which bears the name specified in tagFilename and starts with // header. If rc is non-nil, it is used to expedite the evaluation of a // directory based on previous visits. -func isExcludedByFile(filename, tagFilename, header string, rc *rejectionCache, fs fs.FS, warnf func(msg string, args ...interface{})) bool { +func isExcludedByFile(filename, tagFilename, header string, rc *rejectionCache, fs fs.FS, warnf func(msg string, args ...any)) bool { if tagFilename == "" { return false } @@ -136,7 +136,7 @@ func isExcludedByFile(filename, tagFilename, header string, rc *rejectionCache, return rejected } -func isDirExcludedByFile(dir, tagFilename, header string, fsInst fs.FS, warnf func(msg string, args ...interface{})) bool { +func isDirExcludedByFile(dir, tagFilename, header string, fsInst fs.FS, warnf func(msg string, args ...any)) bool { tf := fsInst.Join(dir, tagFilename) _, err := fsInst.Lstat(tf) if errors.Is(err, os.ErrNotExist) { @@ -318,7 +318,7 @@ func RejectBySize(maxSize int64) (RejectFunc, error) { } // RejectCloudFiles returns a func which rejects files which are online-only cloud files -func RejectCloudFiles(warnf func(msg string, args ...interface{})) (RejectFunc, error) { +func RejectCloudFiles(warnf func(msg string, args ...any)) (RejectFunc, error) { return func(item string, fi *fs.ExtendedFileInfo, _ fs.FS) bool { recall, err := fi.RecallOnDataAccess() if err != nil { diff --git a/internal/archiver/exclude_test.go b/internal/archiver/exclude_test.go index 4080f25f0..475ef2f69 100644 --- a/internal/archiver/exclude_test.go +++ b/internal/archiver/exclude_test.go @@ -49,7 +49,7 @@ func TestIsExcludedByFile(t *testing.T) { if tc.content == "" { h = "" } - if got := isExcludedByFile(foo, tagFilename, h, newRejectionCache(), fs.NewLocal(), func(msg string, args ...interface{}) { t.Logf(msg, args...) }); tc.want != got { + if got := isExcludedByFile(foo, tagFilename, h, newRejectionCache(), fs.NewLocal(), func(msg string, args ...any) { t.Logf(msg, args...) }); tc.want != got { t.Fatalf("expected %v, got %v", tc.want, got) } }) diff --git a/internal/archiver/file_saver.go b/internal/archiver/file_saver.go index 48b308e00..f25f3c7b8 100644 --- a/internal/archiver/file_saver.go +++ b/internal/archiver/file_saver.go @@ -45,7 +45,7 @@ func newFileSaver(ctx context.Context, wg *errgroup.Group, uploader restic.BlobS CompleteBlob: func(uint64) {}, } - for i := uint(0); i < fileWorkers; i++ { + for range fileWorkers { wg.Go(func() error { s.worker(ctx, ch) return nil diff --git a/internal/archiver/file_saver_test.go b/internal/archiver/file_saver_test.go index 9be2f0d95..e71bf6cec 100644 --- a/internal/archiver/file_saver_test.go +++ b/internal/archiver/file_saver_test.go @@ -18,7 +18,7 @@ import ( func createTestFiles(t testing.TB, num int) (files []string) { tempdir := test.TempDir(t) - for i := 0; i < num; i++ { + for i := range num { filename := fmt.Sprintf("testfile-%d", i) err := os.WriteFile(filepath.Join(tempdir, filename), []byte(filename), 0600) if err != nil { @@ -46,8 +46,7 @@ func startFileSaver(ctx context.Context, t testing.TB, _ fs.FS) (*fileSaver, *mo } func TestFileSaver(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() startFn := func() {} completeReadingFn := func() {} diff --git a/internal/archiver/scanner_test.go b/internal/archiver/scanner_test.go index c2ec8fdb8..71898f402 100644 --- a/internal/archiver/scanner_test.go +++ b/internal/archiver/scanner_test.go @@ -78,8 +78,7 @@ func TestScanner(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir := rtest.TempDir(t) TestCreateFiles(t, tempdir, test.src) @@ -213,8 +212,7 @@ func TestScannerError(t *testing.T) { t.Skipf("skip on windows") } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir := rtest.TempDir(t) TestCreateFiles(t, tempdir, test.src) diff --git a/internal/archiver/testing.go b/internal/archiver/testing.go index bec70959f..abca347f4 100644 --- a/internal/archiver/testing.go +++ b/internal/archiver/testing.go @@ -41,7 +41,7 @@ func TestSnapshot(t testing.TB, repo restic.Repository, path string, parent *res } // TestDir describes a directory structure to create for a test. -type TestDir map[string]interface{} +type TestDir map[string]any func (d TestDir) String() string { return "" @@ -119,7 +119,7 @@ func TestCreateFiles(t testing.TB, target string, dir TestDir) { // TestWalkFunc is used by TestWalkFiles to traverse the dir. When an error is // returned, traversal stops and the surrounding test is marked as failed. -type TestWalkFunc func(path string, item interface{}) error +type TestWalkFunc func(path string, item any) error // TestWalkFiles runs fn for each file/directory in dir, the filename will be // constructed with target as the prefix. Symlinks on Windows are ignored. @@ -158,7 +158,7 @@ func TestEnsureFiles(t testing.TB, target string, dir TestDir) { pathsChecked := make(map[string]struct{}) // first, test that all items are there - TestWalkFiles(t, target, dir, func(path string, item interface{}) error { + TestWalkFiles(t, target, dir, func(path string, item any) error { fi, err := os.Lstat(path) if err != nil { return err diff --git a/internal/archiver/testing_test.go b/internal/archiver/testing_test.go index 6c395b94e..1c5450ccd 100644 --- a/internal/archiver/testing_test.go +++ b/internal/archiver/testing_test.go @@ -1,7 +1,6 @@ package archiver import ( - "context" "fmt" "os" "path/filepath" @@ -28,30 +27,30 @@ func (t *MockT) Fail() { } // Fatal is equivalent to Log followed by FailNow. -func (t *MockT) Fatal(args ...interface{}) { +func (t *MockT) Fatal(args ...any) { t.T.Logf("MockT Fatal called with %v", args) t.HasFailed = true } // Fatalf is equivalent to Logf followed by FailNow. -func (t *MockT) Fatalf(msg string, args ...interface{}) { +func (t *MockT) Fatalf(msg string, args ...any) { t.T.Logf("MockT Fatal called: "+msg, args...) t.HasFailed = true } // Error is equivalent to Log followed by Fail. -func (t *MockT) Error(args ...interface{}) { +func (t *MockT) Error(args ...any) { t.T.Logf("MockT Error called with %v", args) t.HasFailed = true } // Errorf is equivalent to Logf followed by Fail. -func (t *MockT) Errorf(msg string, args ...interface{}) { +func (t *MockT) Errorf(msg string, args ...any) { t.T.Logf("MockT Error called: "+msg, args...) t.HasFailed = true } -func createFilesAt(t testing.TB, targetdir string, files map[string]interface{}) { +func createFilesAt(t testing.TB, targetdir string, files map[string]any) { for name, item := range files { target := filepath.Join(targetdir, filepath.FromSlash(name)) err := os.MkdirAll(filepath.Dir(target), 0700) @@ -77,7 +76,7 @@ func createFilesAt(t testing.TB, targetdir string, files map[string]interface{}) func TestTestCreateFiles(t *testing.T) { var tests = []struct { dir TestDir - files map[string]interface{} + files map[string]any }{ { dir: TestDir{ @@ -91,7 +90,7 @@ func TestTestCreateFiles(t *testing.T) { }, }, }, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, "subdir": TestDir{}, "subdir/subfile": TestFile{Content: "bar"}, @@ -196,7 +195,7 @@ func TestTestWalkFiles(t *testing.T) { got := make(map[string]string) TestCreateFiles(t, tempdir, test.dir) - TestWalkFiles(t, tempdir, test.dir, func(path string, item interface{}) error { + TestWalkFiles(t, tempdir, test.dir, func(path string, item any) error { p, err := filepath.Rel(tempdir, path) if err != nil { return err @@ -216,11 +215,11 @@ func TestTestWalkFiles(t *testing.T) { func TestTestEnsureFiles(t *testing.T) { var tests = []struct { expectFailure bool - files map[string]interface{} + files map[string]any want TestDir }{ { - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, "subdir/subfile": TestFile{Content: "bar"}, "x/y/link": TestSymlink{Target: filepath.Clean("../../foo")}, @@ -239,7 +238,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -251,7 +250,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, "subdir/subfile": TestFile{Content: "bar"}, }, @@ -261,7 +260,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "xxx"}, }, want: TestDir{ @@ -270,7 +269,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestSymlink{Target: "/xxx"}, }, want: TestDir{ @@ -279,7 +278,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -288,7 +287,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestSymlink{Target: "xxx"}, }, want: TestDir{ @@ -297,7 +296,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestDir{ "foo": TestFile{Content: "foo"}, }, @@ -308,7 +307,7 @@ func TestTestEnsureFiles(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -341,11 +340,11 @@ func TestTestEnsureFiles(t *testing.T) { func TestTestEnsureSnapshot(t *testing.T) { var tests = []struct { expectFailure bool - files map[string]interface{} + files map[string]any want TestDir }{ { - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, filepath.FromSlash("subdir/subfile"): TestFile{Content: "bar"}, filepath.FromSlash("x/y/link"): TestSymlink{Target: filepath.FromSlash("../../foo")}, @@ -366,7 +365,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -377,7 +376,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, "bar": TestFile{Content: "bar"}, }, @@ -389,7 +388,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -401,7 +400,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -414,7 +413,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestSymlink{Target: filepath.FromSlash("x/y/z")}, }, want: TestDir{ @@ -425,7 +424,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestSymlink{Target: filepath.FromSlash("x/y/z")}, }, want: TestDir{ @@ -436,7 +435,7 @@ func TestTestEnsureSnapshot(t *testing.T) { }, { expectFailure: true, - files: map[string]interface{}{ + files: map[string]any{ "foo": TestFile{Content: "foo"}, }, want: TestDir{ @@ -449,8 +448,7 @@ func TestTestEnsureSnapshot(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tempdir := rtest.TempDir(t) diff --git a/internal/archiver/tree_saver.go b/internal/archiver/tree_saver.go index 8b38b5eb2..295a4c393 100644 --- a/internal/archiver/tree_saver.go +++ b/internal/archiver/tree_saver.go @@ -29,7 +29,7 @@ func newTreeSaver(ctx context.Context, wg *errgroup.Group, treeWorkers uint, upl errFn: errFn, } - for i := uint(0); i < treeWorkers; i++ { + for range treeWorkers { wg.Go(func() error { return s.worker(ctx, ch) }) diff --git a/internal/archiver/tree_saver_test.go b/internal/archiver/tree_saver_test.go index ed3a148af..d3ba741c2 100644 --- a/internal/archiver/tree_saver_test.go +++ b/internal/archiver/tree_saver_test.go @@ -54,7 +54,7 @@ func TestTreeSaver(t *testing.T) { var results []futureNode - for i := 0; i < 20; i++ { + for i := range 20 { node := &data.Node{ Name: fmt.Sprintf("file-%d", i), } diff --git a/internal/backend/azure/azure.go b/internal/backend/azure/azure.go index 234e5ddd1..8e88af896 100644 --- a/internal/backend/azure/azure.go +++ b/internal/backend/azure/azure.go @@ -158,13 +158,13 @@ func supportedAccessTiers() []blob.AccessTier { } // Open opens the Azure backend at specified container. -func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (*Backend, error) { +func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (*Backend, error) { return open(cfg, rt) } // Create opens the Azure backend at specified container and creates the container if // it does not exist yet. -func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (*Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (*Backend, error) { be, err := open(cfg, rt) if err != nil { diff --git a/internal/backend/azure/azure_test.go b/internal/backend/azure/azure_test.go index f755b21d2..149b58257 100644 --- a/internal/backend/azure/azure_test.go +++ b/internal/backend/azure/azure_test.go @@ -2,7 +2,6 @@ package azure_test import ( "bytes" - "context" "fmt" "io" "os" @@ -100,8 +99,7 @@ func TestBackendAzureAccountToken(t *testing.T) { } } - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() cfg, err := azure.ParseConfig(os.Getenv("RESTIC_TEST_AZURE_REPOSITORY")) if err != nil { @@ -143,8 +141,7 @@ func TestBackendAzureContainerToken(t *testing.T) { } } - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() cfg, err := azure.ParseConfig(os.Getenv("RESTIC_TEST_AZURE_REPOSITORY")) if err != nil { @@ -171,8 +168,7 @@ func TestUploadLargeFile(t *testing.T) { return } - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() if os.Getenv("RESTIC_TEST_AZURE_REPOSITORY") == "" { t.Skipf("environment variables not available") diff --git a/internal/backend/b2/b2.go b/internal/backend/b2/b2.go index 567a2875c..5d539fb22 100644 --- a/internal/backend/b2/b2.go +++ b/internal/backend/b2/b2.go @@ -87,7 +87,7 @@ func newClient(ctx context.Context, cfg Config, rt http.RoundTripper) (*b2.Clien } // Open opens a connection to the B2 service. -func Open(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Open(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { debug.Log("cfg %#v", cfg) ctx, cancel := context.WithCancel(ctx) @@ -118,7 +118,7 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, // Create opens a connection to the B2 service. If the bucket does not exist yet, // it is created. -func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { debug.Log("cfg %#v", cfg) ctx, cancel := context.WithCancel(ctx) @@ -258,7 +258,7 @@ func (be *b2Backend) Stat(ctx context.Context, h backend.Handle) (bi backend.Fil // Remove removes the blob with the given name and type. func (be *b2Backend) Remove(ctx context.Context, h backend.Handle) error { // the retry backend will also repeat the remove method up to 10 times - for i := 0; i < 3; i++ { + for range 3 { obj := be.bucket.Object(be.Filename(h)) var err error diff --git a/internal/backend/cache/backend.go b/internal/backend/cache/backend.go index db47767a0..e5dacc692 100644 --- a/internal/backend/cache/backend.go +++ b/internal/backend/cache/backend.go @@ -19,13 +19,13 @@ type cacheBackend struct { // is finished. inProgressMutex sync.Mutex inProgress map[backend.Handle]chan struct{} - errorLog func(string, ...interface{}) + errorLog func(string, ...any) } // ensure Backend implements backend.Backend var _ backend.Backend = &cacheBackend{} -func newBackend(be backend.Backend, c *Cache, errorLog func(string, ...interface{})) *cacheBackend { +func newBackend(be backend.Backend, c *Cache, errorLog func(string, ...any)) *cacheBackend { return &cacheBackend{ Backend: be, Cache: c, diff --git a/internal/backend/cache/backend_test.go b/internal/backend/cache/backend_test.go index 12d4fa028..4f388027b 100644 --- a/internal/backend/cache/backend_test.go +++ b/internal/backend/cache/backend_test.go @@ -238,7 +238,7 @@ func TestErrorBackend(t *testing.T) { wrappedBE := c.Wrap(errBackend, t.Logf) var wg sync.WaitGroup - for i := 0; i < 5; i++ { + for range 5 { wg.Add(1) go loadTest(&wg, wrappedBE) } diff --git a/internal/backend/cache/cache.go b/internal/backend/cache/cache.go index 22c3532ce..235e51a40 100644 --- a/internal/backend/cache/cache.go +++ b/internal/backend/cache/cache.go @@ -125,7 +125,7 @@ func New(id string, basedir string) (c *Cache, err error) { } if v < cacheVersion { - err = os.WriteFile(filepath.Join(cachedir, "version"), []byte(fmt.Sprintf("%d", cacheVersion)), fileMode) + err = os.WriteFile(filepath.Join(cachedir, "version"), fmt.Appendf(nil, "%d", cacheVersion), fileMode) if err != nil { return nil, errors.WithStack(err) } @@ -236,7 +236,7 @@ func IsOld(t time.Time, maxAge time.Duration) bool { } // Wrap returns a backend with a cache. -func (c *Cache) Wrap(be backend.Backend, errorLog func(string, ...interface{})) backend.Backend { +func (c *Cache) Wrap(be backend.Backend, errorLog func(string, ...any)) backend.Backend { return newBackend(be, c, errorLog) } diff --git a/internal/backend/cache/cache_test.go b/internal/backend/cache/cache_test.go index b9d0b905d..7b56e40dc 100644 --- a/internal/backend/cache/cache_test.go +++ b/internal/backend/cache/cache_test.go @@ -24,7 +24,7 @@ func TestNew(t *testing.T) { stepEnd ) - for step := stepCreate; step < stepEnd; step++ { + for step := range stepEnd { switch step { case stepRmTag: rtest.OK(t, os.Remove(tagFile)) diff --git a/internal/backend/cache/file_test.go b/internal/backend/cache/file_test.go index d26c8cc6a..bfeda4959 100644 --- a/internal/backend/cache/file_test.go +++ b/internal/backend/cache/file_test.go @@ -243,7 +243,7 @@ func TestFileSaveConcurrent(t *testing.T) { Name: id.String(), } - for i := 0; i < nproc/2; i++ { + for range nproc / 2 { g.Go(func() error { return c.save(h, bytes.NewReader(data)) }) // Can't use load because only the main goroutine may call t.Fatal. diff --git a/internal/backend/gs/gs.go b/internal/backend/gs/gs.go index 8ebc4902c..5e8a45e81 100644 --- a/internal/backend/gs/gs.go +++ b/internal/backend/gs/gs.go @@ -114,7 +114,7 @@ func open(cfg Config, rt http.RoundTripper) (*gs, error) { } // Open opens the gs backend at the specified bucket. -func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { return open(cfg, rt) } @@ -123,7 +123,7 @@ func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, .. // // The service account must have the "storage.buckets.create" permission to // create a bucket the does not yet exist. -func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { be, err := open(cfg, rt) if err != nil { return nil, err diff --git a/internal/backend/layout/layout_default.go b/internal/backend/layout/layout_default.go index 6566da5a7..e5ff6a8a7 100644 --- a/internal/backend/layout/layout_default.go +++ b/internal/backend/layout/layout_default.go @@ -72,7 +72,7 @@ func (l *DefaultLayout) Paths() (dirs []string) { if !disablePackSubdirs { // also add subdirs - for i := 0; i < 256; i++ { + for i := range 256 { subdir := hex.EncodeToString([]byte{byte(i)}) dirs = append(dirs, l.join(l.path, defaultLayoutPaths[backend.PackFile], subdir)) } diff --git a/internal/backend/layout/layout_test.go b/internal/backend/layout/layout_test.go index af5105c20..1049439b8 100644 --- a/internal/backend/layout/layout_test.go +++ b/internal/backend/layout/layout_test.go @@ -112,7 +112,7 @@ func TestDefaultLayout(t *testing.T) { filepath.Join(tempdir, "keys"), } - for i := 0; i < 256; i++ { + for i := range 256 { want = append(want, filepath.Join(tempdir, "data", fmt.Sprintf("%02x", i))) } diff --git a/internal/backend/limiter/limiter_backend.go b/internal/backend/limiter/limiter_backend.go index 945777688..6f4f2a03a 100644 --- a/internal/backend/limiter/limiter_backend.go +++ b/internal/backend/limiter/limiter_backend.go @@ -7,8 +7,8 @@ import ( "github.com/restic/restic/internal/backend" ) -func WrapBackendConstructor[B backend.Backend, C any](constructor func(ctx context.Context, cfg C, errorLog func(string, ...interface{})) (B, error)) func(ctx context.Context, cfg C, lim Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { - return func(ctx context.Context, cfg C, lim Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { +func WrapBackendConstructor[B backend.Backend, C any](constructor func(ctx context.Context, cfg C, errorLog func(string, ...any)) (B, error)) func(ctx context.Context, cfg C, lim Limiter, errorLog func(string, ...any)) (backend.Backend, error) { + return func(ctx context.Context, cfg C, lim Limiter, errorLog func(string, ...any)) (backend.Backend, error) { var be backend.Backend be, err := constructor(ctx, cfg, errorLog) if err != nil { diff --git a/internal/backend/local/local.go b/internal/backend/local/local.go index 3a1237ee8..141769913 100644 --- a/internal/backend/local/local.go +++ b/internal/backend/local/local.go @@ -52,14 +52,14 @@ func open(cfg Config) (*Local, error) { } // Open opens the local backend as specified by config. -func Open(_ context.Context, cfg Config, _ func(string, ...interface{})) (*Local, error) { +func Open(_ context.Context, cfg Config, _ func(string, ...any)) (*Local, error) { debug.Log("open local backend at %v", cfg.Path) return open(cfg) } // Create creates all the necessary files and directories for a new local // backend at dir. Afterwards a new config blob should be created. -func Create(_ context.Context, cfg Config, _ func(string, ...interface{})) (*Local, error) { +func Create(_ context.Context, cfg Config, _ func(string, ...any)) (*Local, error) { debug.Log("create local backend at %v", cfg.Path) be, err := open(cfg) diff --git a/internal/backend/location/location.go b/internal/backend/location/location.go index db82d1825..4175b87b7 100644 --- a/internal/backend/location/location.go +++ b/internal/backend/location/location.go @@ -11,7 +11,7 @@ import ( // access and (possibly) credentials needed for access. type Location struct { Scheme string - Config interface{} + Config any } // NoPassword returns the repository location unchanged (there's no sensitive information there) diff --git a/internal/backend/location/registry.go b/internal/backend/location/registry.go index c0761e76b..be8d282e8 100644 --- a/internal/backend/location/registry.go +++ b/internal/backend/location/registry.go @@ -31,25 +31,25 @@ func (r *Registry) Lookup(scheme string) Factory { type Factory interface { Scheme() string - ParseConfig(s string) (interface{}, error) + ParseConfig(s string) (any, error) StripPassword(s string) string - Create(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) - Open(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) + Create(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) + Open(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) } type genericBackendFactory[C any, T backend.Backend] struct { scheme string parseConfigFn func(s string) (*C, error) stripPasswordFn func(s string) string - createFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error) - openFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error) + createFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) + openFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) } func (f *genericBackendFactory[C, T]) Scheme() string { return f.scheme } -func (f *genericBackendFactory[C, T]) ParseConfig(s string) (interface{}, error) { +func (f *genericBackendFactory[C, T]) ParseConfig(s string) (any, error) { return f.parseConfigFn(s) } func (f *genericBackendFactory[C, T]) StripPassword(s string) string { @@ -58,10 +58,10 @@ func (f *genericBackendFactory[C, T]) StripPassword(s string) string { } return s } -func (f *genericBackendFactory[C, T]) Create(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { +func (f *genericBackendFactory[C, T]) Create(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { return f.createFn(ctx, *cfg.(*C), rt, lim, errorLog) } -func (f *genericBackendFactory[C, T]) Open(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { +func (f *genericBackendFactory[C, T]) Open(ctx context.Context, cfg any, rt http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { return f.openFn(ctx, *cfg.(*C), rt, lim, errorLog) } @@ -69,17 +69,17 @@ func NewHTTPBackendFactory[C any, T backend.Backend]( scheme string, parseConfigFn func(s string) (*C, error), stripPasswordFn func(s string) string, - createFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...interface{})) (T, error), - openFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...interface{})) (T, error)) Factory { + createFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...any)) (T, error), + openFn func(ctx context.Context, cfg C, rt http.RoundTripper, errorLog func(string, ...any)) (T, error)) Factory { return &genericBackendFactory[C, T]{ scheme: scheme, parseConfigFn: parseConfigFn, stripPasswordFn: stripPasswordFn, - createFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...interface{})) (T, error) { + createFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...any)) (T, error) { return createFn(ctx, cfg, rt, errorLog) }, - openFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...interface{})) (T, error) { + openFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter, errorLog func(string, ...any)) (T, error) { return openFn(ctx, cfg, rt, errorLog) }, } @@ -89,17 +89,17 @@ func NewLimitedBackendFactory[C any, T backend.Backend]( scheme string, parseConfigFn func(s string) (*C, error), stripPasswordFn func(s string) string, - createFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error), - openFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error)) Factory { + createFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...any)) (T, error), + openFn func(ctx context.Context, cfg C, lim limiter.Limiter, errorLog func(string, ...any)) (T, error)) Factory { return &genericBackendFactory[C, T]{ scheme: scheme, parseConfigFn: parseConfigFn, stripPasswordFn: stripPasswordFn, - createFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error) { + createFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) { return createFn(ctx, cfg, lim, errorLog) }, - openFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...interface{})) (T, error) { + openFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter, errorLog func(string, ...any)) (T, error) { return openFn(ctx, cfg, lim, errorLog) }, } diff --git a/internal/backend/mem/mem_backend.go b/internal/backend/mem/mem_backend.go index 6ff38867c..b97996b0c 100644 --- a/internal/backend/mem/mem_backend.go +++ b/internal/backend/mem/mem_backend.go @@ -33,10 +33,10 @@ func NewFactory() location.Factory { return &struct{}{}, nil }, location.NoPassword, - func(_ context.Context, _ struct{}, _ http.RoundTripper, _ func(string, ...interface{})) (*MemoryBackend, error) { + func(_ context.Context, _ struct{}, _ http.RoundTripper, _ func(string, ...any)) (*MemoryBackend, error) { return be, nil }, - func(_ context.Context, _ struct{}, _ http.RoundTripper, _ func(string, ...interface{})) (*MemoryBackend, error) { + func(_ context.Context, _ struct{}, _ http.RoundTripper, _ func(string, ...any)) (*MemoryBackend, error) { return be, nil }, ) diff --git a/internal/backend/rclone/backend.go b/internal/backend/rclone/backend.go index 19d956b3f..7038f2660 100644 --- a/internal/backend/rclone/backend.go +++ b/internal/backend/rclone/backend.go @@ -44,7 +44,7 @@ func NewFactory() location.Factory { } // run starts command with args and initializes the StdioConn. -func run(errorLog func(string, ...interface{}), command string, args ...string) (*StdioConn, *sync.WaitGroup, chan struct{}, func() error, error) { +func run(errorLog func(string, ...any), command string, args ...string) (*StdioConn, *sync.WaitGroup, chan struct{}, func() error, error) { cmd := exec.Command(command, args...) p, err := cmd.StderrPipe() @@ -56,16 +56,14 @@ func run(errorLog func(string, ...interface{}), command string, args ...string) waitCh := make(chan struct{}) // start goroutine to add a prefix to all messages printed by to stderr by rclone - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { defer close(waitCh) sc := bufio.NewScanner(p) for sc.Scan() { errorLog("rclone: %v\n", sc.Text()) } debug.Log("command has exited, closing waitCh") - }() + }) r, stdin, err := os.Pipe() if err != nil { @@ -141,7 +139,7 @@ func wrapConn(c *StdioConn, lim limiter.Limiter) *wrappedConn { } // New initializes a Backend and starts the process. -func newBackend(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...interface{})) (*rclone, error) { +func newBackend(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...any)) (*rclone, error) { var ( args []string err error @@ -207,9 +205,7 @@ func newBackend(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog f ctx, cancel := context.WithCancel(ctx) defer cancel() - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { <-waitCh cancel() @@ -219,7 +215,7 @@ func newBackend(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog f be.waitResult = err // close our side of the pipes to rclone, ignore errors _ = stdioConn.CloseAll() - }() + }) // send an HTTP request to the base URL, see if the server is there client := http.Client{ @@ -270,7 +266,7 @@ func newBackend(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog f } // Open starts an rclone process with the given config. -func Open(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { +func Open(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { be, err := newBackend(ctx, cfg, lim, errorLog) if err != nil { return nil, err @@ -297,7 +293,7 @@ func Open(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(st } // Create initializes a new restic repo with rclone. -func Create(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...interface{})) (backend.Backend, error) { +func Create(ctx context.Context, cfg Config, lim limiter.Limiter, errorLog func(string, ...any)) (backend.Backend, error) { be, err := newBackend(ctx, cfg, lim, errorLog) if err != nil { return nil, err diff --git a/internal/backend/rclone/internal_test.go b/internal/backend/rclone/internal_test.go index f6b7336fb..c43b27726 100644 --- a/internal/backend/rclone/internal_test.go +++ b/internal/backend/rclone/internal_test.go @@ -32,7 +32,7 @@ func TestRcloneExit(t *testing.T) { rtest.OK(t, err) t.Log("killed rclone") - for i := 0; i < 10; i++ { + for range 10 { _, err = be.Stat(context.TODO(), backend.Handle{ Name: "foo", Type: backend.PackFile, diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index c3ed1801f..25483c90c 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -55,7 +55,7 @@ const ( ) // Open opens the REST backend with the given config. -func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (*Backend, error) { +func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (*Backend, error) { // use url without trailing slash for layout url := cfg.URL.String() if url[len(url)-1] == '/' { @@ -84,7 +84,7 @@ func drainAndClose(resp *http.Response) error { } // Create creates a new REST on server configured in config. -func Create(ctx context.Context, cfg Config, rt http.RoundTripper, errorLog func(string, ...interface{})) (*Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper, errorLog func(string, ...any)) (*Backend, error) { be, err := Open(ctx, cfg, rt, errorLog) if err != nil { return nil, err diff --git a/internal/backend/rest/rest_test.go b/internal/backend/rest/rest_test.go index 109259b92..b0073d5e5 100644 --- a/internal/backend/rest/rest_test.go +++ b/internal/backend/rest/rest_test.go @@ -170,8 +170,7 @@ func TestBackendREST(t *testing.T) { } }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() dir := rtest.TempDir(t) serverURL, cleanup := runRESTServer(ctx, t, dir, ":0") @@ -195,8 +194,7 @@ func TestBackendRESTExternalServer(t *testing.T) { } func BenchmarkBackendREST(t *testing.B) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() dir := rtest.TempDir(t) serverURL, cleanup := runRESTServer(ctx, t, dir, ":0") diff --git a/internal/backend/rest/rest_unix_test.go b/internal/backend/rest/rest_unix_test.go index 2c565f8da..d22b6b00e 100644 --- a/internal/backend/rest/rest_unix_test.go +++ b/internal/backend/rest/rest_unix_test.go @@ -3,7 +3,6 @@ package rest_test import ( - "context" "fmt" "path" "testing" @@ -18,8 +17,7 @@ func TestBackendRESTWithUnixSocket(t *testing.T) { } }() - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() dir := rtest.TempDir(t) serverURL, cleanup := runRESTServer(ctx, t, path.Join(dir, "data"), fmt.Sprintf("unix:%s", path.Join(dir, "sock"))) diff --git a/internal/backend/s3/s3.go b/internal/backend/s3/s3.go index 2b249e705..177503395 100644 --- a/internal/backend/s3/s3.go +++ b/internal/backend/s3/s3.go @@ -197,13 +197,13 @@ func getCredentials(cfg Config, tr http.RoundTripper) (*credentials.Credentials, // Open opens the S3 backend at bucket and region. The bucket is created if it // does not exist yet. -func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Open(_ context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { return open(cfg, rt) } // Create opens the S3 backend at bucket and region and creates the bucket if // it does not exist yet. -func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Create(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { be, err := open(cfg, rt) if err != nil { return nil, errors.Wrap(err, "open") diff --git a/internal/backend/s3/s3_test.go b/internal/backend/s3/s3_test.go index b026ce427..e98fce12f 100644 --- a/internal/backend/s3/s3_test.go +++ b/internal/backend/s3/s3_test.go @@ -51,7 +51,7 @@ func runMinio(ctx context.Context, t testing.TB, dir, key, secret string) func() // wait until the TCP port is reachable var success bool - for i := 0; i < 100; i++ { + for range 100 { time.Sleep(200 * time.Millisecond) c, err := net.Dial("tcp", "localhost:9000") @@ -117,8 +117,8 @@ func newMinioTestSuite(t testing.TB) (*test.Suite[s3.Config], func()) { return &cfg, nil }, - Factory: location.NewHTTPBackendFactory("s3", s3.ParseConfig, location.NoPassword, func(ctx context.Context, cfg s3.Config, rt http.RoundTripper, errorLog func(string, ...interface{})) (be backend.Backend, err error) { - for i := 0; i < 50; i++ { + Factory: location.NewHTTPBackendFactory("s3", s3.ParseConfig, location.NoPassword, func(ctx context.Context, cfg s3.Config, rt http.RoundTripper, errorLog func(string, ...any)) (be backend.Backend, err error) { + for i := range 50 { be, err = s3.Create(ctx, cfg, rt, errorLog) if err != nil { t.Logf("s3 open: try %d: error %v", i, err) diff --git a/internal/backend/sema/backend_test.go b/internal/backend/sema/backend_test.go index 96500dd68..cfa42acb0 100644 --- a/internal/backend/sema/backend_test.go +++ b/internal/backend/sema/backend_test.go @@ -115,7 +115,7 @@ func concurrencyTester(t *testing.T, setup func(m *mock.Backend), handler func(b be := sema.NewBackend(m) var wg errgroup.Group - for i := 0; i < workerCount; i++ { + for range workerCount { wg.Go(handler(be)) } @@ -225,12 +225,10 @@ func TestFreeze(t *testing.T) { // Start Save call that should block var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { h := backend.Handle{Type: backend.PackFile, Name: "foobar"} test.OK(t, be.Save(context.TODO(), h, nil)) - }() + }) // check time.Sleep(1 * time.Millisecond) diff --git a/internal/backend/sftp/sftp.go b/internal/backend/sftp/sftp.go index dcc2ea5a7..f33f2b42d 100644 --- a/internal/backend/sftp/sftp.go +++ b/internal/backend/sftp/sftp.go @@ -54,7 +54,7 @@ func NewFactory() location.Factory { return location.NewLimitedBackendFactory("sftp", ParseConfig, location.NoPassword, limiter.WrapBackendConstructor(Create), limiter.WrapBackendConstructor(Open)) } -func startClient(cfg Config, errorLog func(string, ...interface{})) (*SFTP, error) { +func startClient(cfg Config, errorLog func(string, ...any)) (*SFTP, error) { program, args, err := buildSSHCommand(cfg) if err != nil { return nil, err @@ -147,7 +147,7 @@ func (r *SFTP) clientError() error { // Open opens an sftp backend as described by the config by running // "ssh" with the appropriate arguments (or cfg.Command, if set). -func Open(_ context.Context, cfg Config, errorLog func(string, ...interface{})) (*SFTP, error) { +func Open(_ context.Context, cfg Config, errorLog func(string, ...any)) (*SFTP, error) { debug.Log("open backend with config %#v", cfg) sftp, err := startClient(cfg, errorLog) @@ -273,7 +273,7 @@ func buildSSHCommand(cfg Config) (cmd string, args []string, err error) { // Create creates an sftp backend as described by the config by running "ssh" // with the appropriate arguments (or cfg.Command, if set). -func Create(ctx context.Context, cfg Config, errorLog func(string, ...interface{})) (*SFTP, error) { +func Create(ctx context.Context, cfg Config, errorLog func(string, ...any)) (*SFTP, error) { sftp, err := startClient(cfg, errorLog) if err != nil { debug.Log("unable to start program: %v", err) diff --git a/internal/backend/sftp/sftp_test.go b/internal/backend/sftp/sftp_test.go index f9ce09608..2e88b162a 100644 --- a/internal/backend/sftp/sftp_test.go +++ b/internal/backend/sftp/sftp_test.go @@ -17,7 +17,7 @@ import ( ) func findSFTPServerBinary() string { - for _, dir := range strings.Split(rtest.TestSFTPPath, ":") { + for dir := range strings.SplitSeq(rtest.TestSFTPPath, ":") { testpath := filepath.Join(dir, "sftp-server") _, err := os.Stat(testpath) if !errors.Is(err, os.ErrNotExist) { @@ -82,7 +82,7 @@ func TestCreateSetsDirPermissions(t *testing.T) { cfg := testConfig(filepath.Join(rtest.TempDir(t), "repo")) - be, err := sftp.Create(context.Background(), cfg, func(string, ...interface{}) {}) + be, err := sftp.Create(context.Background(), cfg, func(string, ...any) {}) rtest.OK(t, err) defer func() { rtest.OK(t, be.Close()) }() @@ -108,7 +108,7 @@ func TestSaveSetsDirPermissions(t *testing.T) { cfg := testConfig(filepath.Join(rtest.TempDir(t), "repo")) - be, err := sftp.Create(context.Background(), cfg, func(string, ...interface{}) {}) + be, err := sftp.Create(context.Background(), cfg, func(string, ...any) {}) rtest.OK(t, err) defer func() { rtest.OK(t, be.Close()) }() diff --git a/internal/backend/swift/swift.go b/internal/backend/swift/swift.go index 155b5041e..4256c5442 100644 --- a/internal/backend/swift/swift.go +++ b/internal/backend/swift/swift.go @@ -42,7 +42,7 @@ func NewFactory() location.Factory { // Open opens the swift backend at a container in region. The container is // created if it does not exist yet. -func Open(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...interface{})) (backend.Backend, error) { +func Open(ctx context.Context, cfg Config, rt http.RoundTripper, _ func(string, ...any)) (backend.Backend, error) { debug.Log("config %#v", cfg) be := &beSwift{ @@ -202,7 +202,7 @@ func (be *beSwift) List(ctx context.Context, t backend.FileType, fn func(backend prefix += "/" err := be.conn.ObjectsWalk(ctx, be.container, &swift.ObjectsOpts{Prefix: prefix}, - func(ctx context.Context, opts *swift.ObjectsOpts) (interface{}, error) { + func(ctx context.Context, opts *swift.ObjectsOpts) (any, error) { newObjects, err := be.conn.Objects(ctx, be.container, opts) if err != nil { diff --git a/internal/backend/test/suite.go b/internal/backend/test/suite.go index 86acc5cb5..00cff81bd 100644 --- a/internal/backend/test/suite.go +++ b/internal/backend/test/suite.go @@ -67,7 +67,7 @@ type testFunction struct { } func (s *Suite[C]) testFuncs(t testing.TB) (funcs []testFunction) { - tpe := reflect.TypeOf(s) + tpe := reflect.TypeFor[*Suite[C]]() v := reflect.ValueOf(s) for i := 0; i < tpe.NumMethod(); i++ { @@ -102,7 +102,7 @@ type benchmarkFunction struct { } func (s *Suite[C]) benchmarkFuncs(t testing.TB) (funcs []benchmarkFunction) { - tpe := reflect.TypeOf(s) + tpe := reflect.TypeFor[*Suite[C]]() v := reflect.ValueOf(s) for i := 0; i < tpe.NumMethod(); i++ { @@ -192,7 +192,7 @@ func (s *Suite[C]) open(t testing.TB) backend.Backend { t.Fatalf("cannot create transport for tests: %v", err) } - be, err := s.Factory.Open(context.TODO(), s.Config, tr, nil, func(string, ...interface{}) {}) + be, err := s.Factory.Open(context.TODO(), s.Config, tr, nil, func(string, ...any) {}) if err != nil { t.Fatal(err) } diff --git a/internal/backend/test/tests.go b/internal/backend/test/tests.go index 4999bddd9..2c996b2ac 100644 --- a/internal/backend/test/tests.go +++ b/internal/backend/test/tests.go @@ -277,7 +277,7 @@ func (s *Suite[C]) TestList(t *testing.T) { var m sync.Mutex wg, ctx := errgroup.WithContext(context.TODO()) - for i := 0; i < numTestFiles; i++ { + for range numTestFiles { data := test.Random(random.Int(), random.Intn(100)+55) wg.Go(func() error { id := restic.Hash(data) @@ -354,8 +354,8 @@ func (s *Suite[C]) TestListCancel(t *testing.T) { testFiles := make([]backend.Handle, 0, numTestFiles) - for i := 0; i < numTestFiles; i++ { - data := []byte(fmt.Sprintf("random test blob %v", i)) + for i := range numTestFiles { + data := fmt.Appendf(nil, "random test blob %v", i) id := restic.Hash(data) h := backend.Handle{Type: backend.PackFile, Name: id.String()} err := b.Save(context.TODO(), h, backend.NewByteReader(data, b.Hasher())) @@ -768,7 +768,7 @@ func (s *Suite[C]) delayedRemove(t testing.TB, be backend.Backend, handles ...ba func delayedList(t testing.TB, b backend.Backend, tpe backend.FileType, max int, maxwait time.Duration) restic.IDs { list := restic.NewIDSet() start := time.Now() - for i := 0; i < max; i++ { + for range max { err := b.List(context.TODO(), tpe, func(fi backend.FileInfo) error { id := restic.TestParseID(fi.Name) list.Insert(id) diff --git a/internal/bloblru/cache_test.go b/internal/bloblru/cache_test.go index 5fe7bc73c..dd3e0c43d 100644 --- a/internal/bloblru/cache_test.go +++ b/internal/bloblru/cache_test.go @@ -94,7 +94,7 @@ func TestCacheGetOrCompute(t *testing.T) { calls := make(chan struct{}, 10) // start a bunch of blocking goroutines - for i := 0; i < 10; i++ { + for range 10 { wg.Go(func() error { buf, err := c.GetOrCompute(id2, func() ([]byte, error) { // block to ensure that multiple requests are waiting in parallel diff --git a/internal/checker/checker_test.go b/internal/checker/checker_test.go index d755f1201..f70f96fe7 100644 --- a/internal/checker/checker_test.go +++ b/internal/checker/checker_test.go @@ -609,7 +609,7 @@ func benchmarkSnapshotScaling(t *testing.B, newSnapshots int) { treeID := sn2.Tree - for i := 0; i < newSnapshots; i++ { + for i := range newSnapshots { sn, err := data.NewSnapshot([]string{"test" + strconv.Itoa(i)}, nil, "", time.Now()) if err != nil { t.Fatal(err) diff --git a/internal/data/find_test.go b/internal/data/find_test.go index 284566027..f1d9a7924 100644 --- a/internal/data/find_test.go +++ b/internal/data/find_test.go @@ -88,7 +88,7 @@ func TestFindUsedBlobs(t *testing.T) { repo := repository.TestRepository(t) var snapshots []*data.Snapshot - for i := 0; i < findTestSnapshots; i++ { + for i := range findTestSnapshots { sn := data.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth) t.Logf("snapshot %v saved, tree %v", sn.ID().Str(), sn.Tree.Str()) snapshots = append(snapshots, sn) @@ -131,7 +131,7 @@ func TestMultiFindUsedBlobs(t *testing.T) { repo := repository.TestRepository(t) var snapshotTrees restic.IDs - for i := 0; i < findTestSnapshots; i++ { + for i := range findTestSnapshots { sn := data.TestCreateSnapshot(t, repo, findTestTime.Add(time.Duration(i)*time.Second), findTestDepth) t.Logf("snapshot %v saved, tree %v", sn.ID().Str(), sn.Tree.Str()) snapshotTrees = append(snapshotTrees, *sn.Tree) diff --git a/internal/data/node.go b/internal/data/node.go index e7be9914c..2c4e9096c 100644 --- a/internal/data/node.go +++ b/internal/data/node.go @@ -86,9 +86,9 @@ type Node struct { Name string `json:"name"` Type NodeType `json:"type"` Mode os.FileMode `json:"mode,omitempty"` - ModTime time.Time `json:"mtime,omitempty"` - AccessTime time.Time `json:"atime,omitempty"` - ChangeTime time.Time `json:"ctime,omitempty"` + ModTime time.Time `json:"mtime"` + AccessTime time.Time `json:"atime"` + ChangeTime time.Time `json:"ctime"` UID uint32 `json:"uid"` GID uint32 `json:"gid"` User string `json:"user,omitempty"` diff --git a/internal/data/snapshot.go b/internal/data/snapshot.go index 6258e34b7..4e2f81503 100644 --- a/internal/data/snapshot.go +++ b/internal/data/snapshot.go @@ -5,6 +5,7 @@ import ( "fmt" "os/user" "path/filepath" + "slices" "sync" "time" @@ -174,12 +175,7 @@ func (sn *Snapshot) RemoveTags(removeTags []string) (changed bool) { } func (sn *Snapshot) hasTag(tag string) bool { - for _, snTag := range sn.Tags { - if tag == snTag { - return true - } - } - return false + return slices.Contains(sn.Tags, tag) } // HasTags returns true if the snapshot has all the tags in l. @@ -240,13 +236,7 @@ func (sn *Snapshot) HasHostname(hostnames []string) bool { return true } - for _, hostname := range hostnames { - if sn.Hostname == hostname { - return true - } - } - - return false + return slices.Contains(hostnames, sn.Hostname) } // Snapshots is a list of snapshots. diff --git a/internal/data/snapshot_group.go b/internal/data/snapshot_group.go index ca4b0aabc..620e153f5 100644 --- a/internal/data/snapshot_group.go +++ b/internal/data/snapshot_group.go @@ -15,7 +15,7 @@ type SnapshotGroupByOptions struct { func splitSnapshotGroupBy(s string) (SnapshotGroupByOptions, error) { var l SnapshotGroupByOptions - for _, option := range strings.Split(s, ",") { + for option := range strings.SplitSeq(s, ",") { switch option { case "host", "hosts": l.Host = true diff --git a/internal/data/tag_list.go b/internal/data/tag_list.go index b31072d94..ec02f7e1b 100644 --- a/internal/data/tag_list.go +++ b/internal/data/tag_list.go @@ -12,7 +12,7 @@ type TagList []string // need to be separated by commas. Whitespace is stripped around the individual // tags. func splitTagList(s string) (l TagList) { - for _, t := range strings.Split(s, ",") { + for t := range strings.SplitSeq(s, ",") { l = append(l, strings.TrimSpace(t)) } return l diff --git a/internal/data/testing.go b/internal/data/testing.go index 79b0ade5d..6457d97a4 100644 --- a/internal/data/testing.go +++ b/internal/data/testing.go @@ -75,7 +75,7 @@ func (fs *fakeFileSystem) saveTree(ctx context.Context, uploader restic.BlobSave numNodes := int(rnd.Int63() % maxNodes) var nodes []*Node - for i := 0; i < numNodes; i++ { + for i := range numNodes { // randomly select the type of the node, either tree (p = 1/4) or file (p = 3/4). if depth > 1 && rnd.Int63()%4 == 0 { treeSeed := rnd.Int63() % maxSeed diff --git a/internal/data/testing_test.go b/internal/data/testing_test.go index 35d32c04b..cc8bc39a7 100644 --- a/internal/data/testing_test.go +++ b/internal/data/testing_test.go @@ -20,7 +20,7 @@ const ( func TestCreateSnapshot(t *testing.T) { repo := repository.TestRepository(t) - for i := 0; i < testCreateSnapshots; i++ { + for i := range testCreateSnapshots { data.TestCreateSnapshot(t, repo, testSnapshotTime.Add(time.Duration(i)*time.Second), testDepth) } diff --git a/internal/data/tree_stream.go b/internal/data/tree_stream.go index baf7af2be..a2eb3f49b 100644 --- a/internal/data/tree_stream.go +++ b/internal/data/tree_stream.go @@ -201,7 +201,7 @@ func StreamTrees( // decoding a tree can take quite some time such that this can be both CPU- or IO-bound // one extra worker to handle huge tree blobs workerCount := int(repo.Connections()) + runtime.GOMAXPROCS(0) + 1 - for i := 0; i < workerCount; i++ { + for i := range workerCount { workerLoaderChan := loaderChan if i == 0 { workerLoaderChan = hugeTreeChan diff --git a/internal/debug/debug.go b/internal/debug/debug.go index a8c3a7f33..5e4f8aad0 100644 --- a/internal/debug/debug.go +++ b/internal/debug/debug.go @@ -61,7 +61,7 @@ func parseFilter(envname string, pad func(string) string) map[string]bool { return filter } - for _, fn := range strings.Split(env, ",") { + for fn := range strings.SplitSeq(env, ",") { t := pad(strings.TrimSpace(fn)) val := true switch t[0] { @@ -161,7 +161,7 @@ func checkFilter(filter map[string]bool, key string) bool { } // Log prints a message to the debug log (if debug is enabled). -func Log(f string, args ...interface{}) { +func Log(f string, args ...any) { if !opts.isEnabled { return } diff --git a/internal/debug/round_tripper.go b/internal/debug/round_tripper.go index 4afab7298..3ec0e6bc3 100644 --- a/internal/debug/round_tripper.go +++ b/internal/debug/round_tripper.go @@ -3,6 +3,7 @@ package debug import ( "fmt" "io" + "maps" "net/http" "net/http/httputil" "os" @@ -77,9 +78,7 @@ func redactHeader(header http.Header) map[string][]string { } func restoreHeader(header http.Header, origHeaders map[string][]string) { - for hdr, val := range origHeaders { - header[hdr] = val - } + maps.Copy(header, origHeaders) } func (tr loggingRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err error) { diff --git a/internal/dump/common_test.go b/internal/dump/common_test.go index 042d41f90..53cf17490 100644 --- a/internal/dump/common_test.go +++ b/internal/dump/common_test.go @@ -2,7 +2,6 @@ package dump import ( "bytes" - "context" "testing" "github.com/restic/restic/internal/archiver" @@ -80,8 +79,7 @@ func WriteTest(t *testing.T, format string, cd CheckDump) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() tmpdir, repo, be := prepareTempdirRepoSrc(t, tt.args) arch := archiver.New(repo, fs.Track{FS: fs.NewLocal()}, archiver.Options{}) diff --git a/internal/errors/errors.go b/internal/errors/errors.go index 96e5b82bb..7a0ad1c18 100644 --- a/internal/errors/errors.go +++ b/internal/errors/errors.go @@ -30,7 +30,7 @@ var WithStack = errors.WithStack // As finds the first error in err's tree that matches target, and if one is found, // sets target to that error value and returns true. Otherwise, it returns false. -func As(err error, tgt interface{}) bool { return stderrors.As(err, tgt) } +func As(err error, tgt any) bool { return stderrors.As(err, tgt) } // Is reports whether any error in err's tree matches target. func Is(x, y error) bool { return stderrors.Is(x, y) } diff --git a/internal/errors/fatal.go b/internal/errors/fatal.go index 12b310aca..f7029df0e 100644 --- a/internal/errors/fatal.go +++ b/internal/errors/fatal.go @@ -33,7 +33,7 @@ func Fatal(s string) error { } // Fatalf returns an error that is marked fatal, preserving an underlying error if passed. -func Fatalf(s string, data ...interface{}) error { +func Fatalf(s string, data ...any) error { // Use the last error found. var underlyingErr error for i := len(data) - 1; i >= 0; i-- { diff --git a/internal/feature/features.go b/internal/feature/features.go index e3b625e92..ea5d76ef7 100644 --- a/internal/feature/features.go +++ b/internal/feature/features.go @@ -64,7 +64,7 @@ func (f *FlagSet) Apply(flags string, logWarning func(string)) error { selection := make(map[string]bool) - for _, flag := range strings.Split(flags, ",") { + for flag := range strings.SplitSeq(flags, ",") { parts := strings.SplitN(flag, "=", 2) name := parts[0] diff --git a/internal/filter/exclude.go b/internal/filter/exclude.go index 1d3042a58..44f4331c0 100644 --- a/internal/filter/exclude.go +++ b/internal/filter/exclude.go @@ -20,7 +20,7 @@ type RejectByNameFunc func(path string) bool // RejectByPattern returns a RejectByNameFunc which rejects files that match // one of the patterns. -func RejectByPattern(patterns []string, warnf func(msg string, args ...interface{})) RejectByNameFunc { +func RejectByPattern(patterns []string, warnf func(msg string, args ...any)) RejectByNameFunc { parsedPatterns := ParsePatterns(patterns) return func(item string) bool { matched, err := List(parsedPatterns, item) @@ -38,7 +38,7 @@ func RejectByPattern(patterns []string, warnf func(msg string, args ...interface } // RejectByInsensitivePattern is like RejectByPattern but case insensitive. -func RejectByInsensitivePattern(patterns []string, warnf func(msg string, args ...interface{})) RejectByNameFunc { +func RejectByInsensitivePattern(patterns []string, warnf func(msg string, args ...any)) RejectByNameFunc { lowerPatterns := make([]string, len(patterns)) for index, path := range patterns { lowerPatterns[index] = strings.ToLower(path) @@ -115,7 +115,7 @@ func (opts *ExcludePatternOptions) Empty() bool { return len(opts.Excludes) == 0 && len(opts.InsensitiveExcludes) == 0 && len(opts.ExcludeFiles) == 0 && len(opts.InsensitiveExcludeFiles) == 0 } -func (opts ExcludePatternOptions) CollectPatterns(warnf func(msg string, args ...interface{})) ([]RejectByNameFunc, error) { +func (opts ExcludePatternOptions) CollectPatterns(warnf func(msg string, args ...any)) ([]RejectByNameFunc, error) { var fs []RejectByNameFunc // add patterns from file if len(opts.ExcludeFiles) > 0 { diff --git a/internal/filter/filter.go b/internal/filter/filter.go index c2b5f98ce..266ca5a98 100644 --- a/internal/filter/filter.go +++ b/internal/filter/filter.go @@ -131,11 +131,7 @@ func childMatch(pattern Pattern, strs []string) (matched bool, err error) { // match path against absolute pattern prefix l := 0 - if len(strs) > len(pattern.parts) { - l = len(pattern.parts) - } else { - l = len(strs) - } + l = min(len(strs), len(pattern.parts)) return match(Pattern{pattern.original, pattern.parts[0:l], pattern.isNegated}, strs) } diff --git a/internal/filter/include.go b/internal/filter/include.go index 56c4d7258..ae512b521 100644 --- a/internal/filter/include.go +++ b/internal/filter/include.go @@ -29,7 +29,7 @@ func (opts *IncludePatternOptions) Empty() bool { return len(opts.Includes) == 0 && len(opts.InsensitiveIncludes) == 0 && len(opts.IncludeFiles) == 0 && len(opts.InsensitiveIncludeFiles) == 0 } -func (opts IncludePatternOptions) CollectPatterns(warnf func(msg string, args ...interface{})) ([]IncludeByNameFunc, error) { +func (opts IncludePatternOptions) CollectPatterns(warnf func(msg string, args ...any)) ([]IncludeByNameFunc, error) { var fs []IncludeByNameFunc if len(opts.IncludeFiles) > 0 { includePatterns, err := readPatternsFromFiles(opts.IncludeFiles) @@ -77,7 +77,7 @@ func (opts IncludePatternOptions) CollectPatterns(warnf func(msg string, args .. // IncludeByPattern returns an IncludeByNameFunc which includes files that match // one of the patterns. -func IncludeByPattern(patterns []string, warnf func(msg string, args ...interface{})) IncludeByNameFunc { +func IncludeByPattern(patterns []string, warnf func(msg string, args ...any)) IncludeByNameFunc { parsedPatterns := ParsePatterns(patterns) return func(item string) (matched bool, childMayMatch bool) { matched, childMayMatch, err := ListWithChild(parsedPatterns, item) @@ -91,7 +91,7 @@ func IncludeByPattern(patterns []string, warnf func(msg string, args ...interfac // IncludeByInsensitivePattern returns an IncludeByNameFunc which includes files that match // one of the patterns, ignoring the casing of the filenames. -func IncludeByInsensitivePattern(patterns []string, warnf func(msg string, args ...interface{})) IncludeByNameFunc { +func IncludeByInsensitivePattern(patterns []string, warnf func(msg string, args ...any)) IncludeByNameFunc { lowerPatterns := make([]string, len(patterns)) for index, path := range patterns { lowerPatterns[index] = strings.ToLower(path) diff --git a/internal/fs/fs_local_vss.go b/internal/fs/fs_local_vss.go index 1dc5b771c..e0b04ac8f 100644 --- a/internal/fs/fs_local_vss.go +++ b/internal/fs/fs_local_vss.go @@ -42,7 +42,7 @@ func ParseVSSConfig(o options.Options) (VSSConfig, error) { type ErrorHandler func(item string, err error) // MessageHandler is used to report errors/messages via callbacks. -type MessageHandler func(msg string, args ...interface{}) +type MessageHandler func(msg string, args ...any) // volumeFilter is used to filter volumes by their mount point or GUID path. type volumeFilter func(volume string) bool @@ -72,7 +72,7 @@ func parseMountPoints(list string, msgError ErrorHandler) (volumes map[string]st if list == "" { return } - for _, s := range strings.Split(list, ";") { + for s := range strings.SplitSeq(list, ";") { if v, err := getVolumeNameForVolumeMountPoint(s); err != nil { msgError(s, errors.Errorf("failed to parse vss.exclude-volumes [%s]: %s", s, err)) } else { diff --git a/internal/fs/fs_reader_command.go b/internal/fs/fs_reader_command.go index c2d359d92..16313bf1b 100644 --- a/internal/fs/fs_reader_command.go +++ b/internal/fs/fs_reader_command.go @@ -28,7 +28,7 @@ type commandReader struct { alreadyClosedReadErr error } -func NewCommandReader(ctx context.Context, args []string, errorOutput func(msg string, args ...interface{})) (io.ReadCloser, error) { +func NewCommandReader(ctx context.Context, args []string, errorOutput func(msg string, args ...any)) (io.ReadCloser, error) { if len(args) == 0 { return nil, fmt.Errorf("no command was specified as argument") } diff --git a/internal/fs/fs_reader_command_test.go b/internal/fs/fs_reader_command_test.go index 214b1003e..dd8e1c0e0 100644 --- a/internal/fs/fs_reader_command_test.go +++ b/internal/fs/fs_reader_command_test.go @@ -13,7 +13,7 @@ import ( ) func TestCommandReaderSuccess(t *testing.T) { - reader, err := fs.NewCommandReader(context.TODO(), []string{"true"}, func(msg string, args ...interface{}) {}) + reader, err := fs.NewCommandReader(context.TODO(), []string{"true"}, func(msg string, args ...any) {}) test.OK(t, err) _, err = io.Copy(io.Discard, reader) @@ -23,7 +23,7 @@ func TestCommandReaderSuccess(t *testing.T) { } func TestCommandReaderFail(t *testing.T) { - reader, err := fs.NewCommandReader(context.TODO(), []string{"false"}, func(msg string, args ...interface{}) {}) + reader, err := fs.NewCommandReader(context.TODO(), []string{"false"}, func(msg string, args ...any) {}) test.OK(t, err) _, err = io.Copy(io.Discard, reader) @@ -31,17 +31,17 @@ func TestCommandReaderFail(t *testing.T) { } func TestCommandReaderInvalid(t *testing.T) { - _, err := fs.NewCommandReader(context.TODO(), []string{"w54fy098hj7fy5twijouytfrj098y645wr"}, func(msg string, args ...interface{}) {}) + _, err := fs.NewCommandReader(context.TODO(), []string{"w54fy098hj7fy5twijouytfrj098y645wr"}, func(msg string, args ...any) {}) test.Assert(t, err != nil, "missing error") } func TestCommandReaderEmptyArgs(t *testing.T) { - _, err := fs.NewCommandReader(context.TODO(), []string{}, func(msg string, args ...interface{}) {}) + _, err := fs.NewCommandReader(context.TODO(), []string{}, func(msg string, args ...any) {}) test.Assert(t, err != nil, "missing error") } func TestCommandReaderOutput(t *testing.T) { - reader, err := fs.NewCommandReader(context.TODO(), []string{"echo", "hello world"}, func(msg string, args ...interface{}) {}) + reader, err := fs.NewCommandReader(context.TODO(), []string{"echo", "hello world"}, func(msg string, args ...any) {}) test.OK(t, err) var buf bytes.Buffer @@ -56,7 +56,7 @@ func TestCommandReaderOutput(t *testing.T) { func TestCommandReaderQuickClose(t *testing.T) { ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second) defer cancel() - reader, err := fs.NewCommandReader(ctx, []string{"sleep", "3600"}, func(msg string, args ...interface{}) {}) + reader, err := fs.NewCommandReader(ctx, []string{"sleep", "3600"}, func(msg string, args ...any) {}) test.OK(t, err) // test that close returns before the context expires diff --git a/internal/fs/node_test.go b/internal/fs/node_test.go index 50763fc06..4f087635e 100644 --- a/internal/fs/node_test.go +++ b/internal/fs/node_test.go @@ -198,7 +198,7 @@ func TestNodeRestoreAt(t *testing.T) { // Update the tests to use UPPER case xattr names for windows. extAttrArr := test.ExtendedAttributes // Iterate through the array using pointers - for i := 0; i < len(extAttrArr); i++ { + for i := range extAttrArr { extAttrArr[i].Name = strings.ToUpper(extAttrArr[i].Name) } } diff --git a/internal/fs/node_xattr_all_test.go b/internal/fs/node_xattr_all_test.go index 0a2a62c45..08621993e 100644 --- a/internal/fs/node_xattr_all_test.go +++ b/internal/fs/node_xattr_all_test.go @@ -122,7 +122,7 @@ func TestOverwriteXattrWithSelectFilter(t *testing.T) { file := filepath.Join(dir, "file2") rtest.OK(t, os.WriteFile(file, []byte("hello world"), 0o600)) - noopWarnf := func(_ string, _ ...interface{}) {} + noopWarnf := func(_ string, _ ...any) {} // Set a filter as if the user passed in --include-xattr user.* xattrSelectFilter1 := func(xattrName string) bool { diff --git a/internal/fuse/fuse_test.go b/internal/fuse/fuse_test.go index 719d6c2eb..aed188dcd 100644 --- a/internal/fuse/fuse_test.go +++ b/internal/fuse/fuse_test.go @@ -69,8 +69,7 @@ func loadTree(t testing.TB, repo restic.Loader, id restic.ID) data.TreeNodeItera func TestFuseFile(t *testing.T) { repo := repository.TestRepository(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() timestamp, err := time.Parse(time.RFC3339, "2017-01-24T10:42:56+01:00") rtest.OK(t, err) @@ -134,7 +133,7 @@ func TestFuseFile(t *testing.T) { rtest.Equals(t, node.Size, attr.Size) rtest.Equals(t, (node.Size/uint64(attr.BlockSize))+1, attr.Blocks) - for i := 0; i < 200; i++ { + for i := range 200 { offset := rand.Intn(int(filesize)) length := rand.Intn(int(filesize)-offset) + 100 diff --git a/internal/global/global.go b/internal/global/global.go index e44182de1..4df90a600 100644 --- a/internal/global/global.go +++ b/internal/global/global.go @@ -522,7 +522,7 @@ func innerOpenBackend(ctx context.Context, s string, gopts Options, opts options } // parseConfig parses the repository location and extended options and returns the scheme and configuration. -func parseConfig(backends *location.Registry, s string, opts options.Options) (string, interface{}, error) { +func parseConfig(backends *location.Registry, s string, opts options.Options) (string, any, error) { loc, err := location.Parse(backends, s) if err != nil { return "", nil, errors.Fatalf("parsing repository location failed: %v", err) @@ -558,7 +558,7 @@ func setupTransport(gopts Options) (http.RoundTripper, limiter.Limiter, error) { } // createOrOpenBackend creates or opens a backend using the appropriate factory method. -func createOrOpenBackend(ctx context.Context, scheme string, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter, gopts Options, s string, create bool, printer restic.Printer) (backend.Backend, error) { +func createOrOpenBackend(ctx context.Context, scheme string, cfg any, rt http.RoundTripper, lim limiter.Limiter, gopts Options, s string, create bool, printer restic.Printer) (backend.Backend, error) { factory := gopts.Backends.Lookup(scheme) if factory == nil { return nil, errors.Fatalf("invalid backend: %q", scheme) diff --git a/internal/options/options.go b/internal/options/options.go index 7490ac430..71236e940 100644 --- a/internal/options/options.go +++ b/internal/options/options.go @@ -16,7 +16,7 @@ type Options map[string]string var opts []Help // Register allows registering options so that they can be listed with List. -func Register(ns string, cfg interface{}) { +func Register(ns string, cfg any) { opts = appendAllOptions(opts, ns, cfg) } @@ -28,7 +28,7 @@ func List() (list []Help) { } // appendAllOptions appends all options in cfg to opts, sorted by namespace. -func appendAllOptions(opts []Help, ns string, cfg interface{}) []Help { +func appendAllOptions(opts []Help, ns string, cfg any) []Help { for _, opt := range listOptions(cfg) { opt.Namespace = ns opts = append(opts, opt) @@ -39,7 +39,7 @@ func appendAllOptions(opts []Help, ns string, cfg interface{}) []Help { } // listOptions returns a list of options of cfg. -func listOptions(cfg interface{}) (opts []Help) { +func listOptions(cfg any) (opts []Help) { // resolve indirection if cfg is a pointer v := reflect.Indirect(reflect.ValueOf(cfg)) @@ -145,7 +145,7 @@ func (o Options) Extract(ns string) Options { // Apply sets the options on dst via reflection, using the struct tag `option`. // The namespace argument (ns) is only used for error messages. -func (o Options) Apply(ns string, dst interface{}) error { +func (o Options) Apply(ns string, dst any) error { v := reflect.ValueOf(dst).Elem() fields := make(map[string]reflect.StructField) diff --git a/internal/options/options_test.go b/internal/options/options_test.go index ce5153f5b..c83f87639 100644 --- a/internal/options/options_test.go +++ b/internal/options/options_test.go @@ -247,7 +247,7 @@ func TestListOptions(t *testing.T) { }{} tests := []struct { - cfg interface{} + cfg any opts []Help }{ { @@ -298,11 +298,11 @@ func TestListOptions(t *testing.T) { func TestAppendAllOptions(t *testing.T) { tests := []struct { - cfgs map[string]interface{} + cfgs map[string]any opts []Help }{ { - map[string]interface{}{ + map[string]any{ "local": struct { Foo string `option:"foo" help:"bar text help"` }{}, diff --git a/internal/repository/checker.go b/internal/repository/checker.go index bb7e6ff96..5855dbffa 100644 --- a/internal/repository/checker.go +++ b/internal/repository/checker.go @@ -291,7 +291,7 @@ func (c *Checker) ReadPacks(ctx context.Context, filter func(packs map[restic.ID // as packs are streamed the concurrency is limited by IO workerCount := int(c.repo.Connections()) // run workers - for i := 0; i < workerCount; i++ { + for range workerCount { g.Go(func() error { bufRd := bufio.NewReaderSize(nil, maxStreamBufferSize) dec, err := zstd.NewReader(nil) diff --git a/internal/repository/crypto/crypto.go b/internal/repository/crypto/crypto.go index d7ac9c3d4..d8b7663f0 100644 --- a/internal/repository/crypto/crypto.go +++ b/internal/repository/crypto/crypto.go @@ -145,7 +145,7 @@ func (m *MACKey) UnmarshalJSON(data []byte) error { // Valid tests whether the key k is valid (i.e. not zero). func (m *MACKey) Valid() bool { nonzeroK := false - for i := 0; i < len(m.K); i++ { + for i := range len(m.K) { if m.K[i] != 0 { nonzeroK = true } @@ -155,7 +155,7 @@ func (m *MACKey) Valid() bool { return false } - for i := 0; i < len(m.R); i++ { + for i := range len(m.R) { if m.R[i] != 0 { return true } @@ -183,7 +183,7 @@ func (k *EncryptionKey) UnmarshalJSON(data []byte) error { // Valid tests whether the key k is valid (i.e. not zero). func (k *EncryptionKey) Valid() bool { - for i := 0; i < len(k); i++ { + for i := range len(k) { if k[i] != 0 { return true } diff --git a/internal/repository/crypto/crypto_int_test.go b/internal/repository/crypto/crypto_int_test.go index a370ef32e..966dea53b 100644 --- a/internal/repository/crypto/crypto_int_test.go +++ b/internal/repository/crypto/crypto_int_test.go @@ -171,7 +171,7 @@ func TestNonceValid(t *testing.T) { t.Error("null nonce detected as valid") } - for i := 0; i < 100; i++ { + for range 100 { nonce = NewRandomNonce() if !validNonce(nonce) { t.Errorf("random nonce not detected as valid: %02x", nonce) diff --git a/internal/repository/index/index_test.go b/internal/repository/index/index_test.go index d5a779da3..f0a395d7d 100644 --- a/internal/repository/index/index_test.go +++ b/internal/repository/index/index_test.go @@ -20,12 +20,12 @@ func TestIndexSerialize(t *testing.T) { idx := index.NewIndex() // create 50 packs with 20 blobs each - for i := 0; i < 50; i++ { + for i := range 50 { packID := restic.NewRandomID() var blobs pack.Blobs pos := uint(0) - for j := 0; j < 20; j++ { + for j := range 20 { length := uint(i*100 + j) uncompressedLength := uint(0) if i >= 25 { @@ -84,12 +84,12 @@ func TestIndexSerialize(t *testing.T) { // add more blobs to idx newtests := []*pack.PackedBlob{} - for i := 0; i < 10; i++ { + for i := range 10 { packID := restic.NewRandomID() var blobs pack.Blobs pos := uint(0) - for j := 0; j < 10; j++ { + for j := range 10 { length := uint(i*100 + j) pb := &pack.PackedBlob{ Pack: packID, @@ -144,12 +144,12 @@ func TestIndexSize(t *testing.T) { packs := 200 blobCount := 100 - for i := 0; i < packs; i++ { + for i := range packs { packID := restic.NewRandomID() var blobs pack.Blobs pos := uint(0) - for j := 0; j < blobCount; j++ { + for j := range blobCount { length := uint(i*100 + j) blobs = append(blobs, pack.Blob{ BlobHandle: restic.NewRandomBlobHandle(), @@ -400,7 +400,7 @@ func TestIndexPacks(t *testing.T) { idx := index.NewIndex() packs := restic.NewIDSet() - for i := 0; i < 20; i++ { + for range 20 { packID := restic.NewRandomID() idx.StorePack(packID, pack.Blobs{ { @@ -432,7 +432,7 @@ func createRandomIndex(rng *rand.Rand, packfiles int) (idx *index.Index, lookupB idx.Preallocate(restic.DataBlob, packfiles*9) // create index with given number of pack files - for i := 0; i < packfiles; i++ { + for i := range packfiles { packID := NewRandomTestID(rng) var blobs pack.Blobs offset := 0 @@ -523,12 +523,12 @@ func TestIndexHas(t *testing.T) { idx := index.NewIndex() // create 50 packs with 20 blobs each - for i := 0; i < 50; i++ { + for i := range 50 { packID := restic.NewRandomID() var blobs pack.Blobs pos := uint(0) - for j := 0; j < 20; j++ { + for j := range 20 { length := uint(i*100 + j) uncompressedLength := uint(0) if i >= 25 { @@ -564,7 +564,7 @@ func TestMixedEachByPack(t *testing.T) { expected := make(map[restic.ID]int) // create 50 packs with 2 blobs each - for i := 0; i < 50; i++ { + for range 50 { packID := restic.NewRandomID() expected[packID] = 1 blobs := pack.Blobs{ @@ -602,7 +602,7 @@ func TestEachByPackIgnoes(t *testing.T) { ignores := restic.NewIDSet() expected := make(map[restic.ID]int) // create 50 packs with one blob each - for i := 0; i < 50; i++ { + for i := range 50 { packID := restic.NewRandomID() if i < 3 { ignores.Insert(packID) diff --git a/internal/repository/index/indexmap_test.go b/internal/repository/index/indexmap_test.go index 085d6acb1..50c1f9557 100644 --- a/internal/repository/index/indexmap_test.go +++ b/internal/repository/index/indexmap_test.go @@ -42,7 +42,7 @@ func TestIndexMapForeach(t *testing.T) { // empty iteration } - for i := 0; i < N; i++ { + for i := range N { var id restic.ID id[0] = byte(i) m.add(id, uint32(i), uint32(i), uint32(i), uint32(i/2)) @@ -90,11 +90,11 @@ func TestIndexMapForeachWithID(t *testing.T) { rtest.Equals(t, 0, n) // Test insertion and retrieval of duplicates. - for i := 0; i < ndups; i++ { + for i := range ndups { m.add(id, uint32(i), 0, 0, 0) } - for i := 0; i < 100; i++ { + for range 100 { var otherid restic.ID r.Read(otherid[:]) m.add(otherid, math.MaxUint32, 0, 0, 0) @@ -116,13 +116,13 @@ func TestIndexMapForeachWithID(t *testing.T) { func TestHashedArrayTree(t *testing.T) { hat := newHAT() const testSize = 1024 - for i := uint(0); i < testSize; i++ { + for i := range uint(testSize) { rtest.Assert(t, hat.Size() == i, "expected hat size %v got %v", i, hat.Size()) e, idx := hat.Alloc() rtest.Assert(t, idx == i, "expected entry at idx %v got %v", i, idx) e.length = uint32(i) } - for i := uint(0); i < testSize; i++ { + for i := range uint(testSize) { e := hat.Ref(i) rtest.Assert(t, e.length == uint32(i), "expected entry to contain %v got %v", uint32(i), e.length) } diff --git a/internal/repository/index/master_index.go b/internal/repository/index/master_index.go index 500989c5a..7a03587cf 100644 --- a/internal/repository/index/master_index.go +++ b/internal/repository/index/master_index.go @@ -452,7 +452,7 @@ func (mi *MasterIndex) Rewrite(ctx context.Context, repo restic.Unpacked[restic. // the index files are probably already cached at this point loaderCount := runtime.GOMAXPROCS(0) // run workers on ch - for i := 0; i < loaderCount; i++ { + for range loaderCount { rewriteWg.Add(1) wg.Go(loader) } @@ -668,7 +668,7 @@ func (mi *MasterIndex) ListPacks(ctx context.Context, packs restic.IDSet) <-chan go func() { defer close(out) // only resort a part of the index to keep the memory overhead bounded - for i := byte(0); i < 16; i++ { + for i := range byte(16) { packBlob := make(map[restic.ID]pack.Blobs) for pack := range packs { if pack[0]&0xf == i { diff --git a/internal/repository/index/master_index_test.go b/internal/repository/index/master_index_test.go index 97fcb0ef3..36673f848 100644 --- a/internal/repository/index/master_index_test.go +++ b/internal/repository/index/master_index_test.go @@ -416,7 +416,7 @@ var ( func createFilledRepo(t testing.TB, snapshots int, version uint) (*repository.Repository, restic.Unpacked[restic.FileType]) { repo, unpacked, _ := repository.TestRepositoryWithVersion(t, version) - for i := 0; i < snapshots; i++ { + for i := range snapshots { data.TestCreateSnapshot(t, repo, snapshotTime.Add(time.Duration(i)*time.Second), depth) } return repo, unpacked @@ -595,11 +595,11 @@ func TestRewriteOversizedIndex(t *testing.T) { // build oversized index idx := index.NewIndex() numPacks := 5 - for p := 0; p < numPacks; p++ { + for range numPacks { packID := restic.NewRandomID() packBlobs := make(pack.Blobs, 0, fullIndexCount) - for i := 0; i < fullIndexCount; i++ { + for i := range fullIndexCount { blob := pack.Blob{ BlobHandle: restic.BlobHandle{ Type: restic.DataBlob, diff --git a/internal/repository/lock.go b/internal/repository/lock.go index 9a3e8aba5..2b0670c44 100644 --- a/internal/repository/lock.go +++ b/internal/repository/lock.go @@ -44,11 +44,11 @@ var lockerInst = &locker{ // LockRepo acquires a repository lock. The returned context is cancelled when // Unlock is called; cancelling the original context stops lock refresh. -func LockRepo(ctx context.Context, repo *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (func(), context.Context, error) { +func LockRepo(ctx context.Context, repo *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...any)) (func(), context.Context, error) { return lockerInst.Lock(ctx, repo, exclusive, retryLock, printRetry, logger) } -func (l *locker) Lock(ctx context.Context, r *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...interface{})) (func(), context.Context, error) { +func (l *locker) Lock(ctx context.Context, r *Repository, exclusive bool, retryLock time.Duration, printRetry func(msg string), logger func(format string, args ...any)) (func(), context.Context, error) { var lock *lockHandle var err error @@ -121,7 +121,7 @@ type refreshLockRequest struct { result chan bool } -func (l *locker) refreshLocks(ctx context.Context, backend backend.Backend, unlocker *unlocker, refreshed chan<- struct{}, forceRefresh <-chan refreshLockRequest, logger func(format string, args ...interface{})) { +func (l *locker) refreshLocks(ctx context.Context, backend backend.Backend, unlocker *unlocker, refreshed chan<- struct{}, forceRefresh <-chan refreshLockRequest, logger func(format string, args ...any)) { debug.Log("start") lock := unlocker.lock ticker := time.NewTicker(l.refreshInterval) @@ -185,7 +185,7 @@ func (l *locker) refreshLocks(ctx context.Context, backend backend.Backend, unlo } } -func (l *locker) monitorLockRefresh(ctx context.Context, unlocker *unlocker, refreshed <-chan struct{}, forceRefresh chan<- refreshLockRequest, logger func(format string, args ...interface{})) { +func (l *locker) monitorLockRefresh(ctx context.Context, unlocker *unlocker, refreshed <-chan struct{}, forceRefresh chan<- refreshLockRequest, logger func(format string, args ...any)) { // time.Now() might use a monotonic timer which is paused during standby // convert to unix time to ensure we compare real time values lastRefresh := time.Now().UnixNano() @@ -247,7 +247,7 @@ func (l *locker) monitorLockRefresh(ctx context.Context, unlocker *unlocker, ref } } -func tryRefreshStaleLock(ctx context.Context, be backend.Backend, lock *lockHandle, cancel context.CancelFunc, logger func(format string, args ...interface{})) bool { +func tryRefreshStaleLock(ctx context.Context, be backend.Backend, lock *lockHandle, cancel context.CancelFunc, logger func(format string, args ...any)) bool { freeze := backend.AsBackend[backend.FreezeBackend](be) if freeze != nil { debug.Log("freezing backend") diff --git a/internal/repository/lock_file.go b/internal/repository/lock_file.go index cdc295f0d..b05bf286a 100644 --- a/internal/repository/lock_file.go +++ b/internal/repository/lock_file.go @@ -164,7 +164,7 @@ func (l *lockHandle) checkForOtherLocks(ctx context.Context) error { } delay := initialWaitBetweenLockRetries // retry locking a few times - for i := 0; i < 4; i++ { + for i := range 4 { if i != 0 { // sleep between retries to give backend some time to settle if err := cancelableDelay(ctx, delay); err != nil { diff --git a/internal/repository/lock_test.go b/internal/repository/lock_test.go index 847be76e5..e0f01f788 100644 --- a/internal/repository/lock_test.go +++ b/internal/repository/lock_test.go @@ -35,7 +35,7 @@ func openLockTestRepo(t *testing.T, wrapper backendWrapper) (*Repository, backen } func checkedLockRepo(ctx context.Context, t *testing.T, repo *Repository, lockerInst *locker, retryLock time.Duration) (func(), context.Context) { - unlock, wrappedCtx, err := lockerInst.Lock(ctx, repo, false, retryLock, func(msg string) {}, func(format string, args ...interface{}) {}) + unlock, wrappedCtx, err := lockerInst.Lock(ctx, repo, false, retryLock, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) rtest.OK(t, wrappedCtx.Err()) return unlock, wrappedCtx @@ -73,10 +73,10 @@ func TestLockConflict(t *testing.T) { repo, be := openLockTestRepo(t, nil) repo2 := TestOpenBackend(t, be) - unlock, _, err := LockRepo(context.Background(), repo, true, 0, func(msg string) {}, func(format string, args ...interface{}) {}) + unlock, _, err := LockRepo(context.Background(), repo, true, 0, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) defer unlock() - _, _, err = LockRepo(context.Background(), repo2, false, 0, func(msg string) {}, func(format string, args ...interface{}) {}) + _, _, err = LockRepo(context.Background(), repo2, false, 0, func(msg string) {}, func(format string, args ...any) {}) if err == nil { t.Fatal("second lock should have failed") } @@ -237,14 +237,14 @@ func TestLockWaitTimeout(t *testing.T) { t.Parallel() repo, _ := openLockTestRepo(t, nil) - elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...interface{}) {}) + elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) defer elock() retryLock := 200 * time.Millisecond start := time.Now() - _, _, err = LockRepo(context.TODO(), repo, false, retryLock, func(msg string) {}, func(format string, args ...interface{}) {}) + _, _, err = LockRepo(context.TODO(), repo, false, retryLock, func(msg string) {}, func(format string, args ...any) {}) duration := time.Since(start) rtest.Assert(t, err != nil, @@ -259,7 +259,7 @@ func TestLockWaitCancel(t *testing.T) { t.Parallel() repo, _ := openLockTestRepo(t, nil) - elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...interface{}) {}) + elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) defer elock() @@ -270,7 +270,7 @@ func TestLockWaitCancel(t *testing.T) { ctx, cancel := context.WithCancel(context.TODO()) time.AfterFunc(cancelAfter, cancel) - _, _, err = LockRepo(ctx, repo, false, retryLock, func(msg string) {}, func(format string, args ...interface{}) {}) + _, _, err = LockRepo(ctx, repo, false, retryLock, func(msg string) {}, func(format string, args ...any) {}) duration := time.Since(start) rtest.Assert(t, err != nil, @@ -285,7 +285,7 @@ func TestLockWaitSuccess(t *testing.T) { t.Parallel() repo, _ := openLockTestRepo(t, nil) - elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...interface{}) {}) + elock, _, err := LockRepo(context.TODO(), repo, true, 0, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) retryLock := 200 * time.Millisecond @@ -295,7 +295,7 @@ func TestLockWaitSuccess(t *testing.T) { elock() }) - unlock, _, err := LockRepo(context.TODO(), repo, false, retryLock, func(msg string) {}, func(format string, args ...interface{}) {}) + unlock, _, err := LockRepo(context.TODO(), repo, false, retryLock, func(msg string) {}, func(format string, args ...any) {}) rtest.OK(t, err) unlock() } diff --git a/internal/repository/pack/pack.go b/internal/repository/pack/pack.go index 43254b80b..b0a4be24c 100644 --- a/internal/repository/pack/pack.go +++ b/internal/repository/pack/pack.go @@ -143,7 +143,7 @@ func verifyHeader(k *crypto.Key, header []byte, expected []Blob) error { if len(decoded) != len(expected) { return fmt.Errorf("pack header size mismatch") } - for i := 0; i < len(decoded); i++ { + for i := range decoded { if decoded[i] != expected[i] { return fmt.Errorf("pack header entry mismatch got %v instead of %v", decoded[i], expected[i]) } diff --git a/internal/repository/pack/pack_internal_test.go b/internal/repository/pack/pack_internal_test.go index 8c4c37b9c..0a3ed4ef2 100644 --- a/internal/repository/pack/pack_internal_test.go +++ b/internal/repository/pack/pack_internal_test.go @@ -132,10 +132,7 @@ func TestReadRecords(t *testing.T) { testReadRecords := func(dataSize, entryCount, totalRecords int) { totalHeader := rtest.Random(0, totalRecords*int(entrySize)+crypto.Extension) bufSize := entryCount*int(entrySize) + crypto.Extension - off := len(totalHeader) - bufSize - if off < 0 { - off = 0 - } + off := max(len(totalHeader)-bufSize, 0) expectedHeader := totalHeader[off:] buf := &bytes.Buffer{} @@ -172,8 +169,8 @@ func TestReadRecords(t *testing.T) { testReadRecords(dataSize+3, 1, 1) testReadRecords(dataSize+4, 1, 1) - for i := 0; i < 2; i++ { - for j := 0; j < 2; j++ { + for i := range 2 { + for j := range 2 { testReadRecords(dataSize, i, j) } } diff --git a/internal/repository/packer_manager_test.go b/internal/repository/packer_manager_test.go index b91d2262f..d174a1939 100644 --- a/internal/repository/packer_manager_test.go +++ b/internal/repository/packer_manager_test.go @@ -24,7 +24,7 @@ func randomID(rd io.Reader) restic.ID { const maxBlobSize = 1 << 20 func fillPacks(t testing.TB, rnd *rand.Rand, pm *packerManager, buf []byte) (bytes int) { - for i := 0; i < 102; i++ { + for range 102 { l := rnd.Intn(maxBlobSize) id := randomID(rnd) buf = buf[:l] diff --git a/internal/repository/prune_internal_test.go b/internal/repository/prune_internal_test.go index e49009813..9fec41c68 100644 --- a/internal/repository/prune_internal_test.go +++ b/internal/repository/prune_internal_test.go @@ -33,7 +33,7 @@ func TestPruneMaxUnusedDuplicate(t *testing.T) { const blobSize = 1024 * 1024 bufs := [][]byte{} - for i := 0; i < 4; i++ { + for range 4 { // use uniform length for simpler control via MaxUnusedBytes buf := make([]byte, blobSize) random.Read(buf) diff --git a/internal/repository/prune_test.go b/internal/repository/prune_test.go index cf5664104..f514ddd7c 100644 --- a/internal/repository/prune_test.go +++ b/internal/repository/prune_test.go @@ -134,7 +134,7 @@ func TestPruneSmall(t *testing.T) { keep := restic.NewBlobSet() rtest.OK(t, repo.WithBlobUploader(context.TODO(), func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { // we need a minimum of 11 packfiles, each packfile will be about 5 Mb long - for i := 0; i < numBlobsCreated; i++ { + for range numBlobsCreated { buf := make([]byte, blobSize) random.Read(buf) diff --git a/internal/repository/raw_test.go b/internal/repository/raw_test.go index ff57a60ed..30df82d0f 100644 --- a/internal/repository/raw_test.go +++ b/internal/repository/raw_test.go @@ -24,7 +24,7 @@ func TestLoadRaw(t *testing.T) { repo, err := repository.New(b, repository.Options{}) rtest.OK(t, err) - for i := 0; i < 5; i++ { + for i := range 5 { data := rtest.Random(23+i, 500*KiB) id := restic.Hash(data) diff --git a/internal/repository/repack.go b/internal/repository/repack.go index fb59a5c5a..910b871df 100644 --- a/internal/repository/repack.go +++ b/internal/repository/repack.go @@ -20,7 +20,7 @@ type repackBlobSet interface { Len() int } -type LogFunc func(msg string, args ...interface{}) +type LogFunc func(msg string, args ...any) // CopyBlobs takes a list of packs together with a list of blobs contained in // these packs. Each pack is loaded and the blobs listed in keepBlobs is saved @@ -42,7 +42,7 @@ func CopyBlobs( debug.Log("repacking %d packs while keeping %d blobs", len(packs), keepBlobs.Len()) if logf == nil { - logf = func(_ string, _ ...interface{}) {} + logf = func(_ string, _ ...any) {} } p.SetMax(uint64(len(packs))) defer p.Done() diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 8eb9e6a81..0a3ca836d 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -163,7 +163,7 @@ func (r *Repository) PackSize() uint { } // UseCache replaces the backend with the wrapped cache. -func (r *Repository) UseCache(c *cache.Cache, errorLog func(string, ...interface{})) { +func (r *Repository) UseCache(c *cache.Cache, errorLog func(string, ...any)) { if c == nil { return } @@ -810,7 +810,7 @@ func (r *Repository) createIndexFromPacks(ctx context.Context, packsize map[rest // decoding the pack header is usually quite fast, thus we are primarily IO-bound workerCount := int(r.Connections()) // run workers on ch - for i := 0; i < workerCount; i++ { + for range workerCount { wg.Go(worker) } @@ -1114,7 +1114,7 @@ func streamPack(ctx context.Context, beLoad backendLoadFn, loadBlobFn loadBlobFn lastPos := blobs[0].Offset const maxChunkSize = 2 * DefaultPackSize - for i := 0; i < len(blobs); i++ { + for i := range blobs { if blobs[i].Offset < lastPos { // don't wait for streamPackPart to fail return errors.Errorf("overlapping blobs in pack %v", packID) diff --git a/internal/repository/repository_internal_test.go b/internal/repository/repository_internal_test.go index 7f9afa175..2ba8b0f14 100644 --- a/internal/repository/repository_internal_test.go +++ b/internal/repository/repository_internal_test.go @@ -35,7 +35,7 @@ func TestSortCachedPacksFirst(t *testing.T) { r = rand.New(rand.NewSource(1261)) ) - for i := 0; i < len(blobs); i++ { + for i := range len(blobs) { var id restic.ID r.Read(id[:]) blobs[i] = &pack.PackedBlob{Pack: id, Blob: pack.Blob{}} @@ -66,7 +66,7 @@ func BenchmarkSortCachedPacksFirst(b *testing.B) { r = rand.New(rand.NewSource(1261)) ) - for i := 0; i < nblobs; i++ { + for i := range nblobs { var id restic.ID r.Read(id[:]) blobs[i] = &pack.PackedBlob{Pack: id, Blob: pack.Blob{}} @@ -97,7 +97,7 @@ func benchmarkLoadIndex(b *testing.B, version uint) { repo, _, be := TestRepositoryWithVersion(b, version) idx := index.NewIndex() - for i := 0; i < 5000; i++ { + for range 5000 { idx.StorePack(restic.NewRandomID(), pack.Blobs{ { BlobHandle: restic.NewRandomBlobHandle(), @@ -301,8 +301,7 @@ func testStreamPack(t *testing.T, version uint) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() gotBlobs := make(map[restic.ID]int) @@ -380,8 +379,7 @@ func testStreamPack(t *testing.T, version uint) { for _, test := range tests { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() handleBlob := func(blob restic.BlobHandle, buf []byte, err error) error { return err diff --git a/internal/repository/repository_test.go b/internal/repository/repository_test.go index 7df317752..5e7a88948 100644 --- a/internal/repository/repository_test.go +++ b/internal/repository/repository_test.go @@ -391,7 +391,7 @@ func TestRepositoryLoadUnpackedRetryBroken(t *testing.T) { func saveRandomDataBlobs(t testing.TB, repo restic.Repository, num int, sizeMax int) { rnd := rand.New(rand.NewSource(time.Now().UnixNano())) rtest.OK(t, repo.WithBlobUploader(context.TODO(), func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { - for i := 0; i < num; i++ { + for range num { size := rnd.Int() % sizeMax buf := make([]byte, size) @@ -413,7 +413,7 @@ func testRepositoryIncrementalIndex(t *testing.T, version uint) { repo, _, _ := repository.TestRepositoryWithVersion(t, version) // add a few rounds of packs - for j := 0; j < 5; j++ { + for range 5 { // add some packs and write index saveRandomDataBlobs(t, repo, 20, 1<<15) } @@ -532,9 +532,9 @@ func TestSaveBlobAsync(t *testing.T) { err := repo.WithBlobUploader(ctx, func(ctx context.Context, uploader restic.BlobSaverWithAsync) error { var wg sync.WaitGroup wg.Add(numCalls) - for i := 0; i < numCalls; i++ { + for i := range numCalls { // Use unique data for each call - testData := []byte(fmt.Sprintf("test blob data %d", i)) + testData := fmt.Appendf(nil, "test blob data %d", i) uploader.SaveBlobAsync(ctx, restic.DataBlob, testData, restic.ID{}, false, func(newID restic.ID, known bool, size int, err error) { defer wg.Done() @@ -549,7 +549,7 @@ func TestSaveBlobAsync(t *testing.T) { rtest.OK(t, err) for i, result := range results { - testData := []byte(fmt.Sprintf("test blob data %d", i)) + testData := fmt.Appendf(nil, "test blob data %d", i) expectedID := restic.Hash(testData) rtest.Assert(t, result.err == nil, "result %d: unexpected error %v", i, result.err) rtest.Assert(t, result.id.Equal(expectedID), "result %d: expected ID %v, got %v", i, expectedID, result.id) diff --git a/internal/repository/testing.go b/internal/repository/testing.go index dc27be42d..86224bed7 100644 --- a/internal/repository/testing.go +++ b/internal/repository/testing.go @@ -20,7 +20,7 @@ import ( ) type logger interface { - Logf(format string, args ...interface{}) + Logf(format string, args ...any) } var paramsOnce sync.Once diff --git a/internal/restic/blob_set_test.go b/internal/restic/blob_set_test.go index 4e0961aa5..4786dd2d4 100644 --- a/internal/restic/blob_set_test.go +++ b/internal/restic/blob_set_test.go @@ -21,7 +21,7 @@ func TestBlobSetString(t *testing.T) { rtest.Equals(t, "{}", s.String()) var h BlobHandle - for i := 0; i < 100; i++ { + for range 100 { h.Type = DataBlob _, _ = random.Read(h.ID[:]) s.Insert(h) diff --git a/internal/restic/json.go b/internal/restic/json.go index ec64ff153..f4ae97e3e 100644 --- a/internal/restic/json.go +++ b/internal/restic/json.go @@ -10,7 +10,7 @@ import ( // LoadJSONUnpacked decrypts the data and afterwards calls json.Unmarshal on // the item. -func LoadJSONUnpacked(ctx context.Context, repo LoaderUnpacked, t FileType, id ID, item interface{}) (err error) { +func LoadJSONUnpacked(ctx context.Context, repo LoaderUnpacked, t FileType, id ID, item any) (err error) { buf, err := repo.LoadUnpacked(ctx, t, id) if err != nil { return err @@ -21,7 +21,7 @@ func LoadJSONUnpacked(ctx context.Context, repo LoaderUnpacked, t FileType, id I // SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the // backend as type t, without a pack. It returns the storage hash. -func SaveJSONUnpacked[FT FileTypes](ctx context.Context, repo SaverUnpacked[FT], t FT, item interface{}) (ID, error) { +func SaveJSONUnpacked[FT FileTypes](ctx context.Context, repo SaverUnpacked[FT], t FT, item any) (ID, error) { debug.Log("save new blob %v", t) plaintext, err := json.Marshal(item) if err != nil { diff --git a/internal/restic/parallel.go b/internal/restic/parallel.go index f7fffa22e..ffc5c4861 100644 --- a/internal/restic/parallel.go +++ b/internal/restic/parallel.go @@ -44,7 +44,7 @@ func ParallelList(ctx context.Context, r Lister, t FileType, parallelism uint, f } // run workers on ch - for i := uint(0); i < parallelism; i++ { + for range parallelism { wg.Go(worker) } diff --git a/internal/restic/progress.go b/internal/restic/progress.go index e9ce10d58..3e6e3da6a 100644 --- a/internal/restic/progress.go +++ b/internal/restic/progress.go @@ -38,24 +38,24 @@ type Printer interface { // E reports an error. This message is always printed to stderr. // Appends a newline if not present. - E(msg string, args ...interface{}) + E(msg string, args ...any) // S prints a message, this is should only be used for very important messages // that are not errors. The message is even printed if --quiet is specified. // Appends a newline if not present. - S(msg string, args ...interface{}) + S(msg string, args ...any) // PT prints a message if verbosity >= 1 (neither --quiet nor --verbose is specified) // and stdout points to a terminal. // This is used for informational messages. - PT(msg string, args ...interface{}) + PT(msg string, args ...any) // P prints a message if verbosity >= 1 (neither --quiet nor --verbose is specified), // this is used for normal messages which are not errors. Appends a newline if not present. - P(msg string, args ...interface{}) + P(msg string, args ...any) // V prints a message if verbosity >= 2 (equivalent to --verbose), this is used for // verbose messages. Appends a newline if not present. - V(msg string, args ...interface{}) + V(msg string, args ...any) // VV prints a message if verbosity >= 3 (equivalent to --verbose=2), this is used for // debug messages. Appends a newline if not present. - VV(msg string, args ...interface{}) + VV(msg string, args ...any) } // noopPrinter discards all messages. @@ -79,14 +79,14 @@ func (*noopPrinter) NewCounterTerminalOnly(_ string) Counter { return NoopCounter } -func (*noopPrinter) E(_ string, _ ...interface{}) {} +func (*noopPrinter) E(_ string, _ ...any) {} -func (*noopPrinter) S(_ string, _ ...interface{}) {} +func (*noopPrinter) S(_ string, _ ...any) {} -func (*noopPrinter) PT(_ string, _ ...interface{}) {} +func (*noopPrinter) PT(_ string, _ ...any) {} -func (*noopPrinter) P(_ string, _ ...interface{}) {} +func (*noopPrinter) P(_ string, _ ...any) {} -func (*noopPrinter) V(_ string, _ ...interface{}) {} +func (*noopPrinter) V(_ string, _ ...any) {} -func (*noopPrinter) VV(_ string, _ ...interface{}) {} +func (*noopPrinter) VV(_ string, _ ...any) {} diff --git a/internal/restic/zeroprefix_test.go b/internal/restic/zeroprefix_test.go index a21806851..870d9f6d2 100644 --- a/internal/restic/zeroprefix_test.go +++ b/internal/restic/zeroprefix_test.go @@ -18,7 +18,7 @@ func TestZeroPrefixLen(t *testing.T) { test.Equals(t, i, skipped) } // test buffers of various sizes - for i := 0; i < len(buf); i++ { + for i := range len(buf) { skipped := restic.ZeroPrefixLen(buf[i:]) test.Equals(t, 0, skipped) } diff --git a/internal/restorer/filerestorer.go b/internal/restorer/filerestorer.go index 76b2d31c7..0c5c4df44 100644 --- a/internal/restorer/filerestorer.go +++ b/internal/restorer/filerestorer.go @@ -24,8 +24,8 @@ type fileInfo struct { inProgress bool sparse bool size int64 - location string // file on local filesystem relative to restorer basedir - blobs interface{} // blobs of the file + location string // file on local filesystem relative to restorer basedir + blobs any // blobs of the file state *fileState } diff --git a/internal/restorer/filerestorer_test.go b/internal/restorer/filerestorer_test.go index 8526fc608..2b03b70d4 100644 --- a/internal/restorer/filerestorer_test.go +++ b/internal/restorer/filerestorer_test.go @@ -328,7 +328,7 @@ func TestFileRestorerFrequentBlob(t *testing.T) { blobs := []TestBlob{ {"data1-1", "pack1-1"}, } - for i := 0; i < 10000; i++ { + for range 10000 { blobs = append(blobs, TestBlob{"a", "pack1-1"}) } blobs = append(blobs, TestBlob{"end", "pack1-1"}) diff --git a/internal/restorer/fileswriter.go b/internal/restorer/fileswriter.go index 20d458343..ae49e36cc 100644 --- a/internal/restorer/fileswriter.go +++ b/internal/restorer/fileswriter.go @@ -41,7 +41,7 @@ func newFilesWriter(count int, allowRecursiveDelete bool) *filesWriter { // use a large number of buckets to minimize bucket contention // creating a new file can be slow, so make sure that files typically end up in different buckets. buckets := make([]filesWriterBucket, 1024) - for b := 0; b < len(buckets); b++ { + for b := range buckets { buckets[b].files = make(map[string]*partialFile) } diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 98b28f915..cc7e1df9a 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -660,7 +660,7 @@ func (res *Restorer) VerifyFiles(ctx context.Context, dst string, countRestoredF return err }) - for i := 0; i < nVerifyWorkers; i++ { + for range nVerifyWorkers { g.Go(func() (err error) { var buf []byte for job := range work { diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 225c70aa5..fea41f3d2 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -26,7 +26,7 @@ import ( "github.com/restic/restic/internal/ui/progress" ) -type Node interface{} +type Node any type Snapshot struct { Nodes map[string]Node @@ -390,8 +390,7 @@ func TestRestorer(t *testing.T) { return nil } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() countRestoredFiles, err := res.RestoreTo(ctx, tempdir) if err != nil { @@ -488,8 +487,7 @@ func TestRestorerRelative(t *testing.T) { return nil } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() countRestoredFiles, err := res.RestoreTo(ctx, "restore") if err != nil { @@ -743,8 +741,7 @@ func TestRestorerTraverseTree(t *testing.T) { res.SelectFilter = test.Select tempdir := rtest.TempDir(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() // make sure we're creating a new subdir of the tempdir target := filepath.Join(tempdir, "target") @@ -834,8 +831,7 @@ func TestRestorerConsistentTimestampsAndPermissions(t *testing.T) { } tempdir := rtest.TempDir(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _, err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) @@ -872,8 +868,7 @@ func TestVerifyCancel(t *testing.T) { res := NewRestorer(repo, sn, Options{}) tempdir := rtest.TempDir(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() countRestoredFiles, err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) err = os.WriteFile(filepath.Join(tempdir, "foo"), []byte("bar"), 0644) @@ -913,8 +908,7 @@ func TestRestorerSparseFiles(t *testing.T) { res := NewRestorer(repo, sn, Options{Sparse: true}) tempdir := rtest.TempDir(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _, err = res.RestoreTo(ctx, tempdir) rtest.OK(t, err) @@ -1108,7 +1102,7 @@ func TestRestorerOverwriteBehavior(t *testing.T) { func TestRestorerOverwritePartial(t *testing.T) { parts := make([]string, 100) size := 0 - for i := 0; i < len(parts); i++ { + for i := range parts { parts[i] = fmt.Sprint(i) size += len(parts[i]) if i < 8 { @@ -1217,8 +1211,7 @@ func TestRestoreModified(t *testing.T) { repo := repository.TestRepository(t) tempdir := filepath.Join(rtest.TempDir(t), "target") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() for _, snapshot := range snapshots { sn, id := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) @@ -1245,8 +1238,7 @@ func TestRestoreIfChanged(t *testing.T) { repo := repository.TestRepository(t) tempdir := filepath.Join(rtest.TempDir(t), "target") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() sn, id := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) t.Logf("snapshot saved as %v", id.Str()) @@ -1302,8 +1294,7 @@ func TestRestoreDryRun(t *testing.T) { repo := repository.TestRepository(t) tempdir := filepath.Join(rtest.TempDir(t), "target") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() sn, id := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) t.Logf("snapshot saved as %v", id.Str()) @@ -1326,8 +1317,7 @@ func TestRestoreDryRunDelete(t *testing.T) { repo := repository.TestRepository(t) tempdir := filepath.Join(rtest.TempDir(t), "target") tempfile := filepath.Join(tempdir, "existing") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() rtest.OK(t, os.Mkdir(tempdir, 0o755)) f, err := os.Create(tempfile) @@ -1452,8 +1442,7 @@ func TestRestoreDelete(t *testing.T) { for _, test := range tests { t.Run("", func(t *testing.T) { res := NewRestorer(repo, sn, Options{}) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _, err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) @@ -1490,8 +1479,7 @@ func TestRestoreToFile(t *testing.T) { // create a file in the place of the target directory rtest.OK(t, os.WriteFile(tempdir, []byte{}, 0o700)) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() sn, _ := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) res := NewRestorer(repo, sn, Options{}) @@ -1503,7 +1491,7 @@ func TestRestorerLongPath(t *testing.T) { tmp := t.TempDir() longPath := tmp - for i := 0; i < 20; i++ { + for range 20 { longPath = filepath.Join(longPath, "aaaaaaaaaaaaaaaaaaaa") } @@ -1524,8 +1512,7 @@ func TestRestorerLongPath(t *testing.T) { rtest.OK(t, err) res := NewRestorer(repo, sn, Options{}) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() countRestoredFiles, err := res.RestoreTo(ctx, tmp) rtest.OK(t, err) diff --git a/internal/restorer/restorer_unix_test.go b/internal/restorer/restorer_unix_test.go index 6b1388af4..641b89aaf 100644 --- a/internal/restorer/restorer_unix_test.go +++ b/internal/restorer/restorer_unix_test.go @@ -32,8 +32,7 @@ func TestRestorerRestoreEmptyHardlinkedFields(t *testing.T) { res := NewRestorer(repo, sn, Options{}) tempdir := rtest.TempDir(t) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() _, err := res.RestoreTo(ctx, tempdir) rtest.OK(t, err) @@ -115,8 +114,7 @@ func TestRestorePermissions(t *testing.T) { repo := repository.TestRepository(t) tempdir := filepath.Join(rtest.TempDir(t), "target") - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() sn, id := saveSnapshot(t, repo, snapshot, noopGetGenericAttributes) t.Logf("snapshot saved as %v", id.Str()) diff --git a/internal/selfupdate/download.go b/internal/selfupdate/download.go index 00721af80..11c62d78d 100644 --- a/internal/selfupdate/download.go +++ b/internal/selfupdate/download.go @@ -39,7 +39,7 @@ func findHash(buf []byte, filename string) (hash []byte, err error) { return nil, fmt.Errorf("hash for file %v not found", filename) } -func extractToFile(buf []byte, filename, target string, printf func(string, ...interface{})) error { +func extractToFile(buf []byte, filename, target string, printf func(string, ...any)) error { var rd io.Reader = bytes.NewReader(buf) switch filepath.Ext(filename) { case ".bz2": @@ -112,9 +112,9 @@ func extractToFile(buf []byte, filename, target string, printf func(string, ...i // DownloadLatestStableRelease downloads the latest stable released version of // restic and saves it to target. It returns the version string for the newest // version. The function printf is used to print progress information. -func DownloadLatestStableRelease(ctx context.Context, target, currentVersion string, printf func(string, ...interface{})) (version string, err error) { +func DownloadLatestStableRelease(ctx context.Context, target, currentVersion string, printf func(string, ...any)) (version string, err error) { if printf == nil { - printf = func(string, ...interface{}) {} + printf = func(string, ...any) {} } printf("find latest release of restic at GitHub\n") diff --git a/internal/selfupdate/download_test.go b/internal/selfupdate/download_test.go index 00160eef2..acbae0465 100644 --- a/internal/selfupdate/download_test.go +++ b/internal/selfupdate/download_test.go @@ -11,7 +11,7 @@ import ( ) func TestExtractToFileZip(t *testing.T) { - printf := func(string, ...interface{}) {} + printf := func(string, ...any) {} dir := t.TempDir() ext := "zip" @@ -30,7 +30,7 @@ func TestExtractToFileZip(t *testing.T) { rtest.OK(t, zw.Close()) // run twice to test creating a new file and overwriting - for i := 0; i < 2; i++ { + for range 2 { outfn := filepath.Join(dir, ext+"-out") rtest.OK(t, extractToFile(archive.Bytes(), "src."+ext, outfn, printf)) diff --git a/internal/selfupdate/github.go b/internal/selfupdate/github.go index 8cb825b7b..eceaf1cfe 100644 --- a/internal/selfupdate/github.go +++ b/internal/selfupdate/github.go @@ -156,7 +156,7 @@ func getGithubData(ctx context.Context, url string) ([]byte, error) { return buf, nil } -func getGithubDataFile(ctx context.Context, assets []Asset, suffix string, printf func(string, ...interface{})) (filename string, data []byte, err error) { +func getGithubDataFile(ctx context.Context, assets []Asset, suffix string, printf func(string, ...any)) (filename string, data []byte, err error) { var url string for _, a := range assets { if strings.HasSuffix(a.Name, suffix) { diff --git a/internal/test/helpers.go b/internal/test/helpers.go index 48fbf1259..019c5cb6c 100644 --- a/internal/test/helpers.go +++ b/internal/test/helpers.go @@ -16,7 +16,7 @@ import ( ) // Assert fails the test if the condition is false. -func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) { +func Assert(tb testing.TB, condition bool, msg string, v ...any) { tb.Helper() if !condition { tb.Fatalf("\033[31m"+msg+"\033[39m\n\n", v...) @@ -56,7 +56,7 @@ func Equals[T any](tb testing.TB, exp, act T, msgs ...string) { if length == 1 { msgString = msgs[0] } else if length > 1 { - args := make([]interface{}, length-1) + args := make([]any, length-1) for i, msg := range msgs[1:] { args[i] = msg } diff --git a/internal/test/vars.go b/internal/test/vars.go index f3c740d46..2d2e25905 100644 --- a/internal/test/vars.go +++ b/internal/test/vars.go @@ -46,7 +46,7 @@ func getBoolVar(name string, defaultValue bool) bool { // names that must be run. If name is in this list, the test is marked as // failed. func SkipDisallowed(t testing.TB, name string) { - for _, s := range strings.Split(testIntegrationDisallowSkip, ",") { + for s := range strings.SplitSeq(testIntegrationDisallowSkip, ",") { if s == name { t.Fatalf("test %v is in list of tests that need to run ($RESTIC_TEST_DISALLOW_SKIP)", name) } diff --git a/internal/ui/backup/json.go b/internal/ui/backup/json.go index 9c1b51599..98de622b7 100644 --- a/internal/ui/backup/json.go +++ b/internal/ui/backup/json.go @@ -30,11 +30,11 @@ func NewJSONProgress(term ui.Terminal, verbosity uint) ProgressPrinter { } } -func (b *jsonProgress) print(status interface{}) { +func (b *jsonProgress) print(status any) { b.term.Print(ui.ToJSONString(status)) } -func (b *jsonProgress) error(status interface{}) { +func (b *jsonProgress) error(status any) { b.term.Error(ui.ToJSONString(status)) } diff --git a/internal/ui/format.go b/internal/ui/format.go index 36dfa8147..bc39b4ae0 100644 --- a/internal/ui/format.go +++ b/internal/ui/format.go @@ -100,7 +100,7 @@ func ParseBytes(s string) (int64, error) { return value, nil } -func ToJSONString(status interface{}) string { +func ToJSONString(status any) string { buf := new(bytes.Buffer) err := json.NewEncoder(buf).Encode(status) if err != nil { diff --git a/internal/ui/progress/counter_test.go b/internal/ui/progress/counter_test.go index 4c591e534..5db1eaa9e 100644 --- a/internal/ui/progress/counter_test.go +++ b/internal/ui/progress/counter_test.go @@ -40,7 +40,7 @@ func TestCounter(t *testing.T) { done := make(chan struct{}) go func() { defer close(done) - for i := 0; i < N; i++ { + for range N { time.Sleep(time.Millisecond) c.Add(1) } diff --git a/internal/ui/progress/terminal.go b/internal/ui/progress/terminal.go index 7f5428968..36c36b22a 100644 --- a/internal/ui/progress/terminal.go +++ b/internal/ui/progress/terminal.go @@ -66,33 +66,33 @@ func (t *terminalPrinter) NewCounterTerminalOnly(description string) restic.Coun return newProgressMax(t.v > 0 && t.term.OutputIsTerminal(), 0, description, t.term) } -func (t *terminalPrinter) E(msg string, args ...interface{}) { +func (t *terminalPrinter) E(msg string, args ...any) { t.term.Error(fmt.Sprintf(msg, args...)) } -func (t *terminalPrinter) S(msg string, args ...interface{}) { +func (t *terminalPrinter) S(msg string, args ...any) { t.term.Print(fmt.Sprintf(msg, args...)) } -func (t *terminalPrinter) PT(msg string, args ...interface{}) { +func (t *terminalPrinter) PT(msg string, args ...any) { if t.term.OutputIsTerminal() && t.v >= 1 { t.term.Print(fmt.Sprintf(msg, args...)) } } -func (t *terminalPrinter) P(msg string, args ...interface{}) { +func (t *terminalPrinter) P(msg string, args ...any) { if t.v >= 1 { t.term.Print(fmt.Sprintf(msg, args...)) } } -func (t *terminalPrinter) V(msg string, args ...interface{}) { +func (t *terminalPrinter) V(msg string, args ...any) { if t.v >= 2 { t.term.Print(fmt.Sprintf(msg, args...)) } } -func (t *terminalPrinter) VV(msg string, args ...interface{}) { +func (t *terminalPrinter) VV(msg string, args ...any) { if t.v >= 3 { t.term.Print(fmt.Sprintf(msg, args...)) } diff --git a/internal/ui/restore/json.go b/internal/ui/restore/json.go index 4ce66fcbf..a4ae8829f 100644 --- a/internal/ui/restore/json.go +++ b/internal/ui/restore/json.go @@ -24,11 +24,11 @@ func NewJSONProgress(terminal ui.Terminal, verbosity uint) ProgressPrinter { } } -func (t *jsonPrinter) print(status interface{}) { +func (t *jsonPrinter) print(status any) { t.terminal.Print(ui.ToJSONString(status)) } -func (t *jsonPrinter) error(status interface{}) { +func (t *jsonPrinter) error(status any) { t.terminal.Error(ui.ToJSONString(status)) } diff --git a/internal/ui/table/table.go b/internal/ui/table/table.go index 2aff8cbb1..80ad1eba4 100644 --- a/internal/ui/table/table.go +++ b/internal/ui/table/table.go @@ -13,7 +13,7 @@ import ( type Table struct { columns []string templates []*template.Template - data []interface{} + data []any footer []string CellSeparator string @@ -58,7 +58,7 @@ func (t *Table) AddColumn(header, format string) { } // AddRow adds a new row to the table, which is filled with data. -func (t *Table) AddRow(data interface{}) { +func (t *Table) AddRow(data any) { t.data = append(t.data, data) } @@ -80,7 +80,7 @@ func printLine(w io.Writer, print func(io.Writer, string) error, sep string, dat } for i := 0; i < maxLines; i++ { - var s string + var s strings.Builder for fieldNum, lines := range fields { var v string @@ -99,10 +99,10 @@ func printLine(w io.Writer, print func(io.Writer, string) error, sep string, dat v = sep + v } - s += v + s.WriteString(v) } - err := print(w, strings.TrimRight(s, " ")) + err := print(w, strings.TrimRight(s.String(), " ")) if err != nil { return err } @@ -139,7 +139,7 @@ func (t *Table) Write(w io.Writer) error { // find max width for each cell columnWidths := make([]int, columns) for i, desc := range t.columns { - for _, line := range strings.Split(desc, "\n") { + for line := range strings.SplitSeq(desc, "\n") { width := ui.DisplayWidth(line) if columnWidths[i] < width { columnWidths[i] = width @@ -148,7 +148,7 @@ func (t *Table) Write(w io.Writer) error { } for _, line := range lines { for i, content := range line { - for _, l := range strings.Split(content, "\n") { + for l := range strings.SplitSeq(content, "\n") { width := ui.DisplayWidth(l) if columnWidths[i] < width { columnWidths[i] = width diff --git a/internal/ui/termstatus/status.go b/internal/ui/termstatus/status.go index 892e4c712..b0b831c7f 100644 --- a/internal/ui/termstatus/status.go +++ b/internal/ui/termstatus/status.go @@ -80,11 +80,9 @@ func Setup(stdin io.ReadCloser, stdout, stderr io.Writer, quiet bool) (ui.Termin cancelCtx, cancel := context.WithCancel(context.Background()) term := new(stdin, stdout, stderr, quiet) - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { term.Run(cancelCtx) - }() + }) return term, func() { if term.outputWriter != nil { diff --git a/internal/walker/rewriter_test.go b/internal/walker/rewriter_test.go index 7cb34c9d0..ca7f5deef 100644 --- a/internal/walker/rewriter_test.go +++ b/internal/walker/rewriter_test.go @@ -1,7 +1,6 @@ package walker import ( - "context" "slices" "testing" @@ -253,8 +252,7 @@ func TestRewriter(t *testing.T) { expRepo, expRoot := BuildTreeMap(test.newTree) modrepo := data.TestWritableTreeMap{TestTreeMap: repo} - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() rewriter, last := test.check(t) newRoot, err := rewriter.RewriteTree(ctx, modrepo, modrepo, "/", root) @@ -294,8 +292,7 @@ func TestSnapshotSizeQuery(t *testing.T) { expRepo, expRoot := BuildTreeMap(newTree) modrepo := data.TestWritableTreeMap{TestTreeMap: repo} - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() rewriteNode := func(node *data.Node, path string) *data.Node { if path == "/bar" { @@ -383,8 +380,7 @@ func TestRewriterKeepEmptyDirectory(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx := t.Context() repo, root := BuildTreeMap(TestTree{"empty": TestTree{}}) modrepo := data.TestWritableTreeMap{TestTreeMap: repo} @@ -403,8 +399,7 @@ func TestRewriterFailOnUnknownFields(t *testing.T) { id := restic.Hash(node) tm.TestTreeMap[id] = node - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() rewriter := NewTreeRewriter(RewriteOpts{ RewriteNode: func(node *data.Node, path string) *data.Node { @@ -435,8 +430,7 @@ func TestRewriterTreeLoadError(t *testing.T) { tm := data.TestWritableTreeMap{TestTreeMap: data.TestTreeMap{}} id := restic.NewRandomID() - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() // also check that load error by default cause the operation to fail rewriter := NewTreeRewriter(RewriteOpts{}) diff --git a/internal/walker/walker_test.go b/internal/walker/walker_test.go index fad95476d..d0c5c59b0 100644 --- a/internal/walker/walker_test.go +++ b/internal/walker/walker_test.go @@ -1,7 +1,6 @@ package walker import ( - "context" "fmt" "sort" "testing" @@ -12,7 +11,7 @@ import ( ) // TestTree is used to construct a list of trees for testing the walker. -type TestTree map[string]interface{} +type TestTree map[string]any // TestFile is used to test the walker. type TestFile struct { @@ -461,8 +460,7 @@ func TestWalker(t *testing.T) { repo, root := BuildTreeMap(test.tree) for _, check := range test.checks { t.Run("", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.TODO()) - defer cancel() + ctx := t.Context() fn, leaveDir, last := check(t) err := Walk(ctx, repo, root, WalkVisitor{