From 7db061ee71d13cd2404b0968abfaa3b527db45c1 Mon Sep 17 00:00:00 2001 From: Julio Lopez <1953782+julio-lopez@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:42:12 -0800 Subject: [PATCH] build(deps): Go 1.25 (#4987) Upgrade to Go 1.25 Leverage `WaitGroup.Go` in Go 1.25 --- .github/workflows/lint.yml | 2 +- cli/command_benchmark.go | 8 ++----- cli/command_content_verify.go | 7 ++---- cli/command_index_inspect.go | 8 ++----- go.mod | 4 ++-- .../cache/content_cache_concurrency_test.go | 24 +++++-------------- internal/logfile/logfile.go | 10 +------- internal/repodiag/blob_writer.go | 7 ++---- internal/scheduler/scheduler.go | 8 ++----- internal/sleepable/sleepable_timer_test.go | 8 +------ internal/workshare/workshare_pool.go | 8 ++----- repo/blob/rclone/rclone_storage_test.go | 8 ++----- repo/blob/throttling/throttler_test.go | 8 ++----- .../throttling/throttling_semaphore_test.go | 8 ++----- repo/content/content_manager_iterate.go | 8 ++----- repo/content/content_manager_test.go | 16 ++++--------- repo/content/content_prefetch.go | 8 ++----- repo/content/index/index_builder.go | 8 ++----- repo/maintenance/content_rewrite.go | 8 ++----- site/.go-version | 2 +- site/go.mod | 2 +- snapshot/snapshotfs/snapshot_verifier.go | 8 ++----- snapshot/upload/upload_estimator.go | 7 ++---- tests/recovery/recovery_test/recovery_test.go | 7 ++---- tests/robustness/pathlock/path_lock_test.go | 15 ++++-------- tests/testenv/cli_test_env.go | 16 ++++--------- 26 files changed, 57 insertions(+), 166 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6b7111e93..0713a6690 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -37,7 +37,7 @@ jobs: uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4 with: cache: false - go-version-input: '1.24.10' + go-version-input: '1.25.4' # An explicit Go version is needed for govulncheck-action since internally # it uses an outdated setup-go@v5.0 action that does not respect the 'toolchain' # directive in the 'go.mod' file. diff --git a/cli/command_benchmark.go b/cli/command_benchmark.go index 48c956b01..447926b59 100644 --- a/cli/command_benchmark.go +++ b/cli/command_benchmark.go @@ -58,13 +58,9 @@ func runInParallel[A, T any](args []A, run func(arg A) T) T { var wg sync.WaitGroup for _, arg := range args[1:] { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { run(arg) - }() + }) } // run one on the main goroutine and N-1 in parallel. diff --git a/cli/command_content_verify.go b/cli/command_content_verify.go index d820d2d41..f51af3df3 100644 --- a/cli/command_content_verify.go +++ b/cli/command_content_verify.go @@ -51,13 +51,10 @@ func (c *commandContentVerify) run(ctx context.Context, rep repo.DirectRepositor }() // start a goroutine that will populate totalCount - wg.Add(1) - - go func() { - defer wg.Done() + wg.Go(func() { c.getTotalContentCount(subctx, rep, &totalCount) - }() + }) rep.DisableIndexRefresh() diff --git a/cli/command_index_inspect.go b/cli/command_index_inspect.go index 2b53d322c..48edd5550 100644 --- a/cli/command_index_inspect.go +++ b/cli/command_index_inspect.go @@ -43,13 +43,9 @@ func (c *commandIndexInspect) run(ctx context.Context, rep repo.DirectRepository var wg sync.WaitGroup - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { c.dumpIndexBlobEntries(output) - }() + }) err := c.runWithOutput(ctx, rep, output) close(output) diff --git a/go.mod b/go.mod index 2435de945..e94d31cd6 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/kopia/kopia -go 1.24.0 +go 1.25 -toolchain go1.24.10 +toolchain go1.25.4 require ( cloud.google.com/go/storage v1.57.1 diff --git a/internal/cache/content_cache_concurrency_test.go b/internal/cache/content_cache_concurrency_test.go index bdca2e484..d144f5d9b 100644 --- a/internal/cache/content_cache_concurrency_test.go +++ b/internal/cache/content_cache_concurrency_test.go @@ -178,16 +178,12 @@ func testGetContentForDifferentContentIDsExecutesInParallel(t *testing.T, newCac var wg sync.WaitGroup for i := range 20 { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { var tmp gather.WriteBuffer defer tmp.Close() dataCache.GetContent(ctx, fmt.Sprintf("c%v", i), "blob1", int64(i), 1, &tmp) - }() + }) } wg.Wait() @@ -226,16 +222,12 @@ func testGetContentForDifferentBlobsExecutesInParallel(t *testing.T, newCache ne var wg sync.WaitGroup for i := range 20 { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { var tmp gather.WriteBuffer defer tmp.Close() dataCache.GetContent(ctx, fmt.Sprintf("c%v", i), blob.ID(fmt.Sprintf("blob%v", i)), int64(i), 1, &tmp) - }() + }) } wg.Wait() @@ -273,16 +265,12 @@ func testGetContentRaceFetchesOnce(t *testing.T, newCache newContentCacheFunc) { var wg sync.WaitGroup for range 20 { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { var tmp gather.WriteBuffer defer tmp.Close() dataCache.GetContent(ctx, "c1", "blob1", 0, 1, &tmp) - }() + }) } wg.Wait() diff --git a/internal/logfile/logfile.go b/internal/logfile/logfile.go index 9974c7119..51f310e1b 100644 --- a/internal/logfile/logfile.go +++ b/internal/logfile/logfile.go @@ -239,15 +239,7 @@ func (c *loggingFlags) setupLogFileBasedLogger(now time.Time, subdir, suffix, lo logFileBaseName: logFileBaseName, symlinkName: symlinkName, maxSegmentSize: c.logFileMaxSegmentSize, - startSweep: func() { - sweepLogWG.Add(1) - - go func() { - defer sweepLogWG.Done() - - doSweep() - }() - }, + startSweep: func() { sweepLogWG.Go(doSweep) }, } if c.waitForLogSweep { diff --git a/internal/repodiag/blob_writer.go b/internal/repodiag/blob_writer.go index 3948b8b37..714d85807 100644 --- a/internal/repodiag/blob_writer.go +++ b/internal/repodiag/blob_writer.go @@ -37,10 +37,7 @@ func (w *BlobWriter) EncryptAndWriteBlobAsync(ctx context.Context, prefix blob.I b := encrypted.Bytes() - w.wg.Add(1) - - go func() { - defer w.wg.Done() + w.wg.Go(func() { defer encrypted.Close() defer closeFunc() @@ -49,7 +46,7 @@ func (w *BlobWriter) EncryptAndWriteBlobAsync(ctx context.Context, prefix blob.I log(ctx).Warnf("unable to write diagnostics blob: %v", err) return } - }() + }) } // Wait waits for all the writes to complete. diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go index c5a54984b..5da05aeb9 100644 --- a/internal/scheduler/scheduler.go +++ b/internal/scheduler/scheduler.go @@ -61,13 +61,9 @@ func Start(ctx context.Context, getItems GetItemsFunc, opts Options) *Scheduler Debug: opts.Debug, } - s.wg.Add(1) - - go func() { - defer s.wg.Done() - + s.wg.Go(func() { s.run(context.WithoutCancel(ctx)) - }() + }) return s } diff --git a/internal/sleepable/sleepable_timer_test.go b/internal/sleepable/sleepable_timer_test.go index bbafdf1f2..a4e163794 100644 --- a/internal/sleepable/sleepable_timer_test.go +++ b/internal/sleepable/sleepable_timer_test.go @@ -130,13 +130,7 @@ func TestTimerConcurrentStop(t *testing.T) { var wg sync.WaitGroup for range 10 { - wg.Add(1) - - go func() { - defer wg.Done() - - timer.Stop() - }() + wg.Go(timer.Stop) } wg.Wait() diff --git a/internal/workshare/workshare_pool.go b/internal/workshare/workshare_pool.go index e3e7fdcd2..5ddd72038 100644 --- a/internal/workshare/workshare_pool.go +++ b/internal/workshare/workshare_pool.go @@ -48,11 +48,7 @@ func NewPool[T any](numWorkers int) *Pool[T] { } for range numWorkers { - w.wg.Add(1) - - go func() { - defer w.wg.Done() - + w.wg.Go(func() { for { select { case it := <-w.work: @@ -66,7 +62,7 @@ func NewPool[T any](numWorkers int) *Pool[T] { return } } - }() + }) } return w diff --git a/repo/blob/rclone/rclone_storage_test.go b/repo/blob/rclone/rclone_storage_test.go index e0e265b53..d9e063694 100644 --- a/repo/blob/rclone/rclone_storage_test.go +++ b/repo/blob/rclone/rclone_storage_test.go @@ -263,15 +263,11 @@ func TestRCloneProviders(t *testing.T) { prefix := uuid.NewString() for i := range 10 { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for j := range 3 { assert.NoError(t, st.PutBlob(ctx, blob.ID(fmt.Sprintf("%v-%v-%v", prefix, i, j)), gather.FromSlice([]byte{1, 2, 3}), blob.PutOptions{})) } - }() + }) } wg.Wait() diff --git a/repo/blob/throttling/throttler_test.go b/repo/blob/throttling/throttler_test.go index 2e26b5e0b..38f5055ec 100644 --- a/repo/blob/throttling/throttler_test.go +++ b/repo/blob/throttling/throttler_test.go @@ -112,15 +112,11 @@ func testRateLimiting(t *testing.T, name string, wantRate float64, worker func(t var wg sync.WaitGroup for range numWorkers { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for clock.Now().Before(deadline) { worker(total) } - }() + }) } wg.Wait() diff --git a/repo/blob/throttling/throttling_semaphore_test.go b/repo/blob/throttling/throttling_semaphore_test.go index ca3cd3563..26389df47 100644 --- a/repo/blob/throttling/throttling_semaphore_test.go +++ b/repo/blob/throttling/throttling_semaphore_test.go @@ -27,11 +27,7 @@ func TestThrottlingSemaphore(t *testing.T) { ) for range 10 { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for range 10 { s.Acquire() @@ -55,7 +51,7 @@ func TestThrottlingSemaphore(t *testing.T) { s.Release() } - }() + }) } wg.Wait() diff --git a/repo/content/content_manager_iterate.go b/repo/content/content_manager_iterate.go index 17ad2a84c..48ef4496f 100644 --- a/repo/content/content_manager_iterate.go +++ b/repo/content/content_manager_iterate.go @@ -68,11 +68,7 @@ func maybeParallelExecutor(parallel int, originalCallback IterateCallback) (Iter // start N workers, each fetching from the shared channel and invoking the provided callback. // cleanup() must be called to for worker completion for range parallel { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for i := range workch { if err := originalCallback(i); err != nil { select { @@ -81,7 +77,7 @@ func maybeParallelExecutor(parallel int, originalCallback IterateCallback) (Iter } } } - }() + }) } return callback, cleanup diff --git a/repo/content/content_manager_test.go b/repo/content/content_manager_test.go index d19f8f74a..f992ea5d8 100644 --- a/repo/content/content_manager_test.go +++ b/repo/content/content_manager_test.go @@ -1045,11 +1045,7 @@ func (s *contentManagerSuite) TestParallelWrites(t *testing.T) { // start numWorkers, each writing random block and recording it for workerID := range numWorkers { - workersWG.Add(1) - - go func() { - defer workersWG.Done() - + workersWG.Go(func() { for !stopWorker.Load() { id := writeContentAndVerify(ctx, t, bm, seededRandomData(rand.Int(), 100)) @@ -1059,7 +1055,7 @@ func (s *contentManagerSuite) TestParallelWrites(t *testing.T) { workerLock.RUnlock() } - }() + }) } flush := func() { @@ -1128,11 +1124,7 @@ func (s *contentManagerSuite) TestFlushResumesWriters(t *testing.T) { var writeWG sync.WaitGroup - writeWG.Add(1) - - go func() { - defer writeWG.Done() - + writeWG.Go(func() { // start a write while flush is ongoing, the write will block on the condition variable <-resumeWrites t.Logf("write started") @@ -1140,7 +1132,7 @@ func (s *contentManagerSuite) TestFlushResumesWriters(t *testing.T) { second = writeContentAndVerify(ctx, t, bm, []byte{3, 4, 5}) t.Logf("write finished") - }() + }) // flush will take 5 seconds, 1 second into that we will start a write bm.Flush(ctx) diff --git a/repo/content/content_prefetch.go b/repo/content/content_prefetch.go index ad471797d..2a60375ea 100644 --- a/repo/content/content_prefetch.go +++ b/repo/content/content_prefetch.go @@ -108,11 +108,7 @@ type work struct { }() for range parallelFetches { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { var tmp gather.WriteBuffer defer tmp.Close() @@ -143,7 +139,7 @@ type work struct { } } } - }() + }) } wg.Wait() diff --git a/repo/content/index/index_builder.go b/repo/content/index/index_builder.go index dde6c45e0..4eec3e312 100644 --- a/repo/content/index/index_builder.go +++ b/repo/content/index/index_builder.go @@ -75,11 +75,7 @@ func (b Builder) sortedContents() []*Info { numWorkers := runtime.NumCPU() for worker := range numWorkers { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for i := range buckets { if i%numWorkers == worker { buck := buckets[i] @@ -89,7 +85,7 @@ func (b Builder) sortedContents() []*Info { }) } } - }() + }) } wg.Wait() diff --git a/repo/maintenance/content_rewrite.go b/repo/maintenance/content_rewrite.go index c97d9c3ba..c94ad1117 100644 --- a/repo/maintenance/content_rewrite.go +++ b/repo/maintenance/content_rewrite.go @@ -75,11 +75,7 @@ func RewriteContents(ctx context.Context, rep repo.DirectRepositoryWriter, opt * var wg sync.WaitGroup for range opt.Parallel { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { for c := range cnt { if c.err != nil { failedCount.Add(1) @@ -136,7 +132,7 @@ func RewriteContents(ctx context.Context, rep repo.DirectRepositoryWriter, opt * rewritten.Add(int64(c.PackedLength)) } } - }() + }) } wg.Wait() diff --git a/site/.go-version b/site/.go-version index a4219c13d..fc4bf71be 100644 --- a/site/.go-version +++ b/site/.go-version @@ -1 +1 @@ -1.24.x +1.25.x diff --git a/site/go.mod b/site/go.mod index 095b68d9e..ff7a94a60 100644 --- a/site/go.mod +++ b/site/go.mod @@ -1,6 +1,6 @@ module github.com/kopia/kopia/site -go 1.24 +go 1.25 require ( github.com/google/docsy v0.7.0 // indirect diff --git a/snapshot/snapshotfs/snapshot_verifier.go b/snapshot/snapshotfs/snapshot_verifier.go index 4a6a9e171..ab9c9968b 100644 --- a/snapshot/snapshotfs/snapshot_verifier.go +++ b/snapshot/snapshotfs/snapshot_verifier.go @@ -275,11 +275,7 @@ func (v *Verifier) InParallel(ctx context.Context, enqueue func(tw *TreeWalker) v.fileWorkQueue = make(chan verifyFileWorkItem, v.opts.FileQueueLength) for range v.opts.Parallelism { - v.workersWG.Add(1) - - go func() { - defer v.workersWG.Done() - + v.workersWG.Go(func() { for wi := range v.fileWorkQueue { if tw.TooManyErrors() { continue @@ -289,7 +285,7 @@ func (v *Verifier) InParallel(ctx context.Context, enqueue func(tw *TreeWalker) tw.ReportError(ctx, wi.entryPath, err) } } - }() + }) } err := enqueue(tw) diff --git a/snapshot/upload/upload_estimator.go b/snapshot/upload/upload_estimator.go index 1ebcfd6d7..e8985be14 100644 --- a/snapshot/upload/upload_estimator.go +++ b/snapshot/upload/upload_estimator.go @@ -105,11 +105,8 @@ func (e *estimator) StartEstimation(ctx context.Context, cb EstimationDoneFn) { scanCtx, cancelScan := context.WithCancel(ctx) e.cancelCtx = cancelScan - e.scanWG.Add(1) - - go func() { - defer e.scanWG.Done() + e.scanWG.Go(func() { logger := estimateLog(ctx) var filesCount, totalFileSize int64 @@ -147,7 +144,7 @@ func (e *estimator) StartEstimation(ctx context.Context, cb EstimationDoneFn) { } cb(filesCount, totalFileSize) - }() + }) } func (e *estimator) Wait() { diff --git a/tests/recovery/recovery_test/recovery_test.go b/tests/recovery/recovery_test/recovery_test.go index 0f646bf26..8897aeee8 100644 --- a/tests/recovery/recovery_test/recovery_test.go +++ b/tests/recovery/recovery_test/recovery_test.go @@ -254,11 +254,8 @@ func killOnCondition(t *testing.T, cmd *exec.Cmd) { var wg sync.WaitGroup // Add a WaitGroup counter for the first goroutine - wg.Add(1) - - go func() { - defer wg.Done() + wg.Go(func() { // Create a scanner to read from stderrPipe scanner := bufio.NewScanner(stderrPipe) scanner.Split(bufio.ScanLines) @@ -275,7 +272,7 @@ func killOnCondition(t *testing.T, cmd *exec.Cmd) { break } } - }() + }) // Start the command err = cmd.Start() diff --git a/tests/robustness/pathlock/path_lock_test.go b/tests/robustness/pathlock/path_lock_test.go index 7db7aed2b..9c810408f 100644 --- a/tests/robustness/pathlock/path_lock_test.go +++ b/tests/robustness/pathlock/path_lock_test.go @@ -116,11 +116,8 @@ func TestPathLockBasic(t *testing.T) { var path2Err error wg := new(sync.WaitGroup) - wg.Add(1) - - go func() { - defer wg.Done() + wg.Go(func() { lock2, err := pl.Lock(tc.path2) if err != nil { path2Err = err @@ -128,7 +125,7 @@ func TestPathLockBasic(t *testing.T) { } lock2.Unlock() - }() + }) // Wait until the internal atomic counter increments. // That will only happen once the Lock call to path2 executes @@ -281,11 +278,7 @@ func TestPathLockRace(t *testing.T) { numGoroutines := 100 for range numGoroutines { - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { // Pick from three different path values that should all be // covered by the same lock. path := "/some/path/a/b/c" @@ -305,7 +298,7 @@ func TestPathLockRace(t *testing.T) { counter++ lock.Unlock() - }() + }) } wg.Wait() diff --git a/tests/testenv/cli_test_env.go b/tests/testenv/cli_test_env.go index a83036711..0d4c19664 100644 --- a/tests/testenv/cli_test_env.go +++ b/tests/testenv/cli_test_env.go @@ -305,11 +305,7 @@ func (e *CLITest) Run(tb testing.TB, expectedError bool, args ...string) (stdout var wg sync.WaitGroup - wg.Add(1) - - go func() { - defer wg.Done() - + wg.Go(func() { scanner := bufio.NewScanner(stdoutReader) for scanner.Scan() { if logOutput { @@ -318,13 +314,9 @@ func (e *CLITest) Run(tb testing.TB, expectedError bool, args ...string) (stdout stdout = append(stdout, scanner.Text()) } - }() - - wg.Add(1) - - go func() { - defer wg.Done() + }) + wg.Go(func() { scanner := bufio.NewScanner(stderrReader) for scanner.Scan() { if logOutput { @@ -333,7 +325,7 @@ func (e *CLITest) Run(tb testing.TB, expectedError bool, args ...string) (stdout stderr = append(stderr, scanner.Text()) } - }() + }) wg.Wait()