diff --git a/cli/command/completion/functions_test.go b/cli/command/completion/functions_test.go index bb2fa1b62d..87706005c9 100644 --- a/cli/command/completion/functions_test.go +++ b/cli/command/completion/functions_test.go @@ -3,9 +3,9 @@ package completion import ( "context" "errors" - "sort" "testing" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/image" "github.com/moby/moby/api/types/network" @@ -177,9 +177,10 @@ func TestCompleteEnvVarNames(t *testing.T) { values, directives := EnvVarNames()(nil, nil, "") assert.Check(t, is.Equal(directives&cobra.ShellCompDirectiveNoFileComp, cobra.ShellCompDirectiveNoFileComp), "Should not perform file completion") - sort.Strings(values) expected := []string{"ENV_A", "ENV_B"} - assert.Check(t, is.DeepEqual(values, expected)) + assert.Check(t, is.DeepEqual(values, expected, cmpopts.SortSlices(func(a, b string) bool { + return a < b + }))) } func TestCompleteFileNames(t *testing.T) { diff --git a/cli/command/container/create_test.go b/cli/command/container/create_test.go index 1c6ec92649..9c0099904e 100644 --- a/cli/command/container/create_test.go +++ b/cli/command/container/create_test.go @@ -7,7 +7,6 @@ import ( "os" "path/filepath" "runtime" - "sort" "strings" "testing" @@ -15,6 +14,7 @@ import ( "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/internal/test" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/api/types/container" "github.com/moby/moby/api/types/system" "github.com/moby/moby/client" @@ -284,12 +284,12 @@ func TestCreateContainerWithProxyConfig(t *testing.T) { "ALL_PROXY=allProxy", "all_proxy=allProxy", } - sort.Strings(expected) fakeCLI := test.NewFakeCli(&fakeClient{ createContainerFunc: func(options client.ContainerCreateOptions) (client.ContainerCreateResult, error) { - sort.Strings(options.Config.Env) - assert.DeepEqual(t, options.Config.Env, expected) + assert.DeepEqual(t, options.Config.Env, expected, cmpopts.SortSlices(func(a, b string) bool { + return a < b + })) return client.ContainerCreateResult{}, nil }, }) diff --git a/cli/command/container/restart_test.go b/cli/command/container/restart_test.go index 569571b717..4754446866 100644 --- a/cli/command/container/restart_test.go +++ b/cli/command/container/restart_test.go @@ -4,11 +4,11 @@ import ( "context" "errors" "io" - "sort" "sync" "testing" "github.com/docker/cli/internal/test" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -87,8 +87,9 @@ func TestRestart(t *testing.T) { } else { assert.Check(t, is.Nil(err)) } - sort.Strings(restarted) - assert.Check(t, is.DeepEqual(restarted, tc.restarted)) + assert.Check(t, is.DeepEqual(restarted, tc.restarted, cmpopts.SortSlices(func(a, b string) bool { + return a < b + }))) }) } } diff --git a/cli/command/container/rm_test.go b/cli/command/container/rm_test.go index 4ab14407bb..5e31e9abbc 100644 --- a/cli/command/container/rm_test.go +++ b/cli/command/container/rm_test.go @@ -4,11 +4,11 @@ import ( "context" "errors" "io" - "sort" "sync" "testing" "github.com/docker/cli/internal/test" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/client" "gotest.tools/v3/assert" ) @@ -53,8 +53,10 @@ func TestRemoveForce(t *testing.T) { assert.NilError(t, err) } assert.Equal(t, cli.ErrBuffer().String(), "") - sort.Strings(removed) - assert.DeepEqual(t, removed, []string{"mycontainer", "nosuchcontainer"}) + expected := []string{"mycontainer", "nosuchcontainer"} + assert.DeepEqual(t, removed, expected, cmpopts.SortSlices(func(a, b string) bool { + return a < b + })) }) } } diff --git a/cli/command/container/stop_test.go b/cli/command/container/stop_test.go index ed7fc335e2..484e7b4f39 100644 --- a/cli/command/container/stop_test.go +++ b/cli/command/container/stop_test.go @@ -4,11 +4,11 @@ import ( "context" "errors" "io" - "sort" "sync" "testing" "github.com/docker/cli/internal/test" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/client" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" @@ -88,8 +88,9 @@ func TestStop(t *testing.T) { } else { assert.Check(t, is.Nil(err)) } - sort.Strings(stopped) - assert.Check(t, is.DeepEqual(stopped, tc.stopped)) + assert.Check(t, is.DeepEqual(stopped, tc.stopped, cmpopts.SortSlices(func(a, b string) bool { + return a < b + }))) }) } } diff --git a/cli/command/formatter/buildcache.go b/cli/command/formatter/buildcache.go index 3a3c349988..d63cf05d63 100644 --- a/cli/command/formatter/buildcache.go +++ b/cli/command/formatter/buildcache.go @@ -1,7 +1,10 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package formatter import ( - "sort" + "slices" "strconv" "strings" "time" @@ -52,20 +55,20 @@ shared: {{.Shared}} } func buildCacheSort(buildCache []build.CacheRecord) { - sort.Slice(buildCache, func(i, j int) bool { - lui, luj := buildCache[i].LastUsedAt, buildCache[j].LastUsedAt + slices.SortFunc(buildCache, func(a, b build.CacheRecord) int { switch { - case lui == nil && luj == nil: - return strings.Compare(buildCache[i].ID, buildCache[j].ID) < 0 - case lui == nil: - return true - case luj == nil: - return false - case lui.Equal(*luj): - return strings.Compare(buildCache[i].ID, buildCache[j].ID) < 0 - default: - return lui.Before(*luj) + case a.LastUsedAt == nil && b.LastUsedAt == nil: + return strings.Compare(a.ID, b.ID) + case a.LastUsedAt == nil: + return -1 + case b.LastUsedAt == nil: + return 1 } + + if c := a.LastUsedAt.Compare(*b.LastUsedAt); c != 0 { + return c + } + return strings.Compare(a.ID, b.ID) }) } diff --git a/cli/command/formatter/container.go b/cli/command/formatter/container.go index b65209c26c..7b77a8a753 100644 --- a/cli/command/formatter/container.go +++ b/cli/command/formatter/container.go @@ -4,9 +4,10 @@ package formatter import ( + "cmp" "fmt" "net" - "sort" + "slices" "strconv" "strings" "time" @@ -295,7 +296,7 @@ func (c *ContainerContext) Labels() string { for k, v := range c.c.Labels { joinLabels = append(joinLabels, k+"="+v) } - sort.Strings(joinLabels) + slices.Sort(joinLabels) return strings.Join(joinLabels, ",") } @@ -395,9 +396,7 @@ func DisplayablePorts(ports []container.PortSummary) string { var result []string var hostMappings []string var groupMapKeys []string - sort.Slice(ports, func(i, j int) bool { - return comparePorts(ports[i], ports[j]) - }) + slices.SortFunc(ports, comparePorts) for _, port := range ports { current := port.PrivatePort @@ -452,18 +451,13 @@ func formGroup(key string, start, last uint16) string { return group + "/" + groupType } -func comparePorts(i, j container.PortSummary) bool { - if i.PrivatePort != j.PrivatePort { - return i.PrivatePort < j.PrivatePort - } - - if i.IP != j.IP { - return i.IP.Less(j.IP) - } - - if i.PublicPort != j.PublicPort { - return i.PublicPort < j.PublicPort - } - - return i.Type < j.Type +// comparePorts compares ports by private port, IP address, public port, +// and protocol, in that order. +func comparePorts(a, b container.PortSummary) int { + return cmp.Or( + cmp.Compare(a.PrivatePort, b.PrivatePort), + a.IP.Compare(b.IP), + cmp.Compare(a.PublicPort, b.PublicPort), + cmp.Compare(a.Type, b.Type), + ) } diff --git a/cli/command/image/build/internal/git/gitutils.go b/cli/command/image/build/internal/git/gitutils.go index e9245cb098..82b7188324 100644 --- a/cli/command/image/build/internal/git/gitutils.go +++ b/cli/command/image/build/internal/git/gitutils.go @@ -1,3 +1,6 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package git import ( @@ -7,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "github.com/moby/sys/symlink" @@ -202,7 +206,7 @@ func (repo gitRepo) checkout(root string) (string, error) { } func (repo gitRepo) gitWithinDir(dir string, args ...string) ([]byte, error) { - args = append([]string{"-c", "protocol.file.allow=never"}, args...) // Block sneaky repositories from using repos from the filesystem as submodules. + args = slices.Concat([]string{"-c", "protocol.file.allow=never"}, args) // Block sneaky repositories from using repos from the filesystem as submodules. cmd := exec.Command("git", args...) cmd.Dir = dir // Disable unsafe remote protocols. diff --git a/cli/command/image/build_test.go b/cli/command/image/build_test.go index 88d94d6cde..1d61d05bbe 100644 --- a/cli/command/image/build_test.go +++ b/cli/command/image/build_test.go @@ -8,7 +8,7 @@ import ( "io" "os" "path/filepath" - "sort" + "slices" "testing" "github.com/docker/cli/cli/streams" @@ -211,6 +211,6 @@ func (f *fakeBuild) filenames(t *testing.T) []string { for _, header := range h { names = append(names, header.Name) } - sort.Strings(names) + slices.Sort(names) return names } diff --git a/cli/command/image/push_test.go b/cli/command/image/push_test.go index e0e0195e6a..3dbca45ca9 100644 --- a/cli/command/image/push_test.go +++ b/cli/command/image/push_test.go @@ -102,9 +102,11 @@ func TestRunPushRespectsNoColorForAuxNotes(t *testing.T) { SelectedManifest: ocispec.Descriptor{Digest: "sha256:2222222222222222222222222222222222222222222222222222222222222222"}, }) assert.NilError(t, err) - line := append([]byte(`{"aux":`), aux...) - line = append(line, '}', '\n') - return fakeStreamResult{ReadCloser: io.NopCloser(bytes.NewReader(line))}, nil + var buf bytes.Buffer + buf.WriteString(`{"aux":`) + buf.Write(aux) + buf.WriteString("}\n") + return fakeStreamResult{ReadCloser: io.NopCloser(&buf)}, nil }, }) cli.Out().SetIsTerminal(true) diff --git a/cli/command/service/formatter.go b/cli/command/service/formatter.go index 1ec5263deb..5b77bbb1a5 100644 --- a/cli/command/service/formatter.go +++ b/cli/command/service/formatter.go @@ -1,8 +1,13 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package service import ( + "cmp" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -775,17 +780,16 @@ func (c *serviceContext) Ports() string { return "" } - pr := portRange{} - ports := []string{} - - servicePorts := c.service.Endpoint.Ports - sort.Slice(servicePorts, func(i, j int) bool { - if servicePorts[i].Protocol == servicePorts[j].Protocol { - return servicePorts[i].PublishedPort < servicePorts[j].PublishedPort - } - return servicePorts[i].Protocol < servicePorts[j].Protocol + // Sort by protocol first, then by published port. + slices.SortFunc(c.service.Endpoint.Ports, func(a, b swarm.PortConfig) int { + return cmp.Or( + cmp.Compare(a.Protocol, b.Protocol), + cmp.Compare(a.PublishedPort, b.PublishedPort), + ) }) + var pr portRange + var ports []string for _, p := range c.service.Endpoint.Ports { if p.PublishMode == swarm.PortConfigPublishModeIngress { prIsRange := pr.tEnd != pr.tStart diff --git a/cli/command/service/logs.go b/cli/command/service/logs.go index 3474423325..79908b8657 100644 --- a/cli/command/service/logs.go +++ b/cli/command/service/logs.go @@ -1,3 +1,6 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package service import ( @@ -6,7 +9,7 @@ import ( "errors" "fmt" "io" - "sort" + "slices" "strconv" "strings" @@ -314,7 +317,7 @@ func (lw *logWriter) Write(buf []byte) (int, error) { d = append(d, k+"="+details[k]) } // then sort em - sort.Strings(d) + slices.Sort(d) // then join and append output = append(output, []byte(strings.Join(d, ","))...) output = append(output, ' ') diff --git a/cli/command/service/opts.go b/cli/command/service/opts.go index e04f392e46..e2758e64cd 100644 --- a/cli/command/service/opts.go +++ b/cli/command/service/opts.go @@ -4,12 +4,12 @@ package service import ( + "cmp" "context" "errors" "fmt" "net/netip" "slices" - "sort" "strconv" "strings" "time" @@ -737,15 +737,15 @@ func (options *serviceOptions) ToService(ctx context.Context, apiClient client.N } networks := convertNetworks(options.networks) - for i, net := range networks { - nwID, err := resolveNetworkID(ctx, apiClient, net.Target) + for i := range networks { + nwID, err := resolveNetworkID(ctx, apiClient, networks[i].Target) if err != nil { return service, err } networks[i].Target = nwID } - sort.Slice(networks, func(i, j int) bool { - return networks[i].Target < networks[j].Target + slices.SortFunc(networks, func(a, b swarm.NetworkAttachmentConfig) int { + return cmp.Compare(a.Target, b.Target) }) resources, err := options.resources.ToResourceRequirements(flags) diff --git a/cli/command/service/update.go b/cli/command/service/update.go index 7520b08891..f3f7df4314 100644 --- a/cli/command/service/update.go +++ b/cli/command/service/update.go @@ -4,13 +4,13 @@ package service import ( + "cmp" "context" "errors" "fmt" "maps" "net/netip" "slices" - "sort" "strings" "time" @@ -635,7 +635,7 @@ func updatePlacementConstraints(flags *pflag.FlagSet, placement *swarm.Placement } } // Sort so that result is predictable. - sort.Strings(newConstraints) + slices.Sort(newConstraints) placement.Constraints = newConstraints } @@ -720,7 +720,7 @@ func updateSysCtls(flags *pflag.FlagSet, field *map[string]string) { } func updateUlimits(flags *pflag.FlagSet, ulimits []*container.Ulimit) []*container.Ulimit { - newUlimits := make(map[string]*container.Ulimit) + newUlimits := make(map[string]*container.Ulimit, len(ulimits)) for _, ulimit := range ulimits { newUlimits[ulimit.Name] = ulimit @@ -737,17 +737,9 @@ func updateUlimits(flags *pflag.FlagSet, ulimits []*container.Ulimit) []*contain newUlimits[ulimit.Name] = ulimit } } - if len(newUlimits) == 0 { - return nil - } - limits := make([]*container.Ulimit, 0, len(newUlimits)) - for _, ulimit := range newUlimits { - limits = append(limits, ulimit) - } - sort.SliceStable(limits, func(i, j int) bool { - return limits[i].Name < limits[j].Name + return slices.SortedFunc(maps.Values(newUlimits), func(a, b *container.Ulimit) int { + return cmp.Compare(a.Name, b.Name) }) - return limits } func updateEnvironment(flags *pflag.FlagSet, field *[]string) { @@ -953,14 +945,12 @@ func updateMounts(flags *pflag.FlagSet, mounts *[]mount.Mount) error { newMounts = append(newMounts, mnt) } } - sort.Slice(newMounts, func(i, j int) bool { - a, b := newMounts[i], newMounts[j] - - if a.Source == b.Source { - return a.Target < b.Target - } - - return a.Source < b.Source + // Sort mounts by source, then by target. + slices.SortFunc(newMounts, func(a, b mount.Mount) int { + return cmp.Or( + cmp.Compare(a.Source, b.Source), + cmp.Compare(a.Target, b.Target), + ) }) *mounts = newMounts return nil @@ -980,7 +970,7 @@ func updateGroups(flags *pflag.FlagSet, groups *[]string) error { } } // Sort so that result is predictable. - sort.Strings(newGroups) + slices.Sort(newGroups) *groups = newGroups return nil @@ -1039,7 +1029,7 @@ func updateDNSConfig(flags *pflag.FlagSet, config **swarm.DNSConfig) error { } } // Sort so that result is predictable. - sort.Strings(newConfig.Search) + slices.Sort(newConfig.Search) options := (*config).Options if flags.Changed(flagDNSOptionAdd) { @@ -1054,7 +1044,7 @@ func updateDNSConfig(flags *pflag.FlagSet, config **swarm.DNSConfig) error { } } // Sort so that result is predictable. - sort.Strings(newConfig.Options) + slices.Sort(newConfig.Options) *config = newConfig return nil @@ -1107,12 +1097,8 @@ portLoop: } } - // Sort the PortConfig to avoid unnecessary updates - sort.Slice(newPorts, func(i, j int) bool { - // We convert PortConfig into `port/protocol`, e.g., `80/tcp` - // In updatePorts we already filter out with map so there is duplicate entries - return portConfigToString(&newPorts[i]) < portConfigToString(&newPorts[j]) - }) + // Sort the PortConfig to avoid unnecessary updates. + slices.SortFunc(newPorts, swarm.PortConfig.Compare) *portConfig = newPorts return nil } @@ -1348,8 +1334,8 @@ func updateNetworks(ctx context.Context, apiClient client.NetworkAPIClient, flag } } - sort.Slice(newNetworks, func(i, j int) bool { - return newNetworks[i].Target < newNetworks[j].Target + slices.SortFunc(newNetworks, func(a, b swarm.NetworkAttachmentConfig) int { + return cmp.Compare(a.Target, b.Target) }) spec.TaskTemplate.Networks = newNetworks @@ -1523,10 +1509,6 @@ func capsList(caps map[string]bool) []string { if caps[opts.AllCapabilities] { return []string{opts.AllCapabilities} } - out := make([]string, 0, len(caps)) - for c := range caps { - out = append(out, c) - } - sort.Strings(out) - return out + + return slices.Sorted(maps.Keys(caps)) } diff --git a/cli/command/service/update_test.go b/cli/command/service/update_test.go index 6158820951..1211360bcb 100644 --- a/cli/command/service/update_test.go +++ b/cli/command/service/update_test.go @@ -4,7 +4,7 @@ import ( "context" "fmt" "net/netip" - "sort" + "slices" "strconv" "testing" "time" @@ -141,7 +141,7 @@ func TestUpdateEnvironment(t *testing.T) { updateEnvironment(flags, &envs) assert.Assert(t, is.Len(envs, 2)) // Order has been removed in updateEnvironment (map) - sort.Strings(envs) + slices.Sort(envs) assert.Check(t, is.Equal("toadd=newenv", envs[0])) assert.Check(t, is.Equal("tokeep=value", envs[1])) } @@ -282,7 +282,7 @@ func TestUpdatePorts(t *testing.T) { assert.Assert(t, is.Len(portConfigs, 2)) // Do a sort to have the order (might have changed by map) targetPorts := []int{int(portConfigs[0].TargetPort), int(portConfigs[1].TargetPort)} - sort.Ints(targetPorts) + slices.Sort(targetPorts) assert.Check(t, is.Equal(555, targetPorts[0])) assert.Check(t, is.Equal(1000, targetPorts[1])) } diff --git a/cli/command/stack/loader.go b/cli/command/stack/loader.go index 49366e4d50..10579a08d8 100644 --- a/cli/command/stack/loader.go +++ b/cli/command/stack/loader.go @@ -10,7 +10,7 @@ import ( "os" "path/filepath" "runtime" - "sort" + "slices" "strings" "github.com/distribution/reference" @@ -75,9 +75,9 @@ func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]any { func propertyWarnings(properties map[string]string) string { msgs := make([]string, 0, len(properties)) for name, description := range properties { - msgs = append(msgs, fmt.Sprintf("%s: %s", name, description)) + msgs = append(msgs, name+": "+description) } - sort.Strings(msgs) + slices.Sort(msgs) return strings.Join(msgs, "\n\n") } diff --git a/cli/command/stack/remove.go b/cli/command/stack/remove.go index 90ab2df29b..2f6d061b35 100644 --- a/cli/command/stack/remove.go +++ b/cli/command/stack/remove.go @@ -1,10 +1,14 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package stack import ( + "cmp" "context" "errors" "fmt" - "sort" + "slices" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -96,15 +100,11 @@ func runRemove(ctx context.Context, dockerCli command.Cli, opts removeOptions) e return errors.Join(errs...) } -func sortServiceByName(services []swarm.Service) func(i, j int) bool { - return func(i, j int) bool { - return services[i].Spec.Name < services[j].Spec.Name - } -} - func removeServices(ctx context.Context, dockerCLI command.Cli, services []swarm.Service) bool { + slices.SortFunc(services, func(a, b swarm.Service) int { + return cmp.Compare(a.Spec.Name, b.Spec.Name) + }) var hasError bool - sort.Slice(services, sortServiceByName(services)) for _, service := range services { _, _ = fmt.Fprintln(dockerCLI.Out(), "Removing service", service.Spec.Name) if _, err := dockerCLI.Client().ServiceRemove(ctx, service.ID, client.ServiceRemoveOptions{}); err != nil { diff --git a/cli/command/system/events.go b/cli/command/system/events.go index eb77c6c6b2..36264ef010 100644 --- a/cli/command/system/events.go +++ b/cli/command/system/events.go @@ -1,10 +1,14 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package system import ( "context" "fmt" "io" - "sort" + "maps" + "slices" "strings" "text/template" "time" @@ -133,18 +137,13 @@ func prettyPrintEvent(out io.Writer, event events.Message) error { _, _ = fmt.Fprintf(out, "%s %s %s", event.Type, event.Action, event.Actor.ID) if len(event.Actor.Attributes) > 0 { - keys := make([]string, 0, len(event.Actor.Attributes)) - for k := range event.Actor.Attributes { - keys = append(keys, k) - } - sort.Strings(keys) + keys := slices.Sorted(maps.Keys(event.Actor.Attributes)) attrs := make([]string, 0, len(keys)) for _, k := range keys { - v := event.Actor.Attributes[k] - attrs = append(attrs, k+"="+v) + attrs = append(attrs, k+"="+event.Actor.Attributes[k]) } _, _ = fmt.Fprintf(out, " (%s)", strings.Join(attrs, ", ")) } - _, _ = fmt.Fprint(out, "\n") + _, _ = fmt.Fprintln(out) return nil } diff --git a/cli/command/system/info.go b/cli/command/system/info.go index 80a21629ec..fcc533c426 100644 --- a/cli/command/system/info.go +++ b/cli/command/system/info.go @@ -8,7 +8,7 @@ import ( "errors" "fmt" "io" - "sort" + "slices" "strings" "github.com/docker/cli/cli" @@ -468,11 +468,11 @@ func printSwarmInfo(output io.Writer, info system.Info) { } fprintln(output, " Node Address:", info.Swarm.NodeAddr) if len(info.Swarm.RemoteManagers) > 0 { - managers := []string{} + managers := make([]string, 0, len(info.Swarm.RemoteManagers)) for _, entry := range info.Swarm.RemoteManagers { managers = append(managers, entry.Addr) } - sort.Strings(managers) + slices.Sort(managers) fprintln(output, " Manager Addresses:") for _, entry := range managers { fprintf(output, " %s\n", entry) diff --git a/cli/command/system/version.go b/cli/command/system/version.go index b385ef7181..41b7de87c9 100644 --- a/cli/command/system/version.go +++ b/cli/command/system/version.go @@ -1,11 +1,15 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.26 + package system import ( "context" "fmt" "io" + "maps" "runtime" - "sort" + "slices" "strconv" "text/template" "time" @@ -252,10 +256,5 @@ func newVersionTemplate(templateFormat string) (*template.Template, error) { } func getDetailsOrder(v system.ComponentVersion) []string { - out := make([]string, 0, len(v.Details)) - for k := range v.Details { - out = append(out, k) - } - sort.Strings(out) - return out + return slices.Sorted(maps.Keys(v.Details)) } diff --git a/cli/command/volume/create_test.go b/cli/command/volume/create_test.go index 7f8a2c387c..3f9e43cdc0 100644 --- a/cli/command/volume/create_test.go +++ b/cli/command/volume/create_test.go @@ -8,11 +8,11 @@ import ( "fmt" "io" "maps" - "sort" "strings" "testing" "github.com/docker/cli/internal/test" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/moby/moby/api/types/volume" "github.com/moby/moby/client" "gotest.tools/v3/assert" @@ -230,10 +230,9 @@ func TestVolumeCreateClusterOpts(t *testing.T) { cli := test.NewFakeCli(&fakeClient{ volumeCreateFunc: func(options client.VolumeCreateOptions) (client.VolumeCreateResult, error) { - sort.SliceStable(options.ClusterVolumeSpec.Secrets, func(i, j int) bool { - return options.ClusterVolumeSpec.Secrets[i].Key < options.ClusterVolumeSpec.Secrets[j].Key - }) - assert.DeepEqual(t, options, expectedOptions) + assert.Check(t, is.DeepEqual(options, expectedOptions, cmpopts.SortSlices(func(a, b volume.Secret) bool { + return a.Key < b.Key + }))) return client.VolumeCreateResult{}, nil }, })