diff --git a/common/go.mod b/common/go.mod index 58ab4ecc7a..47117e06df 100644 --- a/common/go.mod +++ b/common/go.mod @@ -2,7 +2,7 @@ module go.podman.io/common // Warning: Ensure the "go" and "toolchain" versions match exactly to prevent unwanted auto-updates -go 1.23.3 +go 1.24.0 require ( github.com/BurntSushi/toml v1.5.0 diff --git a/common/libimage/copier.go b/common/libimage/copier.go index e81dfaf0f8..3c7d538104 100644 --- a/common/libimage/copier.go +++ b/common/libimage/copier.go @@ -9,6 +9,7 @@ import ( "io" "net" "os" + "slices" "strings" "time" @@ -396,7 +397,7 @@ func (c *Copier) copyInternal(ctx context.Context, source, destination types.Ima // TimeoutStartSec=, the service manager will allow the service to continue to start, provided the // service repeats "EXTEND_TIMEOUT_USEC=..." within the interval specified until the service startup // status is finished by "READY=1"." - extendValue := []byte(fmt.Sprintf("EXTEND_TIMEOUT_USEC=%d", extension.Microseconds())) + extendValue := fmt.Appendf(nil, "EXTEND_TIMEOUT_USEC=%d", extension.Microseconds()) extendTimeout := func() { if _, err := conn.Write(extendValue); err != nil { logrus.Errorf("Increasing EXTEND_TIMEOUT_USEC failed: %v", err) @@ -555,11 +556,9 @@ func checkRegistrySourcesAllows(dest types.ImageReference) (insecure *bool, err return nil, fmt.Errorf("registry %q denied by policy: not in allowed registries list (%s)", reference.Domain(dref), registrySources) } - for _, insecureDomain := range sources.InsecureRegistries { - if insecureDomain == reference.Domain(dref) { - insecure := true - return &insecure, nil - } + if slices.Contains(sources.InsecureRegistries, reference.Domain(dref)) { + insecure := true + return &insecure, nil } return nil, nil diff --git a/common/libimage/filter/filter.go b/common/libimage/filter/filter.go index 2f3f03baa4..b3be95d57a 100644 --- a/common/libimage/filter/filter.go +++ b/common/libimage/filter/filter.go @@ -24,25 +24,25 @@ type SearchFilter struct { func ParseSearchFilter(filter []string) (*SearchFilter, error) { sFilter := new(SearchFilter) for _, f := range filter { - arr := strings.SplitN(f, "=", 2) - switch arr[0] { + keyword, value, ok := strings.Cut(f, "=") + switch keyword { case define.SearchFilterStars: - if len(arr) < 2 { + if !ok { return nil, fmt.Errorf("invalid filter %q, should be stars=", filter) } - stars, err := strconv.Atoi(arr[1]) + stars, err := strconv.Atoi(value) if err != nil { return nil, fmt.Errorf("incorrect value type for stars filter: %w", err) } sFilter.Stars = stars case define.SearchFilterAutomated: - if len(arr) == 2 && arr[1] == "false" { + if ok && value == "false" { sFilter.IsAutomated = types.OptionalBoolFalse } else { sFilter.IsAutomated = types.OptionalBoolTrue } case define.SearchFilterOfficial: - if len(arr) == 2 && arr[1] == "false" { + if ok && value == "false" { sFilter.IsOfficial = types.OptionalBoolFalse } else { sFilter.IsOfficial = types.OptionalBoolTrue diff --git a/common/libimage/filters.go b/common/libimage/filters.go index dd55713c8d..a40abfe070 100644 --- a/common/libimage/filters.go +++ b/common/libimage/filters.go @@ -89,18 +89,16 @@ func (r *Runtime) compileImageFilters(ctx context.Context, options *ListImagesOp var key, value string var filter filterFunc negate := false - split := strings.SplitN(f, "!=", 2) - if len(split) == 2 { + key, value, ok := strings.Cut(f, "!=") + if ok { negate = true } else { - split = strings.SplitN(f, "=", 2) - if len(split) != 2 { + key, value, ok = strings.Cut(f, "=") + if !ok { return nil, false, fmt.Errorf(filterInvalidValue, f) } } - key = split[0] - value = split[1] switch key { case "after", "since": img, err := r.time(key, value) diff --git a/common/libimage/image.go b/common/libimage/image.go index d0eb1b4c0e..32995968e7 100644 --- a/common/libimage/image.go +++ b/common/libimage/image.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "path/filepath" + "slices" "sort" "strings" "time" @@ -173,12 +174,7 @@ func (i *Image) Digests() []digest.Digest { // hasDigest returns whether the specified value matches any digest of the // image. func (i *Image) hasDigest(wantedDigest digest.Digest) bool { - for _, d := range i.Digests() { - if d == wantedDigest { - return true - } - } - return false + return slices.Contains(i.Digests(), wantedDigest) } // containsDigestPrefix returns whether the specified value matches any digest of the @@ -638,16 +634,9 @@ func (i *Image) Untag(name string) error { name = ref.String() - foundName := false - for _, n := range i.Names() { - if n == name { - foundName = true - break - } - } // Return an error if the name is not found, the c/storage // RemoveNames() API does not create one if no match is found. - if !foundName { + if !slices.Contains(i.Names(), name) { return fmt.Errorf("%s: %w", name, errTagUnknown) } diff --git a/common/libimage/image_config.go b/common/libimage/image_config.go index 6c6bb063e6..a34bc3be92 100644 --- a/common/libimage/image_config.go +++ b/common/libimage/image_config.go @@ -40,17 +40,17 @@ func ImageConfigFromChanges(changes []string) (*ImageConfig, error) { // nolint: for _, change := range changes { // First, let's assume proper Dockerfile format - space // separator between instruction and value - split := strings.SplitN(change, " ", 2) + outerKey, value, ok := strings.Cut(change, " ") - if len(split) != 2 { - split = strings.SplitN(change, "=", 2) - if len(split) != 2 { + if !ok { + outerKey, value, ok = strings.Cut(change, "=") + if !ok { return nil, fmt.Errorf("invalid change %q - must be formatted as KEY VALUE", change) } } - outerKey := strings.ToUpper(strings.TrimSpace(split[0])) - value := strings.TrimSpace(split[1]) + outerKey = strings.ToUpper(strings.TrimSpace(outerKey)) + value = strings.TrimSpace(value) switch outerKey { case "USER": // Assume literal contents are the user. @@ -96,18 +96,11 @@ func ImageConfigFromChanges(changes []string) (*ImageConfig, error) { // nolint: // For now: we only support key=value // We will attempt to strip quotation marks if present. - var key, val string - - splitEnv := strings.SplitN(value, "=", 2) - key = splitEnv[0] + key, val, _ := strings.Cut(value, "=") // val is "" if there is no "=" // We do need a key if key == "" { return nil, fmt.Errorf("invalid change %q - ENV must have at least one argument", change) } - // Perfectly valid to not have a value - if len(splitEnv) == 2 { - val = splitEnv[1] - } if strings.HasPrefix(key, `"`) && strings.HasSuffix(key, `"`) { key = strings.TrimPrefix(strings.TrimSuffix(key, `"`), `"`) @@ -192,17 +185,11 @@ func ImageConfigFromChanges(changes []string) (*ImageConfig, error) { // nolint: // Potentially problematic: LABEL might theoretically // allow an = in the key? If people really do this, we // may need to investigate more advanced parsing. - var ( - key, val string - ) - - splitLabel := strings.SplitN(value, "=", 2) + key, val, ok := strings.Cut(value, "=") // Unlike ENV, LABEL must have a value - if len(splitLabel) != 2 { + if !ok { return nil, fmt.Errorf("invalid change %q - LABEL must be formatted key=value", change) } - key = splitLabel[0] - val = splitLabel[1] if strings.HasPrefix(key, `"`) && strings.HasSuffix(key, `"`) { key = strings.TrimPrefix(strings.TrimSuffix(key, `"`), `"`) diff --git a/common/libimage/manifest_list.go b/common/libimage/manifest_list.go index 1aa31b1d79..f084bbe55f 100644 --- a/common/libimage/manifest_list.go +++ b/common/libimage/manifest_list.go @@ -303,10 +303,8 @@ func (m *ManifestList) LookupInstance(ctx context.Context, architecture, os, var } for _, image := range allImages { - for _, imageDigest := range append(image.Digests(), image.Digest()) { - if imageDigest == instanceDigest { - return image, nil - } + if slices.Contains(image.Digests(), instanceDigest) || instanceDigest == image.Digest() { + return image, nil } } diff --git a/common/libimage/manifests/manifests.go b/common/libimage/manifests/manifests.go index b99d8fc2c2..3caff540dd 100644 --- a/common/libimage/manifests/manifests.go +++ b/common/libimage/manifests/manifests.go @@ -252,10 +252,8 @@ func (l *list) InstanceByFile(file string) (digest.Digest, error) { return "", err } for instanceDigest, files := range l.artifacts.Files { - for _, file := range files { - if file == abs { - return instanceDigest, nil - } + if slices.Contains(files, abs) { + return instanceDigest, nil } } return "", os.ErrNotExist diff --git a/common/libimage/pull.go b/common/libimage/pull.go index 32a391fea6..1183311f4c 100644 --- a/common/libimage/pull.go +++ b/common/libimage/pull.go @@ -253,8 +253,8 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, storageName = imageName case ociTransport.Transport.Name(): - split := strings.SplitN(ref.StringWithinTransport(), ":", 2) - if len(split) == 1 || split[1] == "" { + _, refName, ok := strings.Cut(ref.StringWithinTransport(), ":") + if !ok || refName == "" { // Same trick as for the dir transport: we cannot use // the path to a directory as the name. storageName, err = getImageID(ctx, ref, nil) @@ -263,7 +263,7 @@ func (r *Runtime) copyFromDefault(ctx context.Context, ref types.ImageReference, } imageName = "sha256:" + storageName[1:] } else { // If the OCI-reference includes an image reference, use it - storageName = split[1] + storageName = refName imageName = storageName } diff --git a/common/libimage/search.go b/common/libimage/search.go index 513852ec85..cda0930672 100644 --- a/common/libimage/search.go +++ b/common/libimage/search.go @@ -94,11 +94,11 @@ func (r *Runtime) Search(ctx context.Context, term string, options *SearchOption // that we cannot use the reference parser from the containers/image // library as the search term may container arbitrary input such as // wildcards. See bugzilla.redhat.com/show_bug.cgi?id=1846629. - spl := strings.SplitN(term, "/", 2) + perhapsRegistry, perhapsTerm, ok := strings.Cut(term, "/") switch { - case len(spl) > 1: - searchRegistries = []string{spl[0]} - term = spl[1] + case ok: + searchRegistries = []string{perhapsRegistry} + term = perhapsTerm case len(options.Registries) > 0: searchRegistries = options.Registries default: @@ -203,15 +203,9 @@ func (r *Runtime) searchImageInRegistry(ctx context.Context, term, registry stri // limit is the number of results to output // if the total number of results is less than the limit, output all // if the limit has been set by the user, output those number of queries - limit = searchMaxQueries - if len(results) < limit { - limit = len(results) - } + limit = min(len(results), searchMaxQueries) if options.Limit != 0 { - limit = len(results) - if options.Limit < len(results) { - limit = options.Limit - } + limit = min(len(results), options.Limit) } paramsArr := []SearchResult{} @@ -264,15 +258,9 @@ func searchRepositoryTags(ctx context.Context, sys *types.SystemContext, registr if err != nil { return nil, fmt.Errorf("getting repository tags: %v", err) } - limit := searchMaxQueries - if len(tags) < limit { - limit = len(tags) - } + limit := min(len(tags), searchMaxQueries) if options.Limit != 0 { - limit = len(tags) - if options.Limit < limit { - limit = options.Limit - } + limit = min(len(tags), options.Limit) } paramsArr := []SearchResult{} for i := range limit { diff --git a/common/libnetwork/cni/cni_conversion.go b/common/libnetwork/cni/cni_conversion.go index 7b5d4eab75..c89a867453 100644 --- a/common/libnetwork/cni/cni_conversion.go +++ b/common/libnetwork/cni/cni_conversion.go @@ -355,9 +355,7 @@ func convertSpecgenPortsToCNIPorts(ports []types.PortMapping) ([]cniPortMapEntry if port.Protocol == "" { return nil, errors.New("port protocol should not be empty") } - protocols := strings.Split(port.Protocol, ",") - - for _, protocol := range protocols { + for protocol := range strings.SplitSeq(port.Protocol, ",") { if !slices.Contains([]string{"tcp", "udp", "sctp"}, protocol) { return nil, fmt.Errorf("unknown port protocol %s", protocol) } diff --git a/common/libnetwork/cni/run.go b/common/libnetwork/cni/run.go index ef2b158f10..7877891a9a 100644 --- a/common/libnetwork/cni/run.go +++ b/common/libnetwork/cni/run.go @@ -177,9 +177,9 @@ func getRuntimeConfig(netns, conName, conID, networkName string, ports []cniPort } // Propagate environment CNI_ARGS - for _, kvpairs := range strings.Split(os.Getenv("CNI_ARGS"), ";") { - if keyval := strings.SplitN(kvpairs, "=", 2); len(keyval) == 2 { - rt.Args = append(rt.Args, [2]string{keyval[0], keyval[1]}) + for kvpairs := range strings.SplitSeq(os.Getenv("CNI_ARGS"), ";") { + if key, val, ok := strings.Cut(kvpairs, "="); ok { + rt.Args = append(rt.Args, [2]string{key, val}) } } diff --git a/common/libnetwork/etchosts/hosts.go b/common/libnetwork/etchosts/hosts.go index dbde190fe0..2e3ccaa27c 100644 --- a/common/libnetwork/etchosts/hosts.go +++ b/common/libnetwork/etchosts/hosts.go @@ -236,24 +236,23 @@ func checkIfEntryExists(current HostEntry, entries HostEntries) bool { func parseExtraHosts(extraHosts []string, hostContainersInternalIP string) (HostEntries, error) { entries := make(HostEntries, 0, len(extraHosts)) for _, entry := range extraHosts { - values := strings.SplitN(entry, ":", 2) - if len(values) != 2 { + namesString, ip, ok := strings.Cut(entry, ":") + if !ok { return nil, fmt.Errorf("unable to parse host entry %q: incorrect format", entry) } - if values[0] == "" { + if namesString == "" { return nil, fmt.Errorf("hostname in host entry %q is empty", entry) } - if values[1] == "" { + if ip == "" { return nil, fmt.Errorf("IP address in host entry %q is empty", entry) } - ip := values[1] - if values[1] == HostGateway { + if ip == HostGateway { if hostContainersInternalIP == "" { return nil, fmt.Errorf("unable to replace %q of host entry %q: host containers internal IP address is empty", HostGateway, entry) } ip = hostContainersInternalIP } - names := strings.Split(values[0], ";") + names := strings.Split(namesString, ";") e := HostEntry{IP: ip, Names: names} entries = append(entries, e) } diff --git a/common/libnetwork/pasta/pasta_linux.go b/common/libnetwork/pasta/pasta_linux.go index 33043e8275..a72e7adfde 100644 --- a/common/libnetwork/pasta/pasta_linux.go +++ b/common/libnetwork/pasta/pasta_linux.go @@ -212,8 +212,7 @@ func createPastaArgs(opts *SetupOptions) ([]string, []string, []string, error) { } for _, i := range opts.Ports { - protocols := strings.Split(i.Protocol, ",") - for _, protocol := range protocols { + for protocol := range strings.SplitSeq(i.Protocol, ",") { var addr string if i.HostIP != "" { diff --git a/common/libnetwork/resolvconf/resolvconf.go b/common/libnetwork/resolvconf/resolvconf.go index 5724dfcc2e..a3647528fc 100644 --- a/common/libnetwork/resolvconf/resolvconf.go +++ b/common/libnetwork/resolvconf/resolvconf.go @@ -76,9 +76,8 @@ func filterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) []b // getLines parses input into lines and strips away comments. func getLines(input []byte) [][]byte { - lines := bytes.Split(input, []byte("\n")) var output [][]byte - for _, currentLine := range lines { + for currentLine := range bytes.SplitSeq(input, []byte("\n")) { commentIndex := bytes.Index(currentLine, []byte("#")) if commentIndex == -1 { output = append(output, currentLine) diff --git a/common/libnetwork/slirp4netns/slirp4netns.go b/common/libnetwork/slirp4netns/slirp4netns.go index c4020cae25..083a4e5fcc 100644 --- a/common/libnetwork/slirp4netns/slirp4netns.go +++ b/common/libnetwork/slirp4netns/slirp4netns.go @@ -124,11 +124,10 @@ func parseNetworkOptions(config *config.Config, extraOptions []string) (*network enableIPv6: true, } for _, o := range options { - parts := strings.SplitN(o, "=", 2) - if len(parts) < 2 { + option, value, ok := strings.Cut(o, "=") + if !ok { return nil, fmt.Errorf("unknown option for slirp4netns: %q", o) } - option, value := parts[0], parts[1] switch option { case "cidr": ipv4, _, err := net.ParseCIDR(value) @@ -639,8 +638,7 @@ func setupRootlessPortMappingViaSlirp(ports []types.PortMapping, cmd *exec.Cmd, // for each port we want to add we need to open a connection to the slirp4netns control socket // and send the add_hostfwd command. for _, port := range ports { - protocols := strings.Split(port.Protocol, ",") - for _, protocol := range protocols { + for protocol := range strings.SplitSeq(port.Protocol, ",") { hostIP := port.HostIP if hostIP == "" { hostIP = "0.0.0.0" diff --git a/common/pkg/apparmor/apparmor_linux.go b/common/pkg/apparmor/apparmor_linux.go index 9b0c766653..d677729d8c 100644 --- a/common/pkg/apparmor/apparmor_linux.go +++ b/common/pkg/apparmor/apparmor_linux.go @@ -208,14 +208,14 @@ func parseAAParserVersion(output string) (int, error) { // AppArmor parser version 2.9.1 // Copyright (C) 1999-2008 Novell Inc. // Copyright 2009-2012 Canonical Ltd. - lines := strings.SplitN(output, "\n", 2) - words := strings.Split(lines[0], " ") + firstLine, _, _ := strings.Cut(output, "\n") + words := strings.Split(firstLine, " ") version := words[len(words)-1] // trim "-beta1" suffix from version="3.0.0-beta1" if exists - version = strings.SplitN(version, "-", 2)[0] + version, _, _ = strings.Cut(version, "-") // also trim "~..." suffix used historically (https://gitlab.com/apparmor/apparmor/-/commit/bca67d3d27d219d11ce8c9cc70612bd637f88c10) - version = strings.SplitN(version, "~", 2)[0] + version, _, _ = strings.Cut(version, "~") // split by major minor version v := strings.Split(version, ".") diff --git a/common/pkg/auth/auth.go b/common/pkg/auth/auth.go index 8cb9f3a633..b6f7228546 100644 --- a/common/pkg/auth/auth.go +++ b/common/pkg/auth/auth.go @@ -233,8 +233,7 @@ func parseCredentialsKey(arg string, acceptRepositories bool) (key, registry str return "", "", err } - split := strings.Split(key, "/") - registry = split[0] + registry, _, _ = strings.Cut(key, "/") if !acceptRepositories { return registry, registry, nil diff --git a/common/pkg/cgroups/cgroups_linux.go b/common/pkg/cgroups/cgroups_linux.go index 322436a93e..1c66a8d9cc 100644 --- a/common/pkg/cgroups/cgroups_linux.go +++ b/common/pkg/cgroups/cgroups_linux.go @@ -111,7 +111,7 @@ func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) if err != nil { return nil, fmt.Errorf("failed while reading controllers for cgroup v2: %w", err) } - for _, controllerName := range strings.Fields(string(controllersFileBytes)) { + for controllerName := range strings.FieldsSeq(string(controllersFileBytes)) { c := controller{ name: controllerName, symlink: false, @@ -197,10 +197,9 @@ func getCgroupPathForCurrentProcess() (string, error) { s := bufio.NewScanner(f) for s.Scan() { text := s.Text() - procEntries := strings.SplitN(text, "::", 2) // set process cgroupPath only if entry is valid - if len(procEntries) > 1 { - cgroupPath = procEntries[1] + if _, p, ok := strings.Cut(text, "::"); ok { + cgroupPath = p } } if err := s.Err(); err != nil { @@ -278,10 +277,10 @@ func readFileByKeyAsUint64(path, key string) (uint64, error) { if err != nil { return 0, err } - for _, line := range strings.Split(string(content), "\n") { - fields := strings.SplitN(line, " ", 2) - if fields[0] == key { - v := cleanString(fields[1]) + for line := range strings.SplitSeq(string(content), "\n") { + k, v, _ := strings.Cut(line, " ") + if k == key { + v := cleanString(v) if v == "max" { return math.MaxUint64, nil } @@ -684,7 +683,7 @@ func readAcctList(ctr *CgroupControl, name string) ([]uint64, error) { return nil, err } r := []uint64{} - for _, s := range strings.Split(string(data), " ") { + for s := range strings.SplitSeq(string(data), " ") { s = cleanString(s) if s == "" { break @@ -874,7 +873,7 @@ func rmDirRecursively(path string) error { } // kill all the processes that are still part of the cgroup if procs, err := os.ReadFile(filepath.Join(path, "cgroup.procs")); err == nil { - for _, pidS := range strings.Split(string(procs), "\n") { + for pidS := range strings.SplitSeq(string(procs), "\n") { if pid, err := strconv.Atoi(pidS); err == nil { _ = unix.Kill(pid, signal) } diff --git a/common/pkg/cgroups/systemd_linux.go b/common/pkg/cgroups/systemd_linux.go index 4ae3c0af46..c0bc6d9d38 100644 --- a/common/pkg/cgroups/systemd_linux.go +++ b/common/pkg/cgroups/systemd_linux.go @@ -280,7 +280,7 @@ func resourcesToProps(res *cgroups.Resources, v2 bool) (map[string]uint64, map[s func rangeToBits(str string) ([]byte, error) { bits := new(big.Int) - for _, r := range strings.Split(str, ",") { + for r := range strings.SplitSeq(str, ",") { // allow extra spaces around r = strings.TrimSpace(r) // allow empty elements (extra commas) diff --git a/common/pkg/cgroups/utils_linux.go b/common/pkg/cgroups/utils_linux.go index 2143358e67..a1b18a9695 100644 --- a/common/pkg/cgroups/utils_linux.go +++ b/common/pkg/cgroups/utils_linux.go @@ -270,7 +270,7 @@ func MoveUnderCgroup(cgroup, subtree string, processes []uint32) error { if err != nil { return err } - for _, pid := range bytes.Split(processesData, []byte("\n")) { + for pid := range bytes.SplitSeq(processesData, []byte("\n")) { if len(pid) == 0 { continue } diff --git a/common/pkg/completion/completion.go b/common/pkg/completion/completion.go index fef95b7f35..f487d68630 100644 --- a/common/pkg/completion/completion.go +++ b/common/pkg/completion/completion.go @@ -72,7 +72,7 @@ func autocompleteSubIDName(filename string) ([]string, cobra.ShellCompDirective) var names []string scanner := bufio.NewScanner(file) for scanner.Scan() { - name := strings.SplitN(scanner.Text(), ":", 2)[0] + name, _, _ := strings.Cut(scanner.Text(), ":") names = append(names, name) } if err = scanner.Err(); err != nil { diff --git a/common/pkg/config/config.go b/common/pkg/config/config.go index 9d5a339375..2a11ccb005 100644 --- a/common/pkg/config/config.go +++ b/common/pkg/config/config.go @@ -761,9 +761,9 @@ func (c *Config) CheckCgroupsAndAdjustConfig() { } } } else { - for _, part := range strings.Split(session, ",") { - if strings.HasPrefix(part, "unix:path=") { - err := fileutils.Exists(strings.TrimPrefix(part, "unix:path=")) + for part := range strings.SplitSeq(session, ",") { + if path, ok := strings.CutPrefix(part, "unix:path="); ok { + err := fileutils.Exists(path) hasSession = err == nil break } @@ -1158,17 +1158,17 @@ func (c *Config) ImageCopyTmpDir() (string, error) { // setupEnv sets the environment variables for the engine. func (c *Config) setupEnv() error { for _, env := range c.Engine.Env.Get() { - splitEnv := strings.SplitN(env, "=", 2) - if len(splitEnv) != 2 { + key, value, ok := strings.Cut(env, "=") + if !ok { logrus.Warnf("invalid environment variable for engine %s, valid configuration is KEY=value pair", env) continue } // skip if the env is already defined - if _, ok := os.LookupEnv(splitEnv[0]); ok { - logrus.Debugf("environment variable %s is already defined, skip the settings from containers.conf", splitEnv[0]) + if _, ok := os.LookupEnv(key); ok { + logrus.Debugf("environment variable %s is already defined, skip the settings from containers.conf", key) continue } - if err := os.Setenv(splitEnv[0], splitEnv[1]); err != nil { + if err := os.Setenv(key, value); err != nil { return err } } @@ -1202,7 +1202,7 @@ func (e eventsLogMaxSize) MarshalText() ([]byte, error) { v := []byte{} return v, nil } - return []byte(fmt.Sprintf("%d", e)), nil + return fmt.Appendf(nil, "%d", e), nil } func ValidateImageVolumeMode(mode string) error { diff --git a/common/pkg/config/connections_test.go b/common/pkg/config/connections_test.go index 8021d23056..b2d52cbbd9 100644 --- a/common/pkg/config/connections_test.go +++ b/common/pkg/config/connections_test.go @@ -76,7 +76,7 @@ var _ = Describe("Connections conf", func() { count := 50 wg := sync.WaitGroup{} wg.Add(count) - for i := 0; i < count; i++ { + for range count { go func() { defer wg.Done() err := EditConnectionConfig(func(cfg *ConnectionsFile) error { diff --git a/common/pkg/hooks/exec/exec_test.go b/common/pkg/hooks/exec/exec_test.go index b7d80c60b9..5c6f481379 100644 --- a/common/pkg/hooks/exec/exec_test.go +++ b/common/pkg/hooks/exec/exec_test.go @@ -72,16 +72,13 @@ func TestRunFailedStart(t *testing.T) { func parseEnvironment(input string) (env map[string]string, err error) { env = map[string]string{} - lines := strings.Split(input, "\n") - for i, line := range lines { - if line == "" && i == len(lines)-1 { - continue // no content after the terminal newline - } - keyValue := strings.SplitN(line, "=", 2) - if len(keyValue) < 2 { + input = strings.TrimSuffix(input, "\n") // strip the terminal newline, if any + for line := range strings.SplitSeq(input, "\n") { + key, value, ok := strings.Cut(line, "=") + if !ok { return env, fmt.Errorf("no = in environment line: %q", line) } - env[keyValue[0]] = keyValue[1] + env[key] = value } for _, key := range unavoidableEnvironmentKeys { delete(env, key) diff --git a/common/pkg/hooks/exec/runtimeconfigfilter_test.go b/common/pkg/hooks/exec/runtimeconfigfilter_test.go index 0553672ac4..ba7daa248e 100644 --- a/common/pkg/hooks/exec/runtimeconfigfilter_test.go +++ b/common/pkg/hooks/exec/runtimeconfigfilter_test.go @@ -13,7 +13,8 @@ import ( ) func TestRuntimeConfigFilter(t *testing.T) { - unexpectedEndOfJSONInput := json.Unmarshal([]byte("{\n"), nil) //nolint:govet // this should force the error + var discardedParsingDestination map[string]any + unexpectedEndOfJSONInput := json.Unmarshal([]byte("{\n"), &discardedParsingDestination) // this should force the error fileMode := os.FileMode(0o600) rootUint32 := uint32(0) binUser := int(1) diff --git a/common/pkg/hooks/hooks_test.go b/common/pkg/hooks/hooks_test.go index ba4bf4410e..5db173f9d1 100644 --- a/common/pkg/hooks/hooks_test.go +++ b/common/pkg/hooks/hooks_test.go @@ -31,7 +31,7 @@ func TestGoodNew(t *testing.T) { if i == 0 { extraStages = ", \"poststart\", \"poststop\"" } - err := os.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": %d}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"%s]}", path, i+1, extraStages)), 0o644) + err := os.WriteFile(jsonPath, fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": %d}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"%s]}", path, i+1, extraStages), 0o644) if err != nil { t.Fatal(err) } diff --git a/common/pkg/hooks/monitor_test.go b/common/pkg/hooks/monitor_test.go index ef82d3f6cb..cdb86902f5 100644 --- a/common/pkg/hooks/monitor_test.go +++ b/common/pkg/hooks/monitor_test.go @@ -32,7 +32,7 @@ func TestMonitorOneDirGood(t *testing.T) { jsonPath := filepath.Join(dir, "a.json") t.Run("good-addition", func(t *testing.T) { - err = os.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\", \"poststart\", \"poststop\"]}", path)), 0o644) + err = os.WriteFile(jsonPath, fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\", \"poststart\", \"poststop\"]}", path), 0o644) if err != nil { t.Fatal(err) } @@ -126,7 +126,7 @@ func TestMonitorTwoDirGood(t *testing.T) { } fallbackPath := filepath.Join(fallbackDir, "a.json") - fallbackJSON := []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)) + fallbackJSON := fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path) fallbackInjected := &rspec.Hooks{ CreateRuntime: []rspec.Hook{ { @@ -153,7 +153,7 @@ func TestMonitorTwoDirGood(t *testing.T) { }) primaryPath := filepath.Join(primaryDir, "a.json") - primaryJSON := []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": 1}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)) + primaryJSON := fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\", \"timeout\": 1}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path) one := 1 primaryInjected := &rspec.Hooks{ CreateRuntime: []rspec.Hook{ diff --git a/common/pkg/hooks/read_test.go b/common/pkg/hooks/read_test.go index 2cf5ce515c..bde79f41b8 100644 --- a/common/pkg/hooks/read_test.go +++ b/common/pkg/hooks/read_test.go @@ -32,7 +32,7 @@ func TestGoodFile(t *testing.T) { dir := t.TempDir() jsonPath := filepath.Join(dir, "hook.json") - err := os.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)), 0o644) + err := os.WriteFile(jsonPath, fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path), 0o644) if err != nil { t.Fatal(err) } @@ -121,7 +121,7 @@ func TestGoodDir(t *testing.T) { } jsonPath := filepath.Join(dir, "a.json") - err = os.WriteFile(jsonPath, []byte(fmt.Sprintf("{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path)), 0o644) + err = os.WriteFile(jsonPath, fmt.Appendf(nil, "{\"version\": \"1.0.0\", \"hook\": {\"path\": \"%s\"}, \"when\": {\"always\": true}, \"stages\": [\"prestart\"]}", path), 0o644) if err != nil { t.Fatal(err) } diff --git a/common/pkg/manifests/manifests.go b/common/pkg/manifests/manifests.go index 5198fc0ae6..6884c13d04 100644 --- a/common/pkg/manifests/manifests.go +++ b/common/pkg/manifests/manifests.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "maps" "os" "slices" "strings" @@ -238,9 +239,7 @@ func (l *list) SetAnnotations(instanceDigest *digest.Digest, annotations map[str if *a == nil { (*a) = make(map[string]string) } - for k, v := range annotations { - (*a)[k] = v - } + maps.Copy((*a), annotations) if len(*a) == 0 { *a = nil } @@ -259,9 +258,7 @@ func (l *list) Annotations(instanceDigest *digest.Digest) (map[string]string, er a = oci.Annotations } annotations := make(map[string]string) - for k, v := range a { - annotations[k] = v - } + maps.Copy(annotations, a) return annotations, nil } diff --git a/common/pkg/report/formatter.go b/common/pkg/report/formatter.go index dcc09fdb16..e05e9762f4 100644 --- a/common/pkg/report/formatter.go +++ b/common/pkg/report/formatter.go @@ -2,6 +2,7 @@ package report import ( "io" + "maps" "strings" "text/tabwriter" "text/template" @@ -109,12 +110,8 @@ func (f *Formatter) Parse(origin Origin, text string) (*Formatter, error) { // A default template function will be replaced if there is a key collision. func (f *Formatter) Funcs(funcMap template.FuncMap) *Formatter { m := make(template.FuncMap, len(DefaultFuncs)+len(funcMap)) - for k, v := range DefaultFuncs { - m[k] = v - } - for k, v := range funcMap { - m[k] = v - } + maps.Copy(m, DefaultFuncs) + maps.Copy(m, funcMap) f.template = f.template.Funcs(funcMap) return f } diff --git a/common/pkg/report/template.go b/common/pkg/report/template.go index bb6ce7bea5..a1113d869c 100644 --- a/common/pkg/report/template.go +++ b/common/pkg/report/template.go @@ -3,6 +3,7 @@ package report import ( "bytes" "encoding/json" + "maps" "reflect" "strings" "text/template" @@ -95,7 +96,7 @@ func truncateWithLength(source string, length int) string { // 3) --format 'table {{.ID}}' # includes headers func Headers(object any, overrides map[string]string) []map[string]string { value := reflect.ValueOf(object) - if value.Kind() == reflect.Ptr { + if value.Kind() == reflect.Pointer { value = value.Elem() } @@ -106,9 +107,7 @@ func Headers(object any, overrides map[string]string) []map[string]string { // Recurse to find field names from promoted structs if field.Type.Kind() == reflect.Struct && field.Anonymous { h := Headers(reflect.New(field.Type).Interface(), nil) - for k, v := range h[0] { - headers[k] = v - } + maps.Copy(headers, h[0]) continue } name := strings.Join(camelcase.Split(field.Name), " ") @@ -146,12 +145,8 @@ func (t *Template) Parse(text string) (*Template, error) { // A default template function will be replace if there is a key collision. func (t *Template) Funcs(funcMap FuncMap) *Template { m := make(FuncMap) - for k, v := range DefaultFuncs { - m[k] = v - } - for k, v := range funcMap { - m[k] = v - } + maps.Copy(m, DefaultFuncs) + maps.Copy(m, funcMap) return &Template{Template: t.Template.Funcs(template.FuncMap(m)), isTable: t.isTable} } diff --git a/common/pkg/secrets/shelldriver/shelldriver.go b/common/pkg/secrets/shelldriver/shelldriver.go index 5cf6aa48d2..c8b806d2a0 100644 --- a/common/pkg/secrets/shelldriver/shelldriver.go +++ b/common/pkg/secrets/shelldriver/shelldriver.go @@ -89,8 +89,7 @@ func (d *Driver) List() (secrets []string, err error) { return nil, err } - parts := bytes.Split(buf.Bytes(), []byte("\n")) - for _, part := range parts { + for part := range bytes.SplitSeq(buf.Bytes(), []byte("\n")) { id := strings.Trim(string(part), " \r\n") if len(id) > 0 { secrets = append(secrets, id) diff --git a/common/pkg/ssh/connection_golang.go b/common/pkg/ssh/connection_golang.go index 591e1a7575..c8e3c5bd85 100644 --- a/common/pkg/ssh/connection_golang.go +++ b/common/pkg/ssh/connection_golang.go @@ -166,8 +166,7 @@ func golangConnectionScp(options ConnectionScpOptions) (*ConnectionScpReport, er parent := filepath.Dir(remoteFile) path := string(filepath.Separator) - dirs := strings.Split(parent, path) - for _, dir := range dirs { + for dir := range strings.SplitSeq(parent, path) { path = filepath.Join(path, dir) // ignore errors due to most of the dirs already existing _ = sc.Mkdir(path) diff --git a/common/pkg/ssh/connection_native.go b/common/pkg/ssh/connection_native.go index 39127bbab4..a274db88ab 100644 --- a/common/pkg/ssh/connection_native.go +++ b/common/pkg/ssh/connection_native.go @@ -38,8 +38,8 @@ func nativeConnectionCreate(options ConnectionCreateOptions) error { return err } - if strings.Contains(uri.Host, "/run") { - uri.Host = strings.Split(uri.Host, "/run")[0] + if host, _, ok := strings.Cut(uri.Host, "/run"); ok { + uri.Host = host } conf, err := config.Default() if err != nil { @@ -114,8 +114,8 @@ func nativeConnectionExec(options ConnectionExecOptions, input io.Reader) (*Conn output := &bytes.Buffer{} errors := &bytes.Buffer{} - if strings.Contains(uri.Host, "/run") { - uri.Host = strings.Split(uri.Host, "/run")[0] + if host, _, ok := strings.Cut(uri.Host, "/run"); ok { + uri.Host = host } options.Args = append([]string{uri.User.String() + "@" + uri.Hostname()}, options.Args...) diff --git a/common/pkg/subscriptions/subscriptions.go b/common/pkg/subscriptions/subscriptions.go index a907ea6758..a8921941ba 100644 --- a/common/pkg/subscriptions/subscriptions.go +++ b/common/pkg/subscriptions/subscriptions.go @@ -144,15 +144,12 @@ func getMounts(filePath string) []string { } // getHostAndCtrDir separates the host:container paths. -func getMountsMap(path string) (string, string, error) { //nolint - arr := strings.SplitN(path, ":", 2) - switch len(arr) { - case 1: - return arr[0], arr[0], nil - case 2: - return arr[0], arr[1], nil - } - return "", "", fmt.Errorf("unable to get host and container dir from path: %s", path) +func getMountsMap(path string) (string, string) { + host, ctr, ok := strings.Cut(path, ":") + if !ok { + return path, path + } + return host, ctr } // Return true iff the system is in FIPS mode as determined by reading @@ -238,10 +235,7 @@ func addSubscriptionsFromMountsFile(filePath, mountLabel, containerRunDir string defaultMountsPaths := getMounts(filePath) mounts := make([]rspec.Mount, 0, len(defaultMountsPaths)) for _, path := range defaultMountsPaths { - hostDirOrFile, ctrDirOrFile, err := getMountsMap(path) - if err != nil { - return nil, err - } + hostDirOrFile, ctrDirOrFile := getMountsMap(path) // skip if the hostDirOrFile path doesn't exist fileInfo, err := os.Stat(hostDirOrFile) if err != nil { diff --git a/common/pkg/timetype/timestamp.go b/common/pkg/timetype/timestamp.go index 2fc99d0e39..ca404c84f3 100644 --- a/common/pkg/timetype/timestamp.go +++ b/common/pkg/timetype/timestamp.go @@ -117,19 +117,19 @@ func ParseTimestamps(value string, def int64) (secs, nanoSecs int64, err error) } func parseTimestamp(value string) (int64, int64, error) { - sa := strings.SplitN(value, ".", 2) - s, err := strconv.ParseInt(sa[0], 10, 64) + secStr, nsStr, ok := strings.Cut(value, ".") + s, err := strconv.ParseInt(secStr, 10, 64) if err != nil { return s, 0, err } - if len(sa) != 2 { + if !ok { return s, 0, nil } - n, err := strconv.ParseInt(sa[1], 10, 64) + n, err := strconv.ParseInt(nsStr, 10, 64) if err != nil { return s, n, err } // should already be in nanoseconds but just in case convert n to nanoseconds - n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1])))) + n = int64(float64(n) * math.Pow(float64(10), float64(9-len(nsStr)))) return s, n, nil } diff --git a/common/pkg/version/version.go b/common/pkg/version/version.go index 9b13f484d1..80261c125e 100644 --- a/common/pkg/version/version.go +++ b/common/pkg/version/version.go @@ -28,10 +28,9 @@ func queryPackageVersion(cmdArg ...string) string { switch cmdArg[0] { case "/usr/bin/dlocate": // can return multiple matches - l := strings.Split(output, "\n") - output = l[0] - r := strings.Split(output, ": ") - regexpFormat := `^..\s` + r[0] + `\s` + output, _, _ := strings.Cut(output, "\n") + r, _, _ := strings.Cut(output, ": ") + regexpFormat := `^..\s` + r + `\s` cmd = exec.Command(cmdArg[0], "-P", regexpFormat, "-l") cmd.Env = []string{"COLUMNS=160"} // show entire value // dlocate always returns exit code 1 for list command @@ -46,9 +45,9 @@ func queryPackageVersion(cmdArg ...string) string { } } case "/usr/bin/dpkg": - r := strings.Split(output, ": ") + r, _, _ := strings.Cut(output, ": ") queryFormat := `${Package}_${Version}_${Architecture}` - cmd = exec.Command("/usr/bin/dpkg-query", "-f", queryFormat, "-W", r[0]) + cmd = exec.Command("/usr/bin/dpkg-query", "-f", queryFormat, "-W", r) if outp, err := cmd.Output(); err == nil { output = string(outp) } diff --git a/go.work b/go.work index c1c26abbb3..f4e7f56966 100644 --- a/go.work +++ b/go.work @@ -1,4 +1,4 @@ -go 1.23.3 +go 1.24.0 use ( ./common diff --git a/go.work.sum b/go.work.sum index ca28494fb1..ef575b52c6 100644 --- a/go.work.sum +++ b/go.work.sum @@ -2,9 +2,11 @@ cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= chainguard.dev/go-grpc-kit v0.17.7/go.mod h1:JroMzTY9mdhKe/bvtyChgfECaNh80+bMZH3HS+TGXHw= chainguard.dev/sdk v0.1.29/go.mod h1:DqywTjZ5glB/gUCKkrecO0LywyfcAd5v7IPo2+d91qA= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A= cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= cloud.google.com/go/kms v1.20.4/go.mod h1:gPLsp1r4FblUgBYPOcvI/bUPpdMg2Jm1ZVKU4tQUfcc= @@ -22,6 +24,7 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.26.0 github.com/Microsoft/cosesign1go v1.4.0/go.mod h1:1La/HcGw19rRLhPW0S6u55K6LKfti+GQSgGCtrfhVe8= github.com/Microsoft/didx509go v0.0.3/go.mod h1:wWt+iQsLzn3011+VfESzznLIp/Owhuj7rLF7yLglYbk= github.com/Microsoft/go-winio v0.4.21/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= github.com/Microsoft/hcsshim v0.13.0/go.mod h1:9KWJ/8DgU+QzYGupX4tzMhRQE8h6w90lH6HAaclpEok= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= @@ -33,6 +36,7 @@ github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxk github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.32.8/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= @@ -65,6 +69,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= +github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins= github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= @@ -75,8 +80,11 @@ github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDX github.com/containerd/protobuild v0.3.0/go.mod h1:5mNMFKKAwCIAkFBPiOdtRx2KiQlyEJeMXnL5R1DsWu8= github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= +github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/containerd/typeurl/v2 v2.2.3/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= +github.com/containers/storage v1.59.1/go.mod h1:KoAYHnAjP3/cTsRS+mmWZGkufSY2GACiKQ4V3ZLQnR0= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= @@ -87,10 +95,14 @@ github.com/eggsampler/acme/v3 v3.6.0/go.mod h1:/qh0rKC/Dh7Jj+p4So7DbWmFNzC4dpcpK github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= +github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= @@ -101,10 +113,13 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/goadesign/goa v2.2.5+incompatible/go.mod h1:d/9lpuZBK7HFi/7O0oXfwvdoIl+nx2bwKqctZe/lQao= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -182,6 +197,7 @@ github.com/proglottis/gpgme v0.1.4/go.mod h1:5LoXMgpE4bttgwwdv9bLs/vwqv3qV7F4glE github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= @@ -199,6 +215,7 @@ github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIK github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -220,6 +237,7 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= +github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c/go.mod h1:GSDpFDD4TASObxvfZfvpZZ3OWHIUHMlhVWlkOe4ewVk= github.com/zmap/zlint/v3 v3.6.0/go.mod h1:NVgiIWssgzp0bNl8P4Gz94NHV2ep/4Jyj9V69uTmZyg= @@ -261,6 +279,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.217.0/go.mod h1:qMc2E8cBAbQlRypBTBWHklNJlaZZJBwDv81B1Iu8oSI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/image/docker/reference/normalize_test.go b/image/docker/reference/normalize_test.go index a21c800e14..efb771d351 100644 --- a/image/docker/reference/normalize_test.go +++ b/image/docker/reference/normalize_test.go @@ -474,7 +474,7 @@ func TestNormalizedSplitHostname(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } diff --git a/image/docker/reference/reference_test.go b/image/docker/reference/reference_test.go index ce1a11ddcb..21d62f170e 100644 --- a/image/docker/reference/reference_test.go +++ b/image/docker/reference/reference_test.go @@ -173,7 +173,7 @@ func TestReferenceParse(t *testing.T) { }, } for _, testcase := range referenceTestcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } @@ -267,7 +267,7 @@ func TestWithNameFailure(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } @@ -317,7 +317,7 @@ func TestSplitHostname(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } @@ -373,7 +373,7 @@ func TestSerialization(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } @@ -457,7 +457,7 @@ func TestSerialization(t *testing.T) { // Ensure t.Field is not implementing "Reference" directly, getting // around the Reference type system - var fieldInterface interface{} = t.Field + var fieldInterface any = t.Field if _, ok := fieldInterface.(Reference); ok { failf("field should not implement Reference interface") } @@ -499,7 +499,7 @@ func TestWithTag(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.name)+": "+format, v...) t.Fail() } @@ -556,7 +556,7 @@ func TestWithDigest(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.name)+": "+format, v...) t.Fail() } @@ -627,7 +627,7 @@ func TestParseNamed(t *testing.T) { }, } for _, testcase := range testcases { - failf := func(format string, v ...interface{}) { + failf := func(format string, v ...any) { t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } diff --git a/image/go.mod b/image/go.mod index e719c47504..8e370f4ecb 100644 --- a/image/go.mod +++ b/image/go.mod @@ -1,6 +1,6 @@ module go.podman.io/image/v5 -go 1.23.3 +go 1.24.0 // Warning: Ensure the "go" and "toolchain" versions match exactly to prevent unwanted auto-updates. // That generally means there should be no toolchain directive present. diff --git a/image/openshift/openshift-copies.go b/image/openshift/openshift-copies.go index 1180d2dc8e..2799038644 100644 --- a/image/openshift/openshift-copies.go +++ b/image/openshift/openshift-copies.go @@ -843,10 +843,9 @@ func transportNew(config *restConfig) (http.RoundTripper, error) { func newProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error)) func(req *http.Request) (*url.URL, error) { // we wrap the default method, so we only need to perform our check if the NO_PROXY envvar has a CIDR in it noProxyEnv := os.Getenv("NO_PROXY") - noProxyRules := strings.Split(noProxyEnv, ",") cidrs := []netip.Prefix{} - for _, noProxyRule := range noProxyRules { + for noProxyRule := range strings.SplitSeq(noProxyEnv, ",") { prefix, err := netip.ParsePrefix(noProxyRule) if err == nil { cidrs = append(cidrs, prefix) diff --git a/image/signature/fulcio_cert_test.go b/image/signature/fulcio_cert_test.go index 4ea45fba16..c678b18f6d 100644 --- a/image/signature/fulcio_cert_test.go +++ b/image/signature/fulcio_cert_test.go @@ -171,10 +171,7 @@ func TestFulcioIssuerInCertificate(t *testing.T) { } { testLeafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err, c.name) - testLeafSN, err := cryptoutils.GenerateSerialNumber() - require.NoError(t, err, c.name) testLeafContents := x509.Certificate{ - SerialNumber: testLeafSN, Subject: pkix.Name{CommonName: "leaf"}, NotBefore: referenceTime.Add(-1 * time.Minute), NotAfter: referenceTime.Add(1 * time.Hour), @@ -290,10 +287,7 @@ func TestFulcioTrustRootVerifyFulcioCertificateAtTime(t *testing.T) { referenceTime := time.Now() testCAKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - testCASN, err := cryptoutils.GenerateSerialNumber() - require.NoError(t, err) testCAContents := x509.Certificate{ - SerialNumber: testCASN, Subject: pkix.Name{CommonName: "root CA"}, NotBefore: referenceTime.Add(-1 * time.Minute), NotAfter: referenceTime.Add(1 * time.Hour), @@ -403,10 +397,7 @@ func TestFulcioTrustRootVerifyFulcioCertificateAtTime(t *testing.T) { } { testLeafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err, c.name) - testLeafSN, err := cryptoutils.GenerateSerialNumber() - require.NoError(t, err, c.name) testLeafContents := x509.Certificate{ - SerialNumber: testLeafSN, Subject: pkix.Name{CommonName: "leaf"}, NotBefore: referenceTime.Add(-1 * time.Minute), NotAfter: referenceTime.Add(1 * time.Hour), diff --git a/image/signature/pki_cert_test.go b/image/signature/pki_cert_test.go index 2a3817b1ef..d1e4029211 100644 --- a/image/signature/pki_cert_test.go +++ b/image/signature/pki_cert_test.go @@ -122,10 +122,7 @@ func TestPKIVerify(t *testing.T) { referenceTime := time.Now() testCAKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) - testCASN, err := cryptoutils.GenerateSerialNumber() - require.NoError(t, err) testCAContents := x509.Certificate{ - SerialNumber: testCASN, Subject: pkix.Name{CommonName: "root CA"}, NotBefore: referenceTime.Add(-1 * time.Minute), NotAfter: referenceTime.Add(1 * time.Hour), @@ -239,10 +236,7 @@ func TestPKIVerify(t *testing.T) { } { testLeafKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err, c.name) - testLeafSN, err := cryptoutils.GenerateSerialNumber() - require.NoError(t, err, c.name) testLeafContents := x509.Certificate{ - SerialNumber: testLeafSN, Subject: pkix.Name{CommonName: "leaf"}, NotBefore: referenceTime.Add(-1 * time.Minute), NotAfter: referenceTime.Add(1 * time.Hour), diff --git a/image/storage/storage_dest.go b/image/storage/storage_dest.go index 7ea6cd0531..5909570007 100644 --- a/image/storage/storage_dest.go +++ b/image/storage/storage_dest.go @@ -1122,7 +1122,7 @@ func (s *storageImageDestination) createNewLayer(index int, trusted trustedLayer } } - flags := make(map[string]interface{}) + flags := make(map[string]any) if untrustedUncompressedDigest != "" { flags[expectedLayerDiffIDFlag] = untrustedUncompressedDigest.String() logrus.Debugf("Setting uncompressed digest to %q for layer %q", untrustedUncompressedDigest, newLayerID) diff --git a/storage/check.go b/storage/check.go index f0902dfced..3fb648d8c1 100644 --- a/storage/check.go +++ b/storage/check.go @@ -989,15 +989,15 @@ func (c *checkDirectory) add(path string, typeflag byte, uid, gid int, size int6 // remove removes an item from a checkDirectory func (c *checkDirectory) remove(path string) { - components := strings.Split(path, "/") - if len(components) == 1 { - delete(c.directory, components[0]) - delete(c.file, components[0]) + parent, rest, ok := strings.Cut(path, "/") + if !ok { + delete(c.directory, parent) + delete(c.file, parent) return } - subdirectory := c.directory[components[0]] + subdirectory := c.directory[parent] if subdirectory != nil { - subdirectory.remove(strings.Join(components[1:], "/")) + subdirectory.remove(rest) } } @@ -1019,7 +1019,7 @@ func (c *checkDirectory) header(hdr *tar.Header) { // root directory of the archive, which is not always the // same as being relative to hdr.Name directory := c - for _, component := range strings.Split(path.Clean(hdr.Linkname), "/") { + for component := range strings.SplitSeq(path.Clean(hdr.Linkname), "/") { if component == "." || component == ".." { continue } diff --git a/storage/drivers/chown_darwin.go b/storage/drivers/chown_darwin.go index 7490973212..eea633520c 100644 --- a/storage/drivers/chown_darwin.go +++ b/storage/drivers/chown_darwin.go @@ -37,7 +37,7 @@ func (c *platformChowner) LChown(path string, info os.FileInfo, toHost, toContai i := inode{ Dev: uint64(st.Dev), - Ino: uint64(st.Ino), + Ino: st.Ino, } c.mutex.Lock() _, found := c.inodes[i] diff --git a/storage/drivers/graphtest/graphbench_unix.go b/storage/drivers/graphtest/graphbench_unix.go index 29a47ecac5..aca7728407 100644 --- a/storage/drivers/graphtest/graphbench_unix.go +++ b/storage/drivers/graphtest/graphbench_unix.go @@ -23,8 +23,7 @@ func DriverBenchExists(b *testing.B, drivername string, driveroptions ...string) b.Fatal(err) } - b.ResetTimer() - for range b.N { + for b.Loop() { if !driver.Exists(base) { b.Fatal("Newly created image doesn't exist") } @@ -41,8 +40,7 @@ func DriverBenchGetEmpty(b *testing.B, drivername string, driveroptions ...strin b.Fatal(err) } - b.ResetTimer() - for range b.N { + for b.Loop() { _, err := driver.Get(base, graphdriver.MountOpts{}) b.StopTimer() if err != nil { @@ -68,8 +66,7 @@ func DriverBenchDiffBase(b *testing.B, drivername string, driveroptions ...strin b.Fatal(err) } - b.ResetTimer() - for range b.N { + for b.Loop() { arch, err := driver.Diff(base, nil, "", nil, "") if err != nil { b.Fatal(err) @@ -103,8 +100,7 @@ func DriverBenchDiffN(b *testing.B, bottom, top int, drivername string, driverop if err := addManyFiles(driver, upper, top, 6); err != nil { b.Fatal(err) } - b.ResetTimer() - for range b.N { + for b.Loop() { arch, err := driver.Diff(upper, nil, "", nil, "") if err != nil { b.Fatal(err) @@ -141,9 +137,8 @@ func DriverBenchDiffApplyN(b *testing.B, fileCount int, drivername string, drive if err != nil { b.Fatal(err) } - b.ResetTimer() - b.StopTimer() - for range b.N { + for b.Loop() { + b.StopTimer() diff := stringid.GenerateRandomID() if err := driver.Create(diff, base, nil); err != nil { b.Fatal(err) @@ -195,8 +190,7 @@ func DriverBenchDeepLayerDiff(b *testing.B, layerCount int, drivername string, d b.Fatal(err) } - b.ResetTimer() - for range b.N { + for b.Loop() { arch, err := driver.Diff(topLayer, nil, "", nil, "") if err != nil { b.Fatal(err) @@ -238,8 +232,7 @@ func DriverBenchDeepLayerRead(b *testing.B, layerCount int, drivername string, d } }() - b.ResetTimer() - for range b.N { + for b.Loop() { // Read content c, err := os.ReadFile(filepath.Join(root, "testfile.txt")) diff --git a/storage/drivers/overlay/mount.go b/storage/drivers/overlay/mount.go index 250a185a93..97af37c772 100644 --- a/storage/drivers/overlay/mount.go +++ b/storage/drivers/overlay/mount.go @@ -101,7 +101,7 @@ func mountOverlayFromMain() { // Split out the various options, since we need to manipulate the // paths, but we don't want to mess with other options. var upperk, upperv, workk, workv, lowerk, lowerv, labelk, labelv, others string - for _, arg := range strings.Split(options.Label, ",") { + for arg := range strings.SplitSeq(options.Label, ",") { key, val, _ := strings.Cut(arg, "=") switch key { case "upperdir": @@ -139,10 +139,9 @@ func mountOverlayFromMain() { // Get a descriptor for each lower, and use that descriptor's name as // the new value for the list of lowers, because it's shorter. if lowerv != "" { - lowers := strings.Split(lowerv, ":") var newLowers []string dataOnly := false - for _, lowerPath := range lowers { + for lowerPath := range strings.SplitSeq(lowerv, ":") { if lowerPath == "" { dataOnly = true continue diff --git a/storage/drivers/overlay/overlay.go b/storage/drivers/overlay/overlay.go index f65b2c515a..c08e060466 100644 --- a/storage/drivers/overlay/overlay.go +++ b/storage/drivers/overlay/overlay.go @@ -501,7 +501,7 @@ func parseOptions(options []string) (*overlayOptions, error) { if val == "" { continue } - for _, store := range strings.Split(val, ",") { + for store := range strings.SplitSeq(val, ",") { store = filepath.Clean(store) if !filepath.IsAbs(store) { return nil, fmt.Errorf("overlay: image path %q is not absolute. Can not be relative", store) @@ -521,7 +521,7 @@ func parseOptions(options []string) (*overlayOptions, error) { if val == "" { continue } - for _, lstore := range strings.Split(val, ",") { + for lstore := range strings.SplitSeq(val, ",") { elems := strings.Split(lstore, ":") lstore = filepath.Clean(elems[0]) if !filepath.IsAbs(lstore) { @@ -1196,8 +1196,8 @@ func (d *Driver) getLower(parent string) (string, error) { parentLower, err := os.ReadFile(path.Join(parentDir, lowerFile)) if err == nil { - parentLowers := strings.Split(string(parentLower), ":") - lowers = append(lowers, parentLowers...) + parentLowers := strings.SplitSeq(string(parentLower), ":") + lowers = slices.AppendSeq(lowers, parentLowers) } return strings.Join(lowers, ":"), nil } @@ -1247,7 +1247,7 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) { var lowersArray []string lowers, err := os.ReadFile(path.Join(d.dir(id), lowerFile)) if err == nil { - for _, s := range strings.Split(string(lowers), ":") { + for s := range strings.SplitSeq(string(lowers), ":") { lower := d.dir(s) lp, err := os.Readlink(lower) // if the link does not exist, we lost the symlinks during a sudden reboot. diff --git a/storage/drivers/vfs/driver.go b/storage/drivers/vfs/driver.go index c86e174e77..ffd3bd24ea 100644 --- a/storage/drivers/vfs/driver.go +++ b/storage/drivers/vfs/driver.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "runtime" + "slices" "strconv" "strings" @@ -52,7 +53,7 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error) key = strings.ToLower(key) switch key { case "vfs.imagestore", ".imagestore": - d.additionalHomes = append(d.additionalHomes, strings.Split(val, ",")...) + d.additionalHomes = slices.AppendSeq(d.additionalHomes, strings.SplitSeq(val, ",")) continue case "vfs.mountopt": return nil, fmt.Errorf("vfs driver does not support mount options") diff --git a/storage/drivers/zfs/zfs.go b/storage/drivers/zfs/zfs.go index b804cf0b3b..8660dbaa3e 100644 --- a/storage/drivers/zfs/zfs.go +++ b/storage/drivers/zfs/zfs.go @@ -188,8 +188,8 @@ func (d *Driver) Cleanup() error { // Currently it return 'Zpool', 'Zpool Health', 'Parent Dataset', 'Space Used By Parent', // 'Space Available', 'Parent Quota' and 'Compression'. func (d *Driver) Status() [][2]string { - parts := strings.Split(d.dataset.Name, "/") - pool, err := zfs.GetZpool(parts[0]) + fsName, _, _ := strings.Cut(d.dataset.Name, "/") + pool, err := zfs.GetZpool(fsName) var poolName, poolHealth string if err == nil { diff --git a/storage/go.mod b/storage/go.mod index 98e6ca3678..34bffb1bbc 100644 --- a/storage/go.mod +++ b/storage/go.mod @@ -1,4 +1,4 @@ -go 1.23.3 +go 1.24.0 // Warning: Ensure the "go" and "toolchain" versions match exactly to prevent unwanted auto-updates. // That generally means there should be no toolchain directive present. diff --git a/storage/internal/opts/opts.go b/storage/internal/opts/opts.go index dba0a448bf..304b92963e 100644 --- a/storage/internal/opts/opts.go +++ b/storage/internal/opts/opts.go @@ -232,16 +232,16 @@ func ValidateSysctl(val string) (string, error) { "net.", "fs.mqueue.", } - arr := strings.Split(val, "=") - if len(arr) < 2 { + sysctlName, _, ok := strings.Cut(val, "=") + if !ok { return "", fmt.Errorf("sysctl '%s' is not allowed", val) } - if validSysctlMap[arr[0]] { + if validSysctlMap[sysctlName] { return val, nil } for _, vp := range validSysctlPrefixes { - if strings.HasPrefix(arr[0], vp) { + if strings.HasPrefix(sysctlName, vp) { return val, nil } } diff --git a/storage/internal/opts/opts_test.go b/storage/internal/opts/opts_test.go index 6b461f7b5d..d6a55a179e 100644 --- a/storage/internal/opts/opts_test.go +++ b/storage/internal/opts/opts_test.go @@ -145,11 +145,11 @@ func TestValidateLabel(t *testing.T) { func logOptsValidator(val string) (string, error) { allowedKeys := map[string]string{"max-size": "1", "max-file": "2"} - vals := strings.Split(val, "=") - if allowedKeys[vals[0]] != "" { + key, _, _ := strings.Cut(val, "=") + if allowedKeys[key] != "" { return val, nil } - return "", fmt.Errorf("invalid key %s", vals[0]) + return "", fmt.Errorf("invalid key %s", key) } func TestNamedListOpts(t *testing.T) { diff --git a/storage/internal/staging_lockfile/staging_lockfile_test.go b/storage/internal/staging_lockfile/staging_lockfile_test.go index ca8cbfb250..5512f87601 100644 --- a/storage/internal/staging_lockfile/staging_lockfile_test.go +++ b/storage/internal/staging_lockfile/staging_lockfile_test.go @@ -127,7 +127,7 @@ func TestLockFileRecreation(t *testing.T) { func TestConcurrentLocking(t *testing.T) { const n = 10 ch := make(chan struct{}, n) - for i := 0; i < n; i++ { + for range n { go func() { l, _, err := CreateAndLock(t.TempDir(), "concurrent-lock") require.NoError(t, err) @@ -135,7 +135,7 @@ func TestConcurrentLocking(t *testing.T) { ch <- struct{}{} }() } - for i := 0; i < n; i++ { + for range n { <-ch } require.Len(t, stagingLockFiles, 0) @@ -149,7 +149,7 @@ func TestTryLockPathMultiProcess(t *testing.T) { expectedErrMsg := fmt.Sprintf("error opening lock file %q: failed to acquire lock on ", fullPath) tryLockTimes := 3 - for i := 0; i < tryLockTimes; i++ { + for range tryLockTimes { cmd, stdout, err := subTryLockPath(fullPath) require.NoError(t, err) stderrBuf := new(strings.Builder) diff --git a/storage/internal/tempdir/tempdir_test.go b/storage/internal/tempdir/tempdir_test.go index 00b21bad18..c8cc003c79 100644 --- a/storage/internal/tempdir/tempdir_test.go +++ b/storage/internal/tempdir/tempdir_test.go @@ -133,7 +133,7 @@ func TestListPotentialStaleDirs(t *testing.T) { expectedIds := map[string]struct{}{} - for i := 0; i < 3; i++ { + for range 3 { lockfile, err := os.CreateTemp(rootDir, tempdirLockPrefix) assert.NoError(t, err) lockfileName := filepath.Base(lockfile.Name()) diff --git a/storage/pkg/archive/archive_other.go b/storage/pkg/archive/archive_other.go index b342ff75ee..f7c7352fd3 100644 --- a/storage/pkg/archive/archive_other.go +++ b/storage/pkg/archive/archive_other.go @@ -2,7 +2,7 @@ package archive -func GetWhiteoutConverter(format WhiteoutFormat, data interface{}) TarWhiteoutConverter { +func GetWhiteoutConverter(format WhiteoutFormat, data any) TarWhiteoutConverter { return nil } diff --git a/storage/pkg/archive/archive_test.go b/storage/pkg/archive/archive_test.go index 04ea94eba3..50d714b5ac 100644 --- a/storage/pkg/archive/archive_test.go +++ b/storage/pkg/archive/archive_test.go @@ -811,9 +811,8 @@ func BenchmarkTarUntar(b *testing.B) { b.Fatal(err) } - b.ResetTimer() b.SetBytes(int64(n)) - for range b.N { + for b.Loop() { err := defaultTarUntar(origin, target) if err != nil { b.Fatal(err) @@ -831,9 +830,8 @@ func BenchmarkTarUntarWithLinks(b *testing.B) { b.Fatal(err) } - b.ResetTimer() b.SetBytes(int64(n)) - for range b.N { + for b.Loop() { err := defaultTarUntar(origin, target) if err != nil { b.Fatal(err) diff --git a/storage/pkg/archive/archive_unix.go b/storage/pkg/archive/archive_unix.go index 2d9d68de2c..0ff5716584 100644 --- a/storage/pkg/archive/archive_unix.go +++ b/storage/pkg/archive/archive_unix.go @@ -32,8 +32,10 @@ func statUnix(fi os.FileInfo, hdr *tar.Header) error { if s.Mode&unix.S_IFBLK != 0 || s.Mode&unix.S_IFCHR != 0 { - hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint: unconvert - hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint: unconvert + // _nolint_: Whether this conversion is required is hardware- and OS-dependent: the value might be uint64 on Linux, int32 on macOS. + // So, this might trigger either "uncovert" (if the conversion is unnecessary) or "nolintlint" (if it is required) + hdr.Devmajor = int64(unix.Major(uint64(s.Rdev))) //nolint:unconvert,nolintlint + hdr.Devminor = int64(unix.Minor(uint64(s.Rdev))) //nolint:unconvert,nolintlint } return nil @@ -74,8 +76,10 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat any) (err erro // Currently go does not fill in the major/minors if s.Mode&unix.S_IFBLK != 0 || s.Mode&unix.S_IFCHR != 0 { - hdr.Devmajor = int64(major(uint64(s.Rdev))) //nolint: unconvert - hdr.Devminor = int64(minor(uint64(s.Rdev))) //nolint: unconvert + // _nolint_: Whether this conversion is required is hardware- and OS-dependent: the value might be uint64 on Linux, int32 on macOS. + // So, this might trigger either "uncovert" (if the conversion is unnecessary) or "nolintlint" (if it is required) + hdr.Devmajor = int64(major(uint64(s.Rdev))) //nolint: unconvert,nolintlint + hdr.Devminor = int64(minor(uint64(s.Rdev))) //nolint: unconvert,nolintlint } } diff --git a/storage/pkg/archive/archive_unix_test.go b/storage/pkg/archive/archive_unix_test.go index a22cce19b1..251befbeea 100644 --- a/storage/pkg/archive/archive_unix_test.go +++ b/storage/pkg/archive/archive_unix_test.go @@ -195,7 +195,9 @@ func getNlink(path string) (uint64, error) { if !ok { return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys()) } - return uint64(statT.Nlink), nil //nolint:unconvert // Need the conversion for e.g. linux/arm64. + // _nolint_: Whether this conversion is required is hardware- and OS-dependent: the value might be uint64 on Linux, int32 on macOS. + // So, this might trigger either "uncovert" (if the conversion is unnecessary) or "nolintlint" (if it is required) + return uint64(statT.Nlink), nil //nolint:unconvert,nolintlint } func getInode(path string) (uint64, error) { diff --git a/storage/pkg/archive/changes.go b/storage/pkg/archive/changes.go index 051ab69528..e9e3519819 100644 --- a/storage/pkg/archive/changes.go +++ b/storage/pkg/archive/changes.go @@ -281,8 +281,7 @@ func (info *FileInfo) LookUp(path string) *FileInfo { return info } - pathElements := strings.Split(path, string(os.PathSeparator)) - for _, elem := range pathElements { + for elem := range strings.SplitSeq(path, string(os.PathSeparator)) { if elem != "" { child := parent.children[elem] if child == nil { diff --git a/storage/pkg/archive/fflags_bsd.go b/storage/pkg/archive/fflags_bsd.go index 829c95ef14..7584b14ce5 100644 --- a/storage/pkg/archive/fflags_bsd.go +++ b/storage/pkg/archive/fflags_bsd.go @@ -77,7 +77,7 @@ var ( func parseFileFlags(fflags string) (uint32, uint32, error) { var set, clear uint32 = 0, 0 - for _, fflag := range strings.Split(fflags, ",") { + for fflag := range strings.SplitSeq(fflags, ",") { isClear := false if clean, ok := strings.CutPrefix(fflag, "no"); ok { isClear = true diff --git a/storage/pkg/chunked/compressor/compressor.go b/storage/pkg/chunked/compressor/compressor.go index 23bcbda519..ef26a812ba 100644 --- a/storage/pkg/chunked/compressor/compressor.go +++ b/storage/pkg/chunked/compressor/compressor.go @@ -173,7 +173,7 @@ func (rc *rollingChecksumReader) Read(b []byte) (bool, int, error) { return false, -1, err } if holeLen > 0 { - for j := int64(0); j < holeLen; j++ { + for range holeLen { rc.rollsum.Roll(0) } rc.pendingHole = holeLen diff --git a/storage/pkg/chunked/compressor/rollsum_test.go b/storage/pkg/chunked/compressor/rollsum_test.go index 6008910b34..cc94a93248 100644 --- a/storage/pkg/chunked/compressor/rollsum_test.go +++ b/storage/pkg/chunked/compressor/rollsum_test.go @@ -79,10 +79,9 @@ func BenchmarkRollsum(b *testing.B) { buf[i] = byte(rand.Int63()) } - b.ResetTimer() rs := NewRollSum() splits := 0 - for range b.N { + for b.Loop() { splits = 0 for _, b := range buf { rs.Roll(b) diff --git a/storage/pkg/fileutils/exists_test.go b/storage/pkg/fileutils/exists_test.go index 0407c59576..594284b225 100644 --- a/storage/pkg/fileutils/exists_test.go +++ b/storage/pkg/fileutils/exists_test.go @@ -72,7 +72,7 @@ func TestExist(t *testing.T) { func BenchmarkExists(b *testing.B) { tempDir := b.TempDir() - for range b.N { + for b.Loop() { _ = Exists(tempDir) _ = Lexists(tempDir) } @@ -80,7 +80,7 @@ func BenchmarkExists(b *testing.B) { func BenchmarkStat(b *testing.B) { tempDir := b.TempDir() - for range b.N { + for b.Loop() { _, _ = os.Stat(tempDir) _, _ = os.Lstat(tempDir) } diff --git a/storage/pkg/fileutils/fileutils.go b/storage/pkg/fileutils/fileutils.go index 85ce2d5260..434979825c 100644 --- a/storage/pkg/fileutils/fileutils.go +++ b/storage/pkg/fileutils/fileutils.go @@ -51,7 +51,6 @@ func NewPatternMatcher(patterns []string) (*PatternMatcher, error) { return nil, err } newp.cleanedPattern = p - newp.dirs = strings.Split(p, string(os.PathSeparator)) pm.patterns = append(pm.patterns, newp) } return pm, nil @@ -168,7 +167,6 @@ func (pm *PatternMatcher) Patterns() []*Pattern { // Pattern defines a single regexp used to filter file paths. type Pattern struct { cleanedPattern string - dirs []string regexp *regexp.Regexp exclusion bool } diff --git a/storage/pkg/idtools/idtools_unix.go b/storage/pkg/idtools/idtools_unix.go index 817b59aed1..e7c2643676 100644 --- a/storage/pkg/idtools/idtools_unix.go +++ b/storage/pkg/idtools/idtools_unix.go @@ -8,7 +8,6 @@ import ( "io" "os" "path/filepath" - "strings" "sync" "syscall" @@ -112,7 +111,7 @@ func LookupUser(username string) (user.User, error) { return usr, nil } // local files lookup failed; attempt to call `getent` to query configured passwd dbs - usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username)) + usr, err = getentUser(username) if err != nil { return user.User{}, err } @@ -128,11 +127,11 @@ func LookupUID(uid int) (user.User, error) { return usr, nil } // local files lookup failed; attempt to call `getent` to query configured passwd dbs - return getentUser(fmt.Sprintf("%s %d", "passwd", uid)) + return getentUser(fmt.Sprintf("%d", uid)) } -func getentUser(args string) (user.User, error) { - reader, err := callGetent(args) +func getentUser(key string) (user.User, error) { + reader, err := callGetent("passwd", key) if err != nil { return user.User{}, err } @@ -141,7 +140,7 @@ func getentUser(args string) (user.User, error) { return user.User{}, err } if len(users) == 0 { - return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1]) + return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", key) } return users[0], nil } @@ -155,7 +154,7 @@ func LookupGroup(groupname string) (user.Group, error) { return group, nil } // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(fmt.Sprintf("%s %s", "group", groupname)) + return getentGroup(groupname) } // LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, @@ -167,11 +166,11 @@ func LookupGID(gid int) (user.Group, error) { return group, nil } // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(fmt.Sprintf("%s %d", "group", gid)) + return getentGroup(fmt.Sprintf("%d", gid)) } -func getentGroup(args string) (user.Group, error) { - reader, err := callGetent(args) +func getentGroup(key string) (user.Group, error) { + reader, err := callGetent("group", key) if err != nil { return user.Group{}, err } @@ -180,18 +179,18 @@ func getentGroup(args string) (user.Group, error) { return user.Group{}, err } if len(groups) == 0 { - return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1]) + return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", key) } return groups[0], nil } -func callGetent(args string) (io.Reader, error) { +func callGetent(db, key string) (io.Reader, error) { entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") }) // if no `getent` command on host, can't do anything else if getentCmd == "" { return nil, fmt.Errorf("") } - out, err := execCmd(getentCmd, args) + out, err := execCmd(getentCmd, db, key) if err != nil { exitCode, errC := system.GetExitCode(err) if errC != nil { @@ -201,8 +200,7 @@ func callGetent(args string) (io.Reader, error) { case 1: return nil, fmt.Errorf("getent reported invalid parameters/database unknown") case 2: - terms := strings.Split(args, " ") - return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0]) + return nil, fmt.Errorf("getent unable to find entry %q in %s database", key, db) case 3: return nil, fmt.Errorf("getent database doesn't support enumeration") default: diff --git a/storage/pkg/idtools/usergroupadd_linux.go b/storage/pkg/idtools/usergroupadd_linux.go index d2ff4466c1..ee80ce6a78 100644 --- a/storage/pkg/idtools/usergroupadd_linux.go +++ b/storage/pkg/idtools/usergroupadd_linux.go @@ -2,6 +2,7 @@ package idtools import ( "fmt" + "slices" "sort" "strconv" "strings" @@ -17,19 +18,12 @@ import ( var ( once sync.Once - userCommand string - - cmdTemplates = map[string]string{ - "adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s", - "useradd": "-r -s /bin/false %s", - "usermod": "-%s %d-%d %s", - } + userCommand []string // command, args…, to be finished by adding an user name idOutRegexp = regexp.Delayed(`uid=([0-9]+).*gid=([0-9]+)`) // default length for a UID/GID subordinate range defaultRangeLen = 65536 defaultRangeStart = 100000 - userMod = "usermod" ) // AddNamespaceRangesUser takes a username and uses the standard system @@ -72,16 +66,16 @@ func addUser(userName string) error { once.Do(func() { // set up which commands are used for adding users/groups dependent on distro if _, err := resolveBinary("adduser"); err == nil { - userCommand = "adduser" + userCommand = []string{"adduser", "--system", "--shell", "/bin/false", "--no-create-home", "--disabled-login", "--disabled-password", "--group"} } else if _, err := resolveBinary("useradd"); err == nil { - userCommand = "useradd" + userCommand = []string{"useradd", "-r", "-s", "/bin/false"} } }) - if userCommand == "" { + if userCommand == nil { return fmt.Errorf("cannot add user; no useradd/adduser binary found") } - args := fmt.Sprintf(cmdTemplates[userCommand], userName) - out, err := execCmd(userCommand, args) + args := append(slices.Clone(userCommand), userName) + out, err := execCmd(args[0], args[1:]...) if err != nil { return fmt.Errorf("failed to add user with error: %w; output: %q", err, string(out)) } @@ -101,7 +95,7 @@ func createSubordinateRanges(name string) error { if err != nil { return fmt.Errorf("can't find available subuid range: %w", err) } - out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name)) + out, err := execCmd("usermod", "-v", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name) if err != nil { return fmt.Errorf("unable to add subuid range to user: %q; output: %s, err: %w", name, out, err) } @@ -117,7 +111,7 @@ func createSubordinateRanges(name string) error { if err != nil { return fmt.Errorf("can't find available subgid range: %w", err) } - out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name)) + out, err := execCmd("usermod", "-w", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name) if err != nil { return fmt.Errorf("unable to add subgid range to user: %q; output: %s, err: %w", name, out, err) } diff --git a/storage/pkg/idtools/utils_unix.go b/storage/pkg/idtools/utils_unix.go index f34462a23a..10606fba8a 100644 --- a/storage/pkg/idtools/utils_unix.go +++ b/storage/pkg/idtools/utils_unix.go @@ -6,7 +6,6 @@ import ( "fmt" "os/exec" "path/filepath" - "strings" ) func resolveBinary(binname string) (string, error) { @@ -26,7 +25,7 @@ func resolveBinary(binname string) (string, error) { return "", fmt.Errorf("binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) } -func execCmd(cmd, args string) ([]byte, error) { - execCmd := exec.Command(cmd, strings.Split(args, " ")...) +func execCmd(cmd string, args ...string) ([]byte, error) { + execCmd := exec.Command(cmd, args...) return execCmd.CombinedOutput() } diff --git a/storage/pkg/ioutils/bytespipe_test.go b/storage/pkg/ioutils/bytespipe_test.go index 0f887c5464..c2ce7c6b6d 100644 --- a/storage/pkg/ioutils/bytespipe_test.go +++ b/storage/pkg/ioutils/bytespipe_test.go @@ -138,7 +138,7 @@ func TestBytesPipeWriteRandomChunks(t *testing.T) { func BenchmarkBytesPipeWrite(b *testing.B) { testData := []byte("pretty short line, because why not?") - for range b.N { + for b.Loop() { readBuf := make([]byte, 1024) buf := NewBytesPipe() go func() { @@ -157,7 +157,7 @@ func BenchmarkBytesPipeWrite(b *testing.B) { func BenchmarkBytesPipeRead(b *testing.B) { rd := make([]byte, 512) - for range b.N { + for b.Loop() { b.StopTimer() buf := NewBytesPipe() for range 500 { diff --git a/storage/pkg/mflag/flag.go b/storage/pkg/mflag/flag.go index 9461d7a93c..7610a3477b 100644 --- a/storage/pkg/mflag/flag.go +++ b/storage/pkg/mflag/flag.go @@ -567,7 +567,7 @@ func (fs *FlagSet) PrintDefaults() { format := " -%s=%s" fmt.Fprintf(writer, format, strings.Join(names, ", -"), val) } - for _, line := range strings.Split(flag.Usage, "\n") { + for line := range strings.SplitSeq(flag.Usage, "\n") { fmt.Fprintln(writer, "\t", line) } } @@ -1094,7 +1094,7 @@ func (fs *FlagSet) Parse(arguments []string) error { if err == ErrRetry { if len(name) > 1 { err = nil - for _, letter := range strings.Split(name, "") { + for letter := range strings.SplitSeq(name, "") { fs.args = append([]string{"-" + letter}, fs.args...) seen2, _, err2 := fs.parseOne() if seen2 { diff --git a/storage/pkg/mount/flags.go b/storage/pkg/mount/flags.go index 40a229932b..9325e25977 100644 --- a/storage/pkg/mount/flags.go +++ b/storage/pkg/mount/flags.go @@ -119,7 +119,7 @@ func ParseOptions(options string) (int, string) { data []string ) - for _, o := range strings.Split(options, ",") { + for o := range strings.SplitSeq(options, ",") { // If the option does not exist in the flags table or the flag // is not supported on the platform, // then it is a data value for a specific fs type @@ -139,7 +139,7 @@ func ParseOptions(options string) (int, string) { // ParseTmpfsOptions parse fstab type mount options into flags and data func ParseTmpfsOptions(options string) (int, string, error) { flags, data := ParseOptions(options) - for _, o := range strings.Split(data, ",") { + for o := range strings.SplitSeq(data, ",") { opt, _, _ := strings.Cut(o, "=") if !validFlags[opt] { return 0, "", fmt.Errorf("invalid tmpfs option %q", opt) diff --git a/storage/pkg/mount/mounter_freebsd.go b/storage/pkg/mount/mounter_freebsd.go index 61d6d1c595..1c99ff4618 100644 --- a/storage/pkg/mount/mounter_freebsd.go +++ b/storage/pkg/mount/mounter_freebsd.go @@ -33,8 +33,7 @@ func mount(device, target, mType string, flag uintptr, data string) error { options := []string{"fspath", target} if data != "" { - xs := strings.Split(data, ",") - for _, x := range xs { + for x := range strings.SplitSeq(data, ",") { if x == "bind" { isNullFS = true continue diff --git a/storage/pkg/mount/mounter_linux_test.go b/storage/pkg/mount/mounter_linux_test.go index 24936943f6..5a11bc493d 100644 --- a/storage/pkg/mount/mounter_linux_test.go +++ b/storage/pkg/mount/mounter_linux_test.go @@ -111,21 +111,21 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) { wantedOpts := make(map[string]struct{}) if opts != "" { - for _, opt := range strings.Split(opts, ",") { + for opt := range strings.SplitSeq(opts, ",") { wantedOpts[opt] = struct{}{} } } wantedOptional := make(map[string]struct{}) if optional != "" { - for _, opt := range strings.Split(optional, ",") { + for opt := range strings.SplitSeq(optional, ",") { wantedOptional[opt] = struct{}{} } } wantedVFS := make(map[string]struct{}) if vfs != "" { - for _, opt := range strings.Split(vfs, ",") { + for opt := range strings.SplitSeq(vfs, ",") { wantedVFS[opt] = struct{}{} } } @@ -146,20 +146,20 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) { p := mnts[mi.Parent] pOpts := make(map[string]struct{}) if p.Options != "" { - for _, opt := range strings.Split(p.Options, ",") { + for opt := range strings.SplitSeq(p.Options, ",") { pOpts[clean(opt)] = struct{}{} } } pOptional := make(map[string]struct{}) if p.Optional != "" { - for _, field := range strings.Split(p.Optional, ",") { + for field := range strings.SplitSeq(p.Optional, ",") { pOptional[clean(field)] = struct{}{} } } // Validate Options if mi.Options != "" { - for _, opt := range strings.Split(mi.Options, ",") { + for opt := range strings.SplitSeq(mi.Options, ",") { opt = clean(opt) if !has(volunteeredOPT, opt) && !has(wantedOpts, opt) && !has(pOpts, opt) { t.Errorf("unexpected mount option %q, expected %q", opt, opts) @@ -173,7 +173,7 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) { // Validate Optional if mi.Optional != "" { - for _, field := range strings.Split(mi.Optional, ",") { + for field := range strings.SplitSeq(mi.Optional, ",") { field = clean(field) if !has(wantedOptional, field) && !has(pOptional, field) { t.Errorf("unexpected optional field %q, expected %q", field, optional) @@ -188,7 +188,7 @@ func validateMount(t *testing.T, mnt string, opts, optional, vfs string) { // Validate VFS if set if vfs != "" { if mi.VFSOptions != "" { - for _, opt := range strings.Split(mi.VFSOptions, ",") { + for opt := range strings.SplitSeq(mi.VFSOptions, ",") { opt = clean(opt) if !has(wantedVFS, opt) && !has(volunteeredVFS, opt) { t.Errorf("unexpected vfs option %q, expected %q", opt, vfs) diff --git a/storage/pkg/parsers/kernel/kernel_darwin.go b/storage/pkg/parsers/kernel/kernel_darwin.go index e4bf40a39d..3c043277b5 100644 --- a/storage/pkg/parsers/kernel/kernel_darwin.go +++ b/storage/pkg/parsers/kernel/kernel_darwin.go @@ -31,8 +31,7 @@ func getRelease() (string, error) { } var release string - data := strings.Split(string(osName), "\n") - for _, line := range data { + for line := range strings.SplitSeq(string(osName), "\n") { if strings.Contains(line, "Kernel Version") { // It has the format like ' Kernel Version: Darwin 14.5.0' _, val, ok := strings.Cut(line, ":") diff --git a/storage/pkg/parsers/operatingsystem/operatingsystem_linux.go b/storage/pkg/parsers/operatingsystem/operatingsystem_linux.go index 6275e37cfc..7fc7750913 100644 --- a/storage/pkg/parsers/operatingsystem/operatingsystem_linux.go +++ b/storage/pkg/parsers/operatingsystem/operatingsystem_linux.go @@ -66,7 +66,7 @@ func IsContainerized() (bool, error) { if err != nil { return false, err } - for _, line := range bytes.Split(b, []byte{'\n'}) { + for line := range bytes.SplitSeq(b, []byte{'\n'}) { if len(line) > 0 && !bytes.HasSuffix(line, []byte{'/'}) && !bytes.HasSuffix(line, []byte("init.scope")) { return true, nil } diff --git a/storage/pkg/parsers/parsers.go b/storage/pkg/parsers/parsers.go index 7b20b06287..d87358e6e0 100644 --- a/storage/pkg/parsers/parsers.go +++ b/storage/pkg/parsers/parsers.go @@ -38,10 +38,9 @@ func ParseUintList(val string) (map[int]bool, error) { } availableInts := make(map[int]bool) - split := strings.Split(val, ",") errInvalidFormat := fmt.Errorf("invalid format: %s", val) - for _, r := range split { + for r := range strings.SplitSeq(val, ",") { minS, maxS, ok := strings.Cut(r, "-") if !ok { v, err := strconv.Atoi(r) diff --git a/storage/pkg/system/xattrs_darwin.go b/storage/pkg/system/xattrs_darwin.go index 27ada2083e..d574e9e61c 100644 --- a/storage/pkg/system/xattrs_darwin.go +++ b/storage/pkg/system/xattrs_darwin.go @@ -74,7 +74,7 @@ func Llistxattr(path string) ([]string, error) { } var attrs []string - for _, token := range bytes.Split(dest[:sz], []byte{0}) { + for token := range bytes.SplitSeq(dest[:sz], []byte{0}) { if len(token) > 0 { attrs = append(attrs, string(token)) } diff --git a/storage/pkg/system/xattrs_linux.go b/storage/pkg/system/xattrs_linux.go index 12462cca33..3322707a43 100644 --- a/storage/pkg/system/xattrs_linux.go +++ b/storage/pkg/system/xattrs_linux.go @@ -77,7 +77,7 @@ func Llistxattr(path string) ([]string, error) { } var attrs []string - for _, token := range bytes.Split(dest[:sz], []byte{0}) { + for token := range bytes.SplitSeq(dest[:sz], []byte{0}) { if len(token) > 0 { attrs = append(attrs, string(token)) } diff --git a/storage/pkg/truncindex/truncindex_test.go b/storage/pkg/truncindex/truncindex_test.go index 44f68b1c2b..06ed7b10af 100644 --- a/storage/pkg/truncindex/truncindex_test.go +++ b/storage/pkg/truncindex/truncindex_test.go @@ -159,8 +159,7 @@ func BenchmarkTruncIndexAdd100(b *testing.B) { for range 100 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { @@ -175,8 +174,7 @@ func BenchmarkTruncIndexAdd250(b *testing.B) { for range 250 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { @@ -191,8 +189,7 @@ func BenchmarkTruncIndexAdd500(b *testing.B) { for range 500 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { @@ -216,8 +213,7 @@ func BenchmarkTruncIndexGet100(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { for _, id := range testKeys { if res, err := index.Get(id); err != nil { b.Fatal(res, err) @@ -240,8 +236,7 @@ func BenchmarkTruncIndexGet250(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { for _, id := range testKeys { if res, err := index.Get(id); err != nil { b.Fatal(res, err) @@ -264,8 +259,7 @@ func BenchmarkTruncIndexGet500(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { for _, id := range testKeys { if res, err := index.Get(id); err != nil { b.Fatal(res, err) @@ -279,8 +273,7 @@ func BenchmarkTruncIndexDelete100(b *testing.B) { for range 100 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { b.StopTimer() index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -302,8 +295,7 @@ func BenchmarkTruncIndexDelete250(b *testing.B) { for range 250 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { b.StopTimer() index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -325,8 +317,7 @@ func BenchmarkTruncIndexDelete500(b *testing.B) { for range 500 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { b.StopTimer() index := NewTruncIndex([]string{}) for _, id := range testSet { @@ -348,8 +339,7 @@ func BenchmarkTruncIndexNew100(b *testing.B) { for range 100 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { NewTruncIndex(testSet) } } @@ -359,8 +349,7 @@ func BenchmarkTruncIndexNew250(b *testing.B) { for range 250 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { NewTruncIndex(testSet) } } @@ -370,8 +359,7 @@ func BenchmarkTruncIndexNew500(b *testing.B) { for range 500 { testSet = append(testSet, stringid.GenerateNonCryptoID()) } - b.ResetTimer() - for range b.N { + for b.Loop() { NewTruncIndex(testSet) } } @@ -385,8 +373,7 @@ func BenchmarkTruncIndexAddGet100(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { @@ -410,8 +397,7 @@ func BenchmarkTruncIndexAddGet250(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { @@ -435,8 +421,7 @@ func BenchmarkTruncIndexAddGet500(b *testing.B) { l := rand.IntN(12) + 12 testKeys = append(testKeys, id[:l]) } - b.ResetTimer() - for range b.N { + for b.Loop() { index := NewTruncIndex([]string{}) for _, id := range testSet { if err := index.Add(id); err != nil { diff --git a/storage/store.go b/storage/store.go index fa34f4eecc..84019a4947 100644 --- a/storage/store.go +++ b/storage/store.go @@ -3496,7 +3496,6 @@ func (s *store) ImagesByTopLayer(id string) ([]*Image, error) { return struct{}{}, true, err } for _, image := range imageList { - image := image if image.TopLayer == layer.ID || stringutils.InSlice(image.MappedTopLayers, layer.ID) { images = append(images, &image) } diff --git a/storage/types/options.go b/storage/types/options.go index 2c2be5c22d..8af7c9c405 100644 --- a/storage/types/options.go +++ b/storage/types/options.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "strings" "sync" "time" @@ -362,7 +363,7 @@ func getRootlessStorageOpts(systemOpts StoreOptions) (StoreOptions, error) { } if os.Getenv("STORAGE_OPTS") != "" { - opts.GraphDriverOptions = append(opts.GraphDriverOptions, strings.Split(os.Getenv("STORAGE_OPTS"), ",")...) + opts.GraphDriverOptions = slices.AppendSeq(opts.GraphDriverOptions, strings.SplitSeq(os.Getenv("STORAGE_OPTS"), ",")) } return opts, nil