From 97cc6bf23b97d88e2ca1f52875e4fe68d6c9e747 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Tue, 10 Mar 2026 09:14:55 -0700 Subject: [PATCH] chore: run go modernize tool This is a fixup of the codebase using: go run golang.org/x/tools/go/analysis/passes/modernize/cmd/modernize@latest -fix ./... This has no bahvior changes, and only updates safe changes for modern go features. --- auth/bucket_cors.go | 4 ++-- auth/iam_ipa.go | 4 ++-- aws/signer/internal/v4/host.go | 20 +++++++++---------- aws/signer/internal/v4/util_test.go | 2 +- aws/signer/v4/v4.go | 2 +- aws/signer/v4/v4_test.go | 4 ++-- backend/posix/without_otmpfile.go | 1 - backend/walk.go | 8 ++------ backend/walk_test.go | 6 ++---- cmd/versitygw/admin.go | 8 ++++---- cmd/versitygw/gateway_test.go | 6 ++---- metrics/metrics.go | 8 ++++---- s3api/controllers/base.go | 2 +- s3api/middlewares/apply-default-cors.go | 2 +- s3api/utils/utils.go | 12 +++++------ s3api/utils/utils_test.go | 2 +- s3err/s3err.go | 2 +- s3select/arch64.go | 1 - tests/checker/main.go | 4 ++-- tests/integration/CompleteMultipartUpload.go | 7 +++---- tests/integration/bench.go | 10 ++++------ tests/integration/concurrency.go | 6 ++---- tests/integration/output.go | 6 +++--- tests/integration/utils.go | 7 +++---- tests/rest_scripts/command/payloadChunked.go | 7 +------ .../command/putBucketCorsCommand.go | 4 ++-- tests/rest_scripts/generateCommand.go | 4 ++-- tests/rest_scripts/logger/logging.go | 4 ++-- webui/webserver.go | 2 +- 29 files changed, 67 insertions(+), 88 deletions(-) diff --git a/auth/bucket_cors.go b/auth/bucket_cors.go index 27afaba9..3637bf00 100644 --- a/auth/bucket_cors.go +++ b/auth/bucket_cors.go @@ -327,8 +327,8 @@ func ParseCORSHeaders(headers string) ([]CORSHeader, error) { return result, nil } - headersSplitted := strings.Split(headers, ",") - for _, h := range headersSplitted { + headersSplitted := strings.SplitSeq(headers, ",") + for h := range headersSplitted { corsHeader := CORSHeader(strings.TrimSpace(h)) if corsHeader == "" || !corsHeader.IsValid() { debuglogger.Logf("invalid access control header: %s", h) diff --git a/auth/iam_ipa.go b/auth/iam_ipa.go index 921c37e5..e54e2e03 100644 --- a/auth/iam_ipa.go +++ b/auth/iam_ipa.go @@ -416,7 +416,7 @@ func (ipa *IpaIAMService) newRequest(method string, args []string, dict map[stri return "", fmt.Errorf("ipa request invalid: %w", err) } - request := map[string]interface{}{ + request := map[string]any{ "id": id, "method": json.RawMessage(jmethod), "params": []json.RawMessage{json.RawMessage(jargs), json.RawMessage(jdict)}, @@ -448,7 +448,7 @@ func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) { if n == 0 || n > len(b) { return nil, errors.New("invalid padding on input") } - for i := 0; i < n; i++ { + for i := range n { if b[len(b)-n+i] != c { return nil, errors.New("invalid padding on input") } diff --git a/aws/signer/internal/v4/host.go b/aws/signer/internal/v4/host.go index bf93659a..0c5a3e87 100644 --- a/aws/signer/internal/v4/host.go +++ b/aws/signer/internal/v4/host.go @@ -31,14 +31,14 @@ func getHost(r *http.Request) string { // // Copied from the Go 1.8 standard library (net/url) func stripPort(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { + before, _, ok := strings.Cut(hostport, ":") + if !ok { return hostport } - if i := strings.IndexByte(hostport, ']'); i != -1 { - return strings.TrimPrefix(hostport[:i], "[") + if before, _, ok := strings.Cut(hostport, "]"); ok { + return strings.TrimPrefix(before, "[") } - return hostport[:colon] + return before } // Port returns the port part of u.Host, without the leading colon. @@ -46,17 +46,17 @@ func stripPort(hostport string) string { // // Copied from the Go 1.8 standard library (net/url) func portOnly(hostport string) string { - colon := strings.IndexByte(hostport, ':') - if colon == -1 { + _, after, ok := strings.Cut(hostport, ":") + if !ok { return "" } - if i := strings.Index(hostport, "]:"); i != -1 { - return hostport[i+len("]:"):] + if _, after, ok := strings.Cut(hostport, "]:"); ok { + return after } if strings.Contains(hostport, "]") { return "" } - return hostport[colon+len(":"):] + return after } // Returns true if the specified URI is using the standard port diff --git a/aws/signer/internal/v4/util_test.go b/aws/signer/internal/v4/util_test.go index a38ef2d7..277f87b6 100644 --- a/aws/signer/internal/v4/util_test.go +++ b/aws/signer/internal/v4/util_test.go @@ -122,7 +122,7 @@ func TestStripExcessHeaders(t *testing.T) { "12 3 1abc123", } - for i := 0; i < len(vals); i++ { + for i := range vals { r := StripExcessSpaces(vals[i]) if e, a := expected[i], r; e != a { t.Errorf("%d, expect %v, got %v", i, e, a) diff --git a/aws/signer/v4/v4.go b/aws/signer/v4/v4.go index 02f43b95..b6a3a6d2 100644 --- a/aws/signer/v4/v4.go +++ b/aws/signer/v4/v4.go @@ -457,7 +457,7 @@ func (s *httpSigner) buildCanonicalHeaders(host string, rule v4Internal.Rule, he var canonicalHeaders strings.Builder n := len(headers) const colon = ':' - for i := 0; i < n; i++ { + for i := range n { if headers[i] == hostHeader { canonicalHeaders.WriteString(hostHeader) canonicalHeaders.WriteRune(colon) diff --git a/aws/signer/v4/v4_test.go b/aws/signer/v4/v4_test.go index fc188d55..6c66acc1 100644 --- a/aws/signer/v4/v4_test.go +++ b/aws/signer/v4/v4_test.go @@ -100,7 +100,7 @@ func TestPresignRequest(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } - for _, h := range strings.Split(expectedHeaders, ";") { + for h := range strings.SplitSeq(expectedHeaders, ";") { v := headers.Get(h) if len(v) == 0 { t.Errorf("expect %v, to be present in header map", h) @@ -153,7 +153,7 @@ func TestPresignBodyWithArrayRequest(t *testing.T) { t.Errorf("expect %v, got %v", e, a) } - for _, h := range strings.Split(expectedHeaders, ";") { + for h := range strings.SplitSeq(expectedHeaders, ";") { v := headers.Get(h) if len(v) == 0 { t.Errorf("expect %v, to be present in header map", h) diff --git a/backend/posix/without_otmpfile.go b/backend/posix/without_otmpfile.go index d19b5490..f017e755 100644 --- a/backend/posix/without_otmpfile.go +++ b/backend/posix/without_otmpfile.go @@ -13,7 +13,6 @@ // under the License. //go:build !linux -// +build !linux package posix diff --git a/backend/walk.go b/backend/walk.go index 2e394c4a..75e2cde1 100644 --- a/backend/walk.go +++ b/backend/walk.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "io/fs" + "slices" "strings" "syscall" @@ -300,12 +301,7 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin } func contains(a string, strs []string) bool { - for _, s := range strs { - if s == a { - return true - } - } - return false + return slices.Contains(strs, a) } type WalkVersioningResults struct { diff --git a/backend/walk_test.go b/backend/walk_test.go index 489a4d4e..1e7627a2 100644 --- a/backend/walk_test.go +++ b/backend/walk_test.go @@ -374,14 +374,12 @@ func TestWalkStop(t *testing.T) { var err error var wg sync.WaitGroup - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { _, err = backend.Walk(ctx, s, "", "/", "", 1000, func(path string, d fs.DirEntry) (s3response.Object, error) { return s3response.Object{}, nil }, []string{}) - }() + }) select { case <-time.After(1 * time.Second): diff --git a/cmd/versitygw/admin.go b/cmd/versitygw/admin.go index f88082bd..8d514d8a 100644 --- a/cmd/versitygw/admin.go +++ b/cmd/versitygw/admin.go @@ -583,11 +583,11 @@ func parseCreateBucketPayload(input string) ([]byte, error) { } for _, part := range inputParts { part = strings.TrimSpace(part) - if strings.HasPrefix(part, "LocationConstraint=") { - locConstraint := strings.TrimPrefix(part, "LocationConstraint=") + if after, ok := strings.CutPrefix(part, "LocationConstraint="); ok { + locConstraint := after config.LocationConstraint = &locConstraint - } else if strings.HasPrefix(part, "Tags=") { - tags, err := parseTagging(strings.TrimPrefix(part, "Tags=")) + } else if after, ok := strings.CutPrefix(part, "Tags="); ok { + tags, err := parseTagging(after) if err != nil { return nil, err } diff --git a/cmd/versitygw/gateway_test.go b/cmd/versitygw/gateway_test.go index 0c01ac9f..dc4f631d 100644 --- a/cmd/versitygw/gateway_test.go +++ b/cmd/versitygw/gateway_test.go @@ -68,8 +68,7 @@ func initPosix(ctx context.Context) { log.Fatalf("init posix: %v", err) } - wg.Add(1) - go func() { + wg.Go(func() { err = runGateway(ctx, be) if err != nil && err != context.Canceled { log.Fatalf("run gateway: %v", err) @@ -79,8 +78,7 @@ func initPosix(ctx context.Context) { if err != nil { log.Fatalf("remove temp directory: %v", err) } - wg.Done() - }() + }) // wait for server to start time.Sleep(1 * time.Second) diff --git a/metrics/metrics.go b/metrics/metrics.go index 753b4057..b95cde68 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -88,9 +88,9 @@ func NewManager(ctx context.Context, conf Config) (Manager, error) { // setup statsd endpoints if len(conf.StatsdServers) > 0 { - statsdServers := strings.Split(conf.StatsdServers, ",") + statsdServers := strings.SplitSeq(conf.StatsdServers, ",") - for _, server := range statsdServers { + for server := range statsdServers { statsd, err := newStatsd(server, conf.ServiceName) if err != nil { return nil, err @@ -101,9 +101,9 @@ func NewManager(ctx context.Context, conf Config) (Manager, error) { // setup dogstatsd endpoints if len(conf.DogStatsdServers) > 0 { - dogStatsdServers := strings.Split(conf.DogStatsdServers, ",") + dogStatsdServers := strings.SplitSeq(conf.DogStatsdServers, ",") - for _, server := range dogStatsdServers { + for server := range dogStatsdServers { dogStatsd, err := newDogStatsd(server, conf.ServiceName) if err != nil { return nil, err diff --git a/s3api/controllers/base.go b/s3api/controllers/base.go index 80e95188..cdcb455f 100644 --- a/s3api/controllers/base.go +++ b/s3api/controllers/base.go @@ -349,7 +349,7 @@ func ensureExposeMetaHeaders(ctx *fiber.Ctx) { lowerExisting := map[string]struct{}{} if existing != "" { - for _, part := range strings.Split(existing, ",") { + for part := range strings.SplitSeq(existing, ",") { p := strings.ToLower(strings.TrimSpace(part)) if p != "" { lowerExisting[p] = struct{}{} diff --git a/s3api/middlewares/apply-default-cors.go b/s3api/middlewares/apply-default-cors.go index afb40731..c7c05523 100644 --- a/s3api/middlewares/apply-default-cors.go +++ b/s3api/middlewares/apply-default-cors.go @@ -29,7 +29,7 @@ func ensureExposeETag(ctx *fiber.Ctx) { } lowerExisting := map[string]struct{}{} - for _, part := range strings.Split(existing, ",") { + for part := range strings.SplitSeq(existing, ",") { p := strings.ToLower(strings.TrimSpace(part)) if p != "" { lowerExisting[p] = struct{}{} diff --git a/s3api/utils/utils.go b/s3api/utils/utils.go index bd98621f..c87fad9a 100644 --- a/s3api/utils/utils.go +++ b/s3api/utils/utils.go @@ -401,8 +401,8 @@ func ParseObjectAttributes(ctx *fiber.Ctx) (map[s3response.ObjectAttributes]stru if len(value) == 0 { break } - oattrs := strings.Split(string(value), ",") - for _, a := range oattrs { + oattrs := strings.SplitSeq(string(value), ",") + for a := range oattrs { attr := s3response.ObjectAttributes(a) if !attr.IsValid() { debuglogger.Logf("invalid object attribute: %v\n", attr) @@ -500,16 +500,16 @@ type ChecksumValues map[types.ChecksumAlgorithm]string // e.g. // "x-amz-checksum-crc64nvme, x-amz-checksum-sha1" func (cv ChecksumValues) Headers() string { - result := "" + var result strings.Builder isFirst := false for key := range cv { if !isFirst { - result += ", " + result.WriteString(", ") } - result += fmt.Sprintf("x-amz-checksum-%v", strings.ToLower(string(key))) + result.WriteString(fmt.Sprintf("x-amz-checksum-%v", strings.ToLower(string(key)))) } - return result + return result.String() } // ParseCalculatedChecksumHeaders parses and validates x-amz-checksum-x header keys diff --git a/s3api/utils/utils_test.go b/s3api/utils/utils_test.go index e19e783e..0538bb2c 100644 --- a/s3api/utils/utils_test.go +++ b/s3api/utils/utils_test.go @@ -992,7 +992,7 @@ func TestParseTagging(t *testing.T) { }, } - for i := 0; i < lgth; i++ { + for range lgth { res.TagSet.Tags = append(res.TagSet.Tags, s3response.Tag{ Key: genRandStr(10), Value: genRandStr(20), diff --git a/s3err/s3err.go b/s3err/s3err.go index f3e9c01b..d40dcc4c 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -940,7 +940,7 @@ func GetAPIErrorResponse(err APIError, resource, requestID, hostID string) []byt } // Encodes the response headers into XML format. -func encodeResponse(response interface{}) []byte { +func encodeResponse(response any) []byte { var bytesBuffer bytes.Buffer bytesBuffer.WriteString(xml.Header) e := xml.NewEncoder(&bytesBuffer) diff --git a/s3select/arch64.go b/s3select/arch64.go index 238edc6a..4eb4bf8e 100644 --- a/s3select/arch64.go +++ b/s3select/arch64.go @@ -13,7 +13,6 @@ // under the License. //go:build amd64 || arm64 || ppc64le || riscv64 -// +build amd64 arm64 ppc64le riscv64 package s3select diff --git a/tests/checker/main.go b/tests/checker/main.go index a16b653d..219bd67d 100644 --- a/tests/checker/main.go +++ b/tests/checker/main.go @@ -344,8 +344,8 @@ func headerCompare(expectedHeaders map[string]string, actualHeaders map[string][ } // regex match - if strings.HasPrefix(want, "re:") { - pat := strings.TrimPrefix(want, "re:") + if after, ok := strings.CutPrefix(want, "re:"); ok { + pat := after re, err := regexp.Compile(pat) if err != nil { return fmt.Errorf("bad regex for header %q: %w", k, err) diff --git a/tests/integration/CompleteMultipartUpload.go b/tests/integration/CompleteMultipartUpload.go index e086703a..74f85db8 100644 --- a/tests/integration/CompleteMultipartUpload.go +++ b/tests/integration/CompleteMultipartUpload.go @@ -23,6 +23,7 @@ import ( "fmt" "io" "net/http" + "slices" "strings" "sync" @@ -1898,10 +1899,8 @@ func CompleteMultipartUpload_racey_success(s *S3Conf) error { mu.RLock() defer mu.RUnlock() - for _, s := range sums { - if csum == s { - return nil - } + if slices.Contains(sums, csum) { + return nil } return fmt.Errorf("expected the object checksum to be one of %v, instead got %v", sums, csum) diff --git a/tests/integration/bench.go b/tests/integration/bench.go index 442d16fa..c1957a70 100644 --- a/tests/integration/bench.go +++ b/tests/integration/bench.go @@ -45,7 +45,7 @@ func TestUpload(s *S3Conf, files int, objSize int64, bucket, prefix string) erro runF("performance test: upload objects") - for i := 0; i < files; i++ { + for i := range files { sg.Add(1) go func(i int) { var r io.Reader = NewDataReader(int(objSize), int(s.PartSize)) @@ -87,7 +87,7 @@ func TestDownload(s *S3Conf, files int, objSize int64, bucket, prefix string) er runF("performance test: download objects") - for i := 0; i < files; i++ { + for i := range files { sg.Add(1) go func(i int) { nw := NewNullWriter() @@ -131,16 +131,14 @@ func TestReqPerSec(s *S3Conf, totalReqs int, bucket string) error { runF("performance test: measuring request per second") for i := 0; i < s.Concurrency; i++ { - wg.Add(1) - go func() { - defer wg.Done() + wg.Go(func() { for i := 0; i < totalReqs/s.Concurrency; i++ { _, err := client.HeadBucket(context.Background(), &s3.HeadBucketInput{Bucket: &bucket}) if err != nil && resErr != nil { resErr = err } } - }() + }) } wg.Wait() diff --git a/tests/integration/concurrency.go b/tests/integration/concurrency.go index 924ec9d8..f9b0f5f3 100644 --- a/tests/integration/concurrency.go +++ b/tests/integration/concurrency.go @@ -87,13 +87,11 @@ func (ct *TestState) process() { if err := ct.sem.Acquire(ct.ctx, 1); err != nil { continue } - ct.wg.Add(1) - go func() { + ct.wg.Go(func() { // Run test and release semaphore once done fn(ct.conf) ct.sem.Release(1) - ct.wg.Done() - }() + }) } } } diff --git a/tests/integration/output.go b/tests/integration/output.go index 788cd00a..a0b295f4 100644 --- a/tests/integration/output.go +++ b/tests/integration/output.go @@ -32,17 +32,17 @@ var ( FailCount atomic.Uint32 ) -func runF(format string, a ...interface{}) { +func runF(format string, a ...any) { RunCount.Add(1) fmt.Printf(colorCyan+"RUN "+colorReset+format+"\n", a...) } -func failF(format string, a ...interface{}) { +func failF(format string, a ...any) { FailCount.Add(1) fmt.Printf(colorRed+"FAIL "+colorReset+format+"\n", a...) } -func passF(format string, a ...interface{}) { +func passF(format string, a ...any) { PassCount.Add(1) fmt.Printf(colorGreen+"PASS "+colorReset+format+"\n", a...) } diff --git a/tests/integration/utils.go b/tests/integration/utils.go index 2091b2e3..b3296144 100644 --- a/tests/integration/utils.go +++ b/tests/integration/utils.go @@ -1886,7 +1886,6 @@ func cleanupLockedObjects(client *s3.Client, bucket string, objs []objToDelete) sem := semaphore.NewWeighted(maxDelObjWorkers) for _, obj := range objs { - obj := obj // capture loop variable // Acquire worker slot before processing an object if err := sem.Acquire(ctx, 1); err != nil { @@ -2417,12 +2416,12 @@ func extractSignature(req *http.Request) ([]byte, error) { authHdr := req.Header.Get("Authorization") - i := strings.Index(authHdr, key) - if i == -1 { + _, after, ok := strings.Cut(authHdr, key) + if !ok { return nil, errors.New("signature not found") } - sig := authHdr[i+len(key):] + sig := after return hex.DecodeString(sig) } diff --git a/tests/rest_scripts/command/payloadChunked.go b/tests/rest_scripts/command/payloadChunked.go index 16a9ee41..960d1ae4 100644 --- a/tests/rest_scripts/command/payloadChunked.go +++ b/tests/rest_scripts/command/payloadChunked.go @@ -22,12 +22,7 @@ func (c *PayloadChunked) getChunkedPayloadContentLength(additionalChunkHeaderSiz var sizeIdx int64 var contentLength int64 for sizeIdx = 0; sizeIdx < payloadSize; sizeIdx += c.chunkSize { - var endIdx int64 - if sizeIdx+c.chunkSize < payloadSize { - endIdx = sizeIdx + c.chunkSize - } else { - endIdx = payloadSize - } + endIdx := min(sizeIdx+c.chunkSize, payloadSize) hexSize := fmt.Sprintf("%x", endIdx-sizeIdx) contentLength += int64(len(hexSize)) + additionalChunkHeaderSize + (endIdx - sizeIdx) + 2 } diff --git a/tests/rest_scripts/command/putBucketCorsCommand.go b/tests/rest_scripts/command/putBucketCorsCommand.go index 31fd929e..b773cdbd 100644 --- a/tests/rest_scripts/command/putBucketCorsCommand.go +++ b/tests/rest_scripts/command/putBucketCorsCommand.go @@ -56,8 +56,8 @@ func NewPutBucketCORSCommand(command *S3Command, ruleStrings []string) (*S3Comma func assembleCORSRule(ruleString string) (*CORSRule, error) { corsRule := &CORSRule{} - ruleComponents := strings.Split(ruleString, ";") - for _, component := range ruleComponents { + ruleComponents := strings.SplitSeq(ruleString, ";") + for component := range ruleComponents { componentSegments := strings.Split(component, "=") switch componentSegments[0] { case AllowedMethods: diff --git a/tests/rest_scripts/generateCommand.go b/tests/rest_scripts/generateCommand.go index 65d12dbf..0b8560b5 100644 --- a/tests/rest_scripts/generateCommand.go +++ b/tests/rest_scripts/generateCommand.go @@ -77,8 +77,8 @@ func (r *restParams) String() string { func (r *restParams) Set(value string) error { *r = make(map[string]string) - pairs := strings.Split(value, *paramSeparator) - for _, pair := range pairs { + pairs := strings.SplitSeq(value, *paramSeparator) + for pair := range pairs { kv := strings.SplitN(pair, ":", 2) if len(kv) != 2 { return fmt.Errorf("invalid key-value pair: %s", pair) diff --git a/tests/rest_scripts/logger/logging.go b/tests/rest_scripts/logger/logging.go index 4e108408..0a9ab543 100644 --- a/tests/rest_scripts/logger/logging.go +++ b/tests/rest_scripts/logger/logging.go @@ -8,7 +8,7 @@ import ( var Debug *bool var LogFile *string -func PrintDebug(format string, args ...interface{}) { +func PrintDebug(format string, args ...any) { if *Debug { if *LogFile != "" { logFile, err := os.OpenFile(*LogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) @@ -22,7 +22,7 @@ func PrintDebug(format string, args ...interface{}) { } } -func LogFatal(format string, args ...interface{}) { +func LogFatal(format string, args ...any) { PrintDebug(format, args...) os.Exit(1) } diff --git a/webui/webserver.go b/webui/webserver.go index ff0dfcc6..c4146157 100644 --- a/webui/webserver.go +++ b/webui/webserver.go @@ -138,7 +138,7 @@ func (s *Server) handleIndexHTML(c *fiber.Ctx) error { adminGateways = s.config.Gateways } - configJSON, err := json.Marshal(map[string]interface{}{ + configJSON, err := json.Marshal(map[string]any{ "gateways": s.config.Gateways, "adminGateways": adminGateways, "defaultRegion": s.config.Region,