diff --git a/backend/azureblob/azureblob.go b/backend/azureblob/azureblob.go index 52d9fcd38..87030ffcf 100644 --- a/backend/azureblob/azureblob.go +++ b/backend/azureblob/azureblob.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "io" + "maps" "net/http" "path" "slices" @@ -729,8 +730,8 @@ func parseXMsTags(s string) (map[string]string, error) { return map[string]string{}, nil } out := make(map[string]string) - parts := strings.Split(s, ",") - for _, p := range parts { + parts := strings.SplitSeq(s, ",") + for p := range parts { p = strings.TrimSpace(p) if p == "" { continue @@ -893,9 +894,7 @@ func assembleCopyParams(ctx context.Context, f *Fs, src fs.Object, srcProps *blo if meta == nil { meta = make(map[string]*string, len(userMeta)) } - for k, v := range userMeta { - meta[k] = v - } + maps.Copy(meta, userMeta) } // Apply tags if any if len(mappedTags) > 0 { @@ -992,9 +991,7 @@ func (o *Object) applyMappedMetadata(ctx context.Context, src fs.ObjectInfo, ui if o.tags == nil { o.tags = make(map[string]string, len(tags)) } - for k, v := range tags { - o.tags[k] = v - } + maps.Copy(o.tags, tags) } if mappedModTime != nil { @@ -1859,9 +1856,7 @@ func (f *Fs) copySinglepart(ctx context.Context, remote, dstContainer, dstPath s // Apply tags and post-copy headers only when mapping requested changes if len(tags) > 0 { options.BlobTags = make(map[string]string, len(tags)) - for k, v := range tags { - options.BlobTags[k] = v - } + maps.Copy(options.BlobTags, tags) } if hadMapping { // Only set metadata explicitly when mapping was requested; otherwise @@ -2062,9 +2057,7 @@ func (o *Object) Metadata(ctx context.Context) (fs.Metadata, error) { // Merge user metadata (already lower-cased keys) metadataMu.Lock() - for k, v := range o.meta { - m[k] = v - } + maps.Copy(m, o.meta) metadataMu.Unlock() return m, nil diff --git a/backend/b2/api/types.go b/backend/b2/api/types.go index 13982dfc9..ae3a0a60f 100644 --- a/backend/b2/api/types.go +++ b/backend/b2/api/types.go @@ -287,13 +287,13 @@ type StartLargeFileRequest struct { // StartLargeFileResponse is the response to StartLargeFileRequest type StartLargeFileResponse struct { - ID string `json:"fileId"` // The unique identifier for this version of this file. Used with b2_get_file_info, b2_download_file_by_id, and b2_delete_file_version. - Name string `json:"fileName"` // The name of this file, which can be used with b2_download_file_by_name. - AccountID string `json:"accountId"` // The identifier for the account. - BucketID string `json:"bucketId"` // The unique ID of the bucket. - ContentType string `json:"contentType"` // The MIME type of the file. - Info map[string]string `json:"fileInfo"` // The custom information that was uploaded with the file. This is a JSON object, holding the name/value pairs that were uploaded with the file. - UploadTimestamp Timestamp `json:"uploadTimestamp,omitempty"` // This is a UTC time when this file was uploaded. + ID string `json:"fileId"` // The unique identifier for this version of this file. Used with b2_get_file_info, b2_download_file_by_id, and b2_delete_file_version. + Name string `json:"fileName"` // The name of this file, which can be used with b2_download_file_by_name. + AccountID string `json:"accountId"` // The identifier for the account. + BucketID string `json:"bucketId"` // The unique ID of the bucket. + ContentType string `json:"contentType"` // The MIME type of the file. + Info map[string]string `json:"fileInfo"` // The custom information that was uploaded with the file. This is a JSON object, holding the name/value pairs that were uploaded with the file. + UploadTimestamp Timestamp `json:"uploadTimestamp"` // This is a UTC time when this file was uploaded. } // GetUploadPartURLRequest is passed to b2_get_upload_part_url diff --git a/backend/googlephotos/api/types.go b/backend/googlephotos/api/types.go index f49195685..0e598932c 100644 --- a/backend/googlephotos/api/types.go +++ b/backend/googlephotos/api/types.go @@ -116,8 +116,8 @@ type Date struct { type DateFilter struct { Dates []Date `json:"dates,omitempty"` Ranges []struct { - StartDate Date `json:"startDate,omitempty"` - EndDate Date `json:"endDate,omitempty"` + StartDate Date `json:"startDate"` + EndDate Date `json:"endDate"` } `json:"ranges,omitempty"` } diff --git a/backend/http/http.go b/backend/http/http.go index 253bc04ab..ae2c50539 100644 --- a/backend/http/http.go +++ b/backend/http/http.go @@ -583,9 +583,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e entriesMu.Unlock() } for range checkers { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for remote := range in { file := &Object{ fs: f, @@ -601,7 +599,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e fs.Debugf(remote, "skipping because of error: %v", err) } } - }() + }) } for _, name := range names { isDir := name[len(name)-1] == '/' diff --git a/backend/iclouddrive/api/drive.go b/backend/iclouddrive/api/drive.go index a0856b262..fa98362f4 100644 --- a/backend/iclouddrive/api/drive.go +++ b/backend/iclouddrive/api/drive.go @@ -599,7 +599,7 @@ type UpdateFileInfo struct { Signature string `json:"signature,omitempty"` Size int64 `json:"size,omitempty"` WrappingKey string `json:"wrapping_key,omitempty"` - } `json:"data,omitempty"` + } `json:"data"` DocumentID string `json:"document_id"` FileFlags FileFlags `json:"file_flags"` Mtime int64 `json:"mtime"` @@ -849,10 +849,10 @@ type DriveItem struct { NumberOfItems int64 `json:"numberOfItems"` Status string `json:"status"` Extension string `json:"extension,omitempty"` - DateModified time.Time `json:"dateModified,omitempty"` - DateChanged time.Time `json:"dateChanged,omitempty"` + DateModified time.Time `json:"dateModified"` + DateChanged time.Time `json:"dateChanged"` Size int64 `json:"size,omitempty"` - LastOpenTime time.Time `json:"lastOpenTime,omitempty"` + LastOpenTime time.Time `json:"lastOpenTime"` Urls struct { URLDownload string `json:"url_download"` } `json:"urls"` diff --git a/backend/local/remove_test.go b/backend/local/remove_test.go index a80075000..631f2dda0 100644 --- a/backend/local/remove_test.go +++ b/backend/local/remove_test.go @@ -33,12 +33,10 @@ func TestRemove(t *testing.T) { assert.True(t, exists()) // close the file in the background var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { time.Sleep(250 * time.Millisecond) require.NoError(t, fd.Close()) - }() + }) // delete the open file err = remove(name) require.NoError(t, err) diff --git a/backend/local/remove_windows.go b/backend/local/remove_windows.go index 70d65b63e..4a4eb8b7c 100644 --- a/backend/local/remove_windows.go +++ b/backend/local/remove_windows.go @@ -14,7 +14,7 @@ import ( func remove(name string) (err error) { const maxTries = 10 var sleepTime = 1 * time.Millisecond - for i := 0; i < maxTries; i++ { + for i := range maxTries { err = os.Remove(name) if err == nil { break diff --git a/backend/mailru/api/m1.go b/backend/mailru/api/m1.go index e4babfecc..2393a4c8b 100644 --- a/backend/mailru/api/m1.go +++ b/backend/mailru/api/m1.go @@ -112,7 +112,7 @@ type ListItem struct { Count struct { Folders int `json:"folders"` Files int `json:"files"` - } `json:"count,omitempty"` + } `json:"count"` Kind string `json:"kind"` Type string `json:"type"` Name string `json:"name"` @@ -154,7 +154,7 @@ type FolderInfoResponse struct { Type string `json:"type"` Home string `json:"home"` List []ListItem `json:"list"` - } `json:"body,omitempty"` + } `json:"body"` Time int64 `json:"time"` Status int `json:"status"` Email string `json:"email"` diff --git a/backend/onedrive/api/types.go b/backend/onedrive/api/types.go index ba23a1165..75fdfda00 100644 --- a/backend/onedrive/api/types.go +++ b/backend/onedrive/api/types.go @@ -50,12 +50,12 @@ type Identity struct { // to represent a set of identities associated with various events for // an item, such as created by or last modified by. type IdentitySet struct { - User Identity `json:"user,omitempty"` - Application Identity `json:"application,omitempty"` - Device Identity `json:"device,omitempty"` - Group Identity `json:"group,omitempty"` - SiteGroup Identity `json:"siteGroup,omitempty"` // The SharePoint group associated with this action. Optional. - SiteUser Identity `json:"siteUser,omitempty"` // The SharePoint user associated with this action. Optional. + User Identity `json:"user"` + Application Identity `json:"application"` + Device Identity `json:"device"` + Group Identity `json:"group"` + SiteGroup Identity `json:"siteGroup"` // The SharePoint group associated with this action. Optional. + SiteUser Identity `json:"siteUser"` // The SharePoint user associated with this action. Optional. } // Quota groups storage space quota-related information on OneDrive into a single structure. @@ -155,8 +155,8 @@ type FileFacet struct { // facet can be used to specify the last modified date or created date // of the item as it was on the local device. type FileSystemInfoFacet struct { - CreatedDateTime Timestamp `json:"createdDateTime,omitempty"` // The UTC date and time the file was created on a client. - LastModifiedDateTime Timestamp `json:"lastModifiedDateTime,omitempty"` // The UTC date and time the file was last modified on a client. + CreatedDateTime Timestamp `json:"createdDateTime"` // The UTC date and time the file was created on a client. + LastModifiedDateTime Timestamp `json:"lastModifiedDateTime"` // The UTC date and time the file was last modified on a client. } // DeletedFacet indicates that the item on OneDrive has been @@ -175,10 +175,10 @@ type PackageFacet struct { // SharedType indicates a DriveItem has been shared with others. The resource includes information about how the item is shared. // If a Driveitem has a non-null shared facet, the item has been shared. type SharedType struct { - Owner IdentitySet `json:"owner,omitempty"` // The identity of the owner of the shared item. Read-only. - Scope string `json:"scope,omitempty"` // Indicates the scope of how the item is shared: anonymous, organization, or users. Read-only. - SharedBy IdentitySet `json:"sharedBy,omitempty"` // The identity of the user who shared the item. Read-only. - SharedDateTime Timestamp `json:"sharedDateTime,omitempty"` // The UTC date and time when the item was shared. Read-only. + Owner IdentitySet `json:"owner"` // The identity of the owner of the shared item. Read-only. + Scope string `json:"scope,omitempty"` // Indicates the scope of how the item is shared: anonymous, organization, or users. Read-only. + SharedBy IdentitySet `json:"sharedBy"` // The identity of the user who shared the item. Read-only. + SharedDateTime Timestamp `json:"sharedDateTime"` // The UTC date and time when the item was shared. Read-only. } // SharingInvitationType groups invitation-related data items into a single structure. diff --git a/backend/pikpak/api/types.go b/backend/pikpak/api/types.go index e167ffcfd..c97829cfb 100644 --- a/backend/pikpak/api/types.go +++ b/backend/pikpak/api/types.go @@ -75,8 +75,8 @@ type ErrorDetails struct { Type string `json:"@type,omitempty"` Reason string `json:"reason,omitempty"` Domain string `json:"domain,omitempty"` - Metadata struct{} `json:"metadata,omitempty"` // TODO: undiscovered yet - Locale string `json:"locale,omitempty"` // e.g. "en" + Metadata struct{} `json:"metadata"` // TODO: undiscovered yet + Locale string `json:"locale,omitempty"` // e.g. "en" Message string `json:"message,omitempty"` StackEntries []any `json:"stack_entries,omitempty"` // TODO: undiscovered yet Detail string `json:"detail,omitempty"` @@ -189,8 +189,8 @@ type File struct { Apps []*FileApp `json:"apps,omitempty"` Audit *FileAudit `json:"audit,omitempty"` Collection string `json:"collection,omitempty"` // TODO - CreatedTime Time `json:"created_time,omitempty"` - DeleteTime Time `json:"delete_time,omitempty"` + CreatedTime Time `json:"created_time"` + DeleteTime Time `json:"delete_time"` FileCategory string `json:"file_category,omitempty"` // "AUDIO", "VIDEO" FileExtension string `json:"file_extension,omitempty"` FolderType string `json:"folder_type,omitempty"` @@ -202,7 +202,7 @@ type File struct { Md5Checksum string `json:"md5_checksum,omitempty"` Medias []*Media `json:"medias,omitempty"` MimeType string `json:"mime_type,omitempty"` - ModifiedTime Time `json:"modified_time,omitempty"` // updated when renamed or moved + ModifiedTime Time `json:"modified_time"` // updated when renamed or moved Name string `json:"name,omitempty"` OriginalFileIndex int `json:"original_file_index,omitempty"` // TODO OriginalURL string `json:"original_url,omitempty"` @@ -221,7 +221,7 @@ type File struct { ThumbnailLink string `json:"thumbnail_link,omitempty"` Trashed bool `json:"trashed,omitempty"` UserID string `json:"user_id,omitempty"` - UserModifiedTime Time `json:"user_modified_time,omitempty"` + UserModifiedTime Time `json:"user_modified_time"` WebContentLink string `json:"web_content_link,omitempty"` Writable bool `json:"writable,omitempty"` } @@ -252,7 +252,7 @@ type Media struct { AudioCodec string `json:"audio_codec,omitempty"` // "pcm_bluray", "aac" VideoType string `json:"video_type,omitempty"` // "mpegts" HdrType string `json:"hdr_type,omitempty"` - } `json:"video,omitempty"` + } `json:"video"` Link *Link `json:"link,omitempty"` NeedMoreQuota bool `json:"need_more_quota,omitempty"` VipTypes []any `json:"vip_types,omitempty"` // TODO maybe list of something? @@ -290,11 +290,11 @@ type FileApp struct { NeedMoreQuota bool `json:"need_more_quota,omitempty"` IconLink string `json:"icon_link,omitempty"` IsDefault bool `json:"is_default,omitempty"` - Params struct{} `json:"params,omitempty"` // TODO + Params struct{} `json:"params"` // TODO CategoryIDs []any `json:"category_ids,omitempty"` AdSceneType int `json:"ad_scene_type,omitempty"` Space string `json:"space,omitempty"` - Links struct{} `json:"links,omitempty"` // TODO + Links struct{} `json:"links"` // TODO } // ------------------------------------------------------------ @@ -320,8 +320,8 @@ type Task struct { FileName string `json:"file_name,omitempty"` FileSize string `json:"file_size,omitempty"` Message string `json:"message,omitempty"` // e.g. "Saving" - CreatedTime Time `json:"created_time,omitempty"` - UpdatedTime Time `json:"updated_time,omitempty"` + CreatedTime Time `json:"created_time"` + UpdatedTime Time `json:"updated_time"` ThirdTaskID string `json:"third_task_id,omitempty"` // TODO Phase string `json:"phase,omitempty"` // e.g. "PHASE_TYPE_RUNNING" Progress int `json:"progress,omitempty"` @@ -368,7 +368,7 @@ type ResumableParams struct { AccessKeySecret string `json:"access_key_secret,omitempty"` Bucket string `json:"bucket,omitempty"` Endpoint string `json:"endpoint,omitempty"` - Expiration Time `json:"expiration,omitempty"` + Expiration Time `json:"expiration"` Key string `json:"key,omitempty"` SecurityToken string `json:"security_token,omitempty"` } @@ -409,7 +409,7 @@ type About struct { Kind string `json:"kind,omitempty"` // "drive#about" Quota *Quota `json:"quota,omitempty"` ExpiresAt string `json:"expires_at,omitempty"` - Quotas struct{} `json:"quotas,omitempty"` // maybe []*Quota? + Quotas struct{} `json:"quotas"` // maybe []*Quota? } // Quota informs drive quota @@ -445,8 +445,8 @@ type User struct { PhoneNumber string `json:"phone_number,omitempty"` Password string `json:"password,omitempty"` // "SET" if configured Status string `json:"status,omitempty"` // "ACTIVE" - CreatedAt Time `json:"created_at,omitempty"` - PasswordUpdatedAt Time `json:"password_updated_at,omitempty"` + CreatedAt Time `json:"created_at"` + PasswordUpdatedAt Time `json:"password_updated_at"` } // UserProvider details third-party authentication @@ -464,11 +464,11 @@ type VIP struct { Message string `json:"message,omitempty"` RedirectURI string `json:"redirect_uri,omitempty"` Data struct { - Expire Time `json:"expire,omitempty"` + Expire Time `json:"expire"` Status string `json:"status,omitempty"` // "invalid" or "ok" Type string `json:"type,omitempty"` // "novip" or "platinum" UserID string `json:"user_id,omitempty"` // same as User.Sub - } `json:"data,omitempty"` + } `json:"data"` } // DecompressResult is a response to RequestDecompress @@ -538,7 +538,7 @@ type CaptchaToken struct { CaptchaToken string `json:"captcha_token"` ExpiresIn int64 `json:"expires_in"` // currently 300s // API doesn't provide Expiry field and thus it should be populated from ExpiresIn on retrieval - Expiry time.Time `json:"expiry,omitempty"` + Expiry time.Time `json:"expiry"` URL string `json:"url,omitempty"` // a link for users to solve captcha } diff --git a/backend/shade/shade.go b/backend/shade/shade.go index d06c66d51..dc8d1c64e 100644 --- a/backend/shade/shade.go +++ b/backend/shade/shade.go @@ -163,7 +163,7 @@ func (f *Fs) refreshJWTToken(ctx context.Context) (string, error) { if err != nil { return "", fmt.Errorf("invalid token received from server") } - var claims map[string]interface{} + var claims map[string]any if err := json.Unmarshal(payload, &claims); err != nil { return "", err } @@ -182,7 +182,7 @@ func (f *Fs) refreshJWTToken(ctx context.Context) (string, error) { return f.token, nil } -func (f *Fs) callAPI(ctx context.Context, method, path string, response interface{}) (*http.Response, error) { +func (f *Fs) callAPI(ctx context.Context, method, path string, response any) (*http.Response, error) { token, err := f.refreshJWTToken(ctx) if err != nil { return nil, err diff --git a/backend/shade/upload.go b/backend/shade/upload.go index a4b1ecc04..0419f42d1 100644 --- a/backend/shade/upload.go +++ b/backend/shade/upload.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "io" + "maps" "net/http" "net/url" "path" @@ -203,9 +204,7 @@ func (s *shadeChunkWriter) WriteChunk(ctx context.Context, chunkNumber int, read var uploadRes *http.Response if len(partURL.Headers) > 0 { opts.ExtraHeaders = make(map[string]string) - for k, v := range partURL.Headers { - opts.ExtraHeaders[k] = v - } + maps.Copy(opts.ExtraHeaders, partURL.Headers) } err = s.f.pacer.Call(func() (bool, error) { diff --git a/backend/sharefile/api/types.go b/backend/sharefile/api/types.go index 7b48bbec7..b6f01e373 100644 --- a/backend/sharefile/api/types.go +++ b/backend/sharefile/api/types.go @@ -27,8 +27,8 @@ type Item struct { FileCount int32 `json:"FileCount,omitempty"` Name string `json:"Name,omitempty"` FileName string `json:"FileName,omitempty"` - CreatedAt time.Time `json:"CreationDate,omitempty"` - ModifiedAt time.Time `json:"ClientModifiedDate,omitempty"` + CreatedAt time.Time `json:"CreationDate"` + ModifiedAt time.Time `json:"ClientModifiedDate"` IsHidden bool `json:"IsHidden,omitempty"` Size int64 `json:"FileSizeBytes,omitempty"` Type string `json:"odata.type,omitempty"` diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index 32d884257..bc6a0241f 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -610,7 +610,7 @@ func (f *Fs) findHeader(headers fs.CommaSepList, find string) bool { // fetch the bearer token and set it if successful func (f *Fs) fetchAndSetBearerToken() error { - _, err, _ := f.authSingleflight.Do("bearerToken", func() (interface{}, error) { + _, err, _ := f.authSingleflight.Do("bearerToken", func() (any, error) { if len(f.opt.BearerTokenCommand) == 0 { return nil, nil } diff --git a/backend/zoho/api/types.go b/backend/zoho/api/types.go index efbb4c564..a606fa335 100644 --- a/backend/zoho/api/types.go +++ b/backend/zoho/api/types.go @@ -256,7 +256,7 @@ type WriteMultiMetadataRequest struct { // WriteMetadata is used to write item metadata type WriteMetadata struct { - Attributes WriteAttributes `json:"attributes,omitempty"` + Attributes WriteAttributes `json:"attributes"` ID string `json:"id,omitempty"` Type string `json:"type"` } diff --git a/cmd/archive/files/countwriter_test.go b/cmd/archive/files/countwriter_test.go index 3168960e5..bb95e818b 100644 --- a/cmd/archive/files/countwriter_test.go +++ b/cmd/archive/files/countwriter_test.go @@ -92,10 +92,10 @@ func TestCountWriterConcurrent(t *testing.T) { var wg sync.WaitGroup wg.Add(goroutines) - for g := 0; g < goroutines; g++ { + for range goroutines { go func() { defer wg.Done() - for i := 0; i < loops; i++ { + for range loops { n, err := cw.Write(data) assert.NoError(t, err) assert.Equal(t, chunkSize, n) diff --git a/cmd/bisync/lockfile.go b/cmd/bisync/lockfile.go index e294ff0e8..e9e37fa7f 100644 --- a/cmd/bisync/lockfile.go +++ b/cmd/bisync/lockfile.go @@ -128,9 +128,7 @@ func (b *bisyncRun) startLockRenewal() func() { } stopLockRenewal := make(chan struct{}) var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { ticker := time.NewTicker(time.Duration(b.opt.MaxLock) - time.Minute) for { select { @@ -141,7 +139,7 @@ func (b *bisyncRun) startLockRenewal() func() { return } } - }() + }) return func() { close(stopLockRenewal) wg.Wait() diff --git a/cmd/cmd.go b/cmd/cmd.go index cc485dd4f..792544e73 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -361,9 +361,7 @@ func StartStats() func() { } stopStats := make(chan struct{}) var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { ticker := time.NewTicker(*statsInterval) for { select { @@ -374,7 +372,7 @@ func StartStats() func() { return } } - }() + }) return func() { close(stopStats) wg.Wait() diff --git a/cmd/cmount/mount.go b/cmd/cmount/mount.go index 5b23a829e..908ae0b9c 100644 --- a/cmd/cmount/mount.go +++ b/cmd/cmount/mount.go @@ -108,7 +108,7 @@ func mountOptions(VFS *vfs.VFS, device string, mountpoint string, opt *mountlib. func waitFor(fn func() bool) (ok bool) { const totalWait = 10 * time.Second const individualWait = 10 * time.Millisecond - for i := 0; i < int(totalWait/individualWait); i++ { + for range int(totalWait / individualWait) { ok = fn() if ok { return ok diff --git a/cmd/progress.go b/cmd/progress.go index 539f0b801..3ec1d94ff 100644 --- a/cmd/progress.go +++ b/cmd/progress.go @@ -41,9 +41,7 @@ func startProgress() func() { } var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { progressInterval := defaultProgressInterval if ShowStats() && *statsInterval > 0 { progressInterval = *statsInterval @@ -65,7 +63,7 @@ func startProgress() func() { return } } - }() + }) return func() { close(stopStats) wg.Wait() diff --git a/cmd/serve/nfs/cache_test.go b/cmd/serve/nfs/cache_test.go index 2cc4d961e..e38c06934 100644 --- a/cmd/serve/nfs/cache_test.go +++ b/cmd/serve/nfs/cache_test.go @@ -66,11 +66,9 @@ func testCacheCRUD(t *testing.T, h *Handler, c Cache, fileName string) { func testCacheThrashDifferent(t *testing.T, h *Handler, c Cache) { var wg sync.WaitGroup for i := range 100 { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { testCacheCRUD(t, h, c, fmt.Sprintf("file-%d", i)) - }() + }) } wg.Wait() } @@ -79,9 +77,7 @@ func testCacheThrashDifferent(t *testing.T, h *Handler, c Cache) { func testCacheThrashSame(t *testing.T, h *Handler, c Cache) { var wg sync.WaitGroup for range 100 { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { // Write a handle splitPath := []string{"file"} @@ -108,7 +104,7 @@ func testCacheThrashSame(t *testing.T, h *Handler, c Cache) { require.Error(t, err) assert.Equal(t, errStaleHandle, err) } - }() + }) } wg.Wait() } diff --git a/fs/accounting/transfer.go b/fs/accounting/transfer.go index fc79c5ca1..b18723921 100644 --- a/fs/accounting/transfer.go +++ b/fs/accounting/transfer.go @@ -19,7 +19,7 @@ type TransferSnapshot struct { Checked bool `json:"checked"` What string `json:"what"` StartedAt time.Time `json:"started_at"` - CompletedAt time.Time `json:"completed_at,omitempty"` + CompletedAt time.Time `json:"completed_at"` Error error `json:"-"` Group string `json:"group"` SrcFs string `json:"srcFs,omitempty"` diff --git a/fs/asyncreader/asyncreader_test.go b/fs/asyncreader/asyncreader_test.go index a6665e33b..7c5f9ce97 100644 --- a/fs/asyncreader/asyncreader_test.go +++ b/fs/asyncreader/asyncreader_test.go @@ -265,9 +265,7 @@ func testAsyncReaderClose(t *testing.T, writeto bool) { var copyErr error var wg sync.WaitGroup started := make(chan struct{}) - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { close(started) if writeto { // exercise the WriteTo path @@ -284,7 +282,7 @@ func testAsyncReaderClose(t *testing.T, writeto bool) { } } } - }() + }) // Do some copying <-started time.Sleep(100 * time.Millisecond) diff --git a/fs/config/configstruct/configstruct.go b/fs/config/configstruct/configstruct.go index bb72ae359..545f7d166 100644 --- a/fs/config/configstruct/configstruct.go +++ b/fs/config/configstruct/configstruct.go @@ -163,7 +163,7 @@ type Item struct { // struct, otherwise they will be embedded as they are. func Items(opt any) (items []Item, err error) { def := reflect.ValueOf(opt) - if def.Kind() != reflect.Ptr { + if def.Kind() != reflect.Pointer { return nil, errors.New("argument must be a pointer") } def = def.Elem() // indirect the pointer diff --git a/fs/log/log.go b/fs/log/log.go index 76bf2b72d..76f1f6b0e 100644 --- a/fs/log/log.go +++ b/fs/log/log.go @@ -156,7 +156,7 @@ func Trace(o any, format string, a ...any) func(string, ...any) { for i := range a { // read the values of the pointed to items typ := reflect.TypeOf(a[i]) - if typ.Kind() == reflect.Ptr { + if typ.Kind() == reflect.Pointer { value := reflect.ValueOf(a[i]) if value.IsNil() { a[i] = nil diff --git a/fs/march/march.go b/fs/march/march.go index 9123f8a7e..fbcacab1b 100644 --- a/fs/march/march.go +++ b/fs/march/march.go @@ -205,9 +205,7 @@ func (m *March) Run(ctx context.Context) error { checkers := ci.Checkers in := make(chan listDirJob, checkers) for range checkers { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for { select { case <-m.Ctx.Done(): @@ -244,7 +242,7 @@ func (m *March) Run(ctx context.Context) error { traversing.Done() } } - }() + }) } // Start the process @@ -393,9 +391,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { // List the src and dst directories if !job.noSrc { srcChan := srcChan // duplicate this as we may override it later - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { srcListErr = m.srcListDir(job.srcRemote, func(entries fs.DirEntries) error { for _, entry := range entries { srcChan <- entry @@ -403,16 +399,14 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { return nil }) close(srcChan) - }() + }) } else { close(srcChan) } startedDst := false if !m.NoTraverse && !job.noDst { startedDst = true - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { dstListErr = m.dstListDir(job.dstRemote, func(entries fs.DirEntries) error { for _, entry := range entries { dstChan <- entry @@ -420,7 +414,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { return nil }) close(dstChan) - }() + }) } // If NoTraverse is set, then try to find a matching object // for each item in the srcList to head dst object @@ -455,9 +449,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { // Get the tasks from the queue and find a matching object. var workerWg sync.WaitGroup for range workers { - workerWg.Add(1) - go func() { - defer workerWg.Done() + workerWg.Go(func() { for t := range matchTasks { // Can't match directories with NewObject if _, ok := t.src.(fs.Object); !ok { @@ -476,7 +468,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { } t.dstMatch <- dst } - }() + }) } // Close dstResults when all the workers have finished @@ -486,9 +478,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { }() // Read the matches in order and send them to dstChan if found. - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for dstMatch := range dstMatches { dst := <-dstMatch // Note that dst may be nil here @@ -497,7 +487,7 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) { } close(srcChan) close(dstChan) - }() + }) } if !startedDst { close(dstChan) diff --git a/fs/march/march_test.go b/fs/march/march_test.go index 76747287e..d1a866538 100644 --- a/fs/march/march_test.go +++ b/fs/march/march_test.go @@ -508,9 +508,7 @@ func TestMatchListings(t *testing.T) { } ls, err := list.NewSorter(ctx, nil, list.SortToChan(out), key) require.NoError(t, err) - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for i := 0; i < len(test.input); i += 2 { entry := test.input[i+offset] if entry != nil { @@ -520,7 +518,7 @@ func TestMatchListings(t *testing.T) { require.NoError(t, ls.Send()) ls.CleanUp() close(out) - }() + }) return out } diff --git a/fs/sync/sync.go b/fs/sync/sync.go index a425345a4..6ec0c074f 100644 --- a/fs/sync/sync.go +++ b/fs/sync/sync.go @@ -570,13 +570,11 @@ func (s *syncCopyMove) startTrackRenames() { if !s.trackRenames { return } - s.trackRenamesWg.Add(1) - go func() { - defer s.trackRenamesWg.Done() + s.trackRenamesWg.Go(func() { for o := range s.trackRenamesCh { s.renameCheck = append(s.renameCheck, o) } - }() + }) } // This stops the background rename collection @@ -593,12 +591,10 @@ func (s *syncCopyMove) startDeleters() { if s.deleteMode != fs.DeleteModeDuring && s.deleteMode != fs.DeleteModeOnly { return } - s.deletersWg.Add(1) - go func() { - defer s.deletersWg.Done() + s.deletersWg.Go(func() { err := operations.DeleteFilesWithBackupDir(s.ctx, s.deleteFilesCh, s.backupDir) s.processError(err) - }() + }) } // This stops the background deleters diff --git a/fs/walk/walk.go b/fs/walk/walk.go index d9857a2f1..de3db6d8c 100644 --- a/fs/walk/walk.go +++ b/fs/walk/walk.go @@ -391,9 +391,7 @@ func walk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel i }) } for range ci.Checkers { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for { select { case job, ok := <-in: @@ -442,7 +440,7 @@ func walk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel i return } } - }() + }) } // Start the process traversing.Add(1) diff --git a/lib/errors/errors.go b/lib/errors/errors.go index bb81b8529..4fb1fc901 100644 --- a/lib/errors/errors.go +++ b/lib/errors/errors.go @@ -44,7 +44,7 @@ func Walk(err error, f WalkFunc) { // *os.SyscallError and many others in the stdlib. errType := reflect.TypeOf(err) errValue := reflect.ValueOf(err) - if errValue.IsValid() && errType.Kind() == reflect.Ptr { + if errValue.IsValid() && errType.Kind() == reflect.Pointer { errType = errType.Elem() errValue = errValue.Elem() } diff --git a/lib/pacer/pacer_test.go b/lib/pacer/pacer_test.go index e34a406aa..bfaa96e88 100644 --- a/lib/pacer/pacer_test.go +++ b/lib/pacer/pacer_test.go @@ -375,21 +375,17 @@ func TestCallMaxConnectionsRecursiveDeadlock2(t *testing.T) { // Normal for range 100 { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { err := p.Call(func() (bool, error) { // check we have taken the connection token assert.Equal(t, 0, len(p.connTokens)) return false, nil }) assert.NoError(t, err) - }() + }) // Now attempt a recursive call - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { err := p.Call(func() (bool, error) { // check we have taken the connection token assert.Equal(t, 0, len(p.connTokens)) @@ -397,7 +393,7 @@ func TestCallMaxConnectionsRecursiveDeadlock2(t *testing.T) { return false, p.Call(dp.fn) }) assert.Equal(t, errFoo, err) - }() + }) } // Tidy up diff --git a/lib/pool/pool_test.go b/lib/pool/pool_test.go index 5c0434e82..72a22d605 100644 --- a/lib/pool/pool_test.go +++ b/lib/pool/pool_test.go @@ -290,9 +290,7 @@ func TestPoolMaxBufferMemory(t *testing.T) { ) const trials = 50 for i := range trials { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { if i < trials/2 { n := i%4 + 1 buf := bp.GetN(n) @@ -307,7 +305,7 @@ func TestPoolMaxBufferMemory(t *testing.T) { countBuf(-1) bp.Put(buf) } - }() + }) } wg.Wait() diff --git a/lib/pool/reader_writer_test.go b/lib/pool/reader_writer_test.go index bd6a91631..568424c23 100644 --- a/lib/pool/reader_writer_test.go +++ b/lib/pool/reader_writer_test.go @@ -563,11 +563,9 @@ func TestRWConcurrency(t *testing.T) { writeTo := func(rw *RW, size int64) { in, out := io.Pipe() var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { check(in, size, rw) - }() + }) var n int64 for n < size { nn, err := rw.WriteTo(out) diff --git a/vfs/test_vfs/test_vfs.go b/vfs/test_vfs/test_vfs.go index a38f72e67..3d571fef0 100644 --- a/vfs/test_vfs/test_vfs.go +++ b/vfs/test_vfs/test_vfs.go @@ -296,13 +296,11 @@ func main() { quit = make(chan struct{}, *iterations) ) for range *number { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { t := NewTest(dir) defer t.Tidy() t.RandomTests(*iterations, quit) - }() + }) } wg.Wait() } diff --git a/vfs/vfscache/downloaders/downloaders.go b/vfs/vfscache/downloaders/downloaders.go index 87783fb6b..99d3d39bd 100644 --- a/vfs/vfscache/downloaders/downloaders.go +++ b/vfs/vfscache/downloaders/downloaders.go @@ -115,9 +115,7 @@ func New(item Item, opt *vfscommon.Options, remote string, src fs.Object) (dls * src: src, remote: remote, } - dls.wg.Add(1) - go func() { - defer dls.wg.Done() + dls.wg.Go(func() { ticker := time.NewTicker(backgroundKickerInterval) select { case <-ticker.C: @@ -129,7 +127,7 @@ func New(item Item, opt *vfscommon.Options, remote string, src fs.Object) (dls * break } ticker.Stop() - }() + }) return dls } @@ -189,9 +187,7 @@ func (dls *Downloaders) _newDownloader(r ranges.Range) (dl *downloader, err erro dls.dls = append(dls.dls, dl) - dl.wg.Add(1) - go func() { - defer dl.wg.Done() + dl.wg.Go(func() { n, err := dl.download() _ = dl.close(err) dl.dls.countErrors(n, err) @@ -202,7 +198,7 @@ func (dls *Downloaders) _newDownloader(r ranges.Range) (dl *downloader, err erro if err != nil { fs.Errorf(dl.dls.src, "vfs cache: failed to kick waiters: %v", err) } - }() + }) return dl, nil } diff --git a/vfs/vfscache/item_test.go b/vfs/vfscache/item_test.go index 048261b62..5efe0d036 100644 --- a/vfs/vfscache/item_test.go +++ b/vfs/vfscache/item_test.go @@ -542,9 +542,7 @@ func TestItemReadWrite(t *testing.T) { assert.False(t, item.present()) var wg sync.WaitGroup for range 8 { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { in := readers.NewPatternReader(size) buf := make([]byte, 1024*1024) buf2 := make([]byte, 1024*1024) @@ -553,7 +551,7 @@ func TestItemReadWrite(t *testing.T) { offset := max(rand.Int63n(size+2*int64(blockSize))-int64(blockSize), 0) _, _ = readCheckBuf(t, in, buf, buf2, item, offset, blockSize) } - }() + }) } wg.Wait() require.NoError(t, item.Close(nil))