diff --git a/pkg/compose/create.go b/pkg/compose/create.go index ab888dce71b..a3e1a19fc32 100644 --- a/pkg/compose/create.go +++ b/pkg/compose/create.go @@ -24,6 +24,7 @@ import ( "fmt" "os" "path/filepath" + "slices" "strconv" "strings" @@ -32,7 +33,6 @@ import ( "github.com/docker/compose/v2/pkg/api" "github.com/docker/compose/v2/pkg/progress" "github.com/docker/compose/v2/pkg/prompt" - "github.com/docker/compose/v2/pkg/utils" "github.com/docker/docker/api/types/blkiodev" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -1312,8 +1312,8 @@ func (s *composeService) resolveOrCreateNetwork(ctx context.Context, project *ty } // NetworkList Matches all or part of a network name, so we have to filter for a strict match - networks = utils.Filter(networks, func(net network.Summary) bool { - return net.Name == n.Name + networks = slices.DeleteFunc(networks, func(net network.Summary) bool { + return net.Name != n.Name }) for _, net := range networks { @@ -1436,18 +1436,19 @@ func (s *composeService) resolveExternalNetwork(ctx context.Context, n *types.Ne if len(networks) == 0 { // in this instance, n.Name is really an ID sn, err := s.apiClient().NetworkInspect(ctx, n.Name, network.InspectOptions{}) - if err != nil && !errdefs.IsNotFound(err) { + if err == nil { + networks = append(networks, sn) + } else if !errdefs.IsNotFound(err) { return "", err } - networks = append(networks, sn) + } // NetworkList API doesn't return the exact name match, so we can retrieve more than one network with a request - networks = utils.Filter(networks, func(net network.Inspect) bool { - // later in this function, the name is changed the to ID. + networks = slices.DeleteFunc(networks, func(net network.Inspect) bool { // this function is called during the rebuild stage of `compose watch`. // we still require just one network back, but we need to run the search on the ID - return net.Name == n.Name || net.ID == n.Name + return net.Name != n.Name && net.ID != n.Name }) switch len(networks) { diff --git a/pkg/compose/dependencies.go b/pkg/compose/dependencies.go index 19660e8e886..812e45c986f 100644 --- a/pkg/compose/dependencies.go +++ b/pkg/compose/dependencies.go @@ -26,8 +26,6 @@ import ( "github.com/compose-spec/compose-go/v2/types" "github.com/docker/compose/v2/pkg/api" "golang.org/x/sync/errgroup" - - "github.com/docker/compose/v2/pkg/utils" ) // ServiceStatus indicates the status of a service @@ -120,7 +118,7 @@ func WithRootNodesAndDown(nodes []string) func(*graphTraversal) { t.ignored = map[string]struct{}{} for k := range graph.Vertices { - if !utils.Contains(want, k) { + if !slices.Contains(want, k) { t.ignored[k] = struct{}{} } } diff --git a/pkg/compose/generate.go b/pkg/compose/generate.go index 157c1384e6c..61906b94946 100644 --- a/pkg/compose/generate.go +++ b/pkg/compose/generate.go @@ -19,11 +19,11 @@ package compose import ( "context" "fmt" + "slices" "strings" "github.com/compose-spec/compose-go/v2/types" "github.com/docker/compose/v2/pkg/api" - "github.com/docker/compose/v2/pkg/utils" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/mount" @@ -54,8 +54,11 @@ func (s *composeService) Generate(ctx context.Context, options api.GenerateOptio if err != nil { return nil, err } + for _, ctr := range containersByIds { - if !utils.Contains(containers, ctr) { + if !slices.ContainsFunc(containers, func(summary container.Summary) bool { + return summary.ID == ctr.ID + }) { containers = append(containers, ctr) } } diff --git a/pkg/compose/run.go b/pkg/compose/run.go index ebc974aa0f9..b88d9767daa 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -22,12 +22,12 @@ import ( "fmt" "os" "os/signal" + "slices" "github.com/compose-spec/compose-go/v2/types" "github.com/docker/cli/cli" cmd "github.com/docker/cli/cli/command/container" "github.com/docker/compose/v2/pkg/api" - "github.com/docker/compose/v2/pkg/utils" "github.com/docker/docker/pkg/stringid" ) @@ -130,11 +130,11 @@ func applyRunOptions(project *types.Project, service *types.ServiceConfig, opts if len(opts.CapAdd) > 0 { service.CapAdd = append(service.CapAdd, opts.CapAdd...) - service.CapDrop = utils.Remove(service.CapDrop, opts.CapAdd...) + service.CapDrop = slices.DeleteFunc(service.CapDrop, func(e string) bool { return slices.Contains(opts.CapAdd, e) }) } if len(opts.CapDrop) > 0 { service.CapDrop = append(service.CapDrop, opts.CapDrop...) - service.CapAdd = utils.Remove(service.CapAdd, opts.CapDrop...) + service.CapAdd = slices.DeleteFunc(service.CapAdd, func(e string) bool { return slices.Contains(opts.CapDrop, e) }) } if opts.WorkingDir != "" { service.WorkingDir = opts.WorkingDir diff --git a/pkg/compose/start.go b/pkg/compose/start.go index 06d73d9ccde..b80abc9a1a8 100644 --- a/pkg/compose/start.go +++ b/pkg/compose/start.go @@ -20,6 +20,7 @@ import ( "context" "errors" "fmt" + "slices" "strings" "time" @@ -199,7 +200,7 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo ofInterest := func(c containerType.Summary) bool { if len(services) > 0 { // we only watch some services - return utils.Contains(services, c.Labels[api.ServiceLabel]) + return slices.Contains(services, c.Labels[api.ServiceLabel]) } return true } @@ -208,7 +209,7 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo isRequired := func(c containerType.Summary) bool { if len(services) > 0 && len(required) > 0 { // we only watch some services - return utils.Contains(required, c.Labels[api.ServiceLabel]) + return slices.Contains(required, c.Labels[api.ServiceLabel]) } return true } @@ -263,8 +264,8 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo } if _, ok := watched[container.ID]; ok { eType := api.ContainerEventStopped - if utils.Contains(replaced, container.ID) { - utils.Remove(replaced, container.ID) + if slices.Contains(replaced, container.ID) { + replaced = slices.DeleteFunc(replaced, func(e string) bool { return e == container.ID }) eType = api.ContainerEventRecreated } listener(api.ContainerEvent{ @@ -290,8 +291,8 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo } eType := api.ContainerEventExit - if utils.Contains(replaced, container.ID) { - utils.Remove(replaced, container.ID) + if slices.Contains(replaced, container.ID) { + replaced = slices.DeleteFunc(replaced, func(e string) bool { return e == container.ID }) eType = api.ContainerEventRecreated } diff --git a/pkg/utils/slices.go b/pkg/utils/slices.go deleted file mode 100644 index 6dbf1c6e776..00000000000 --- a/pkg/utils/slices.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package utils - -import "reflect" - -// Contains helps to detect if a non-comparable struct is part of an array -// only use this method if you can't rely on existing golang Contains function of slices (https://pkg.go.dev/golang.org/x/exp/slices#Contains) -func Contains[T any](origin []T, element T) bool { - for _, v := range origin { - if reflect.DeepEqual(v, element) { - return true - } - } - return false -} - -// Remove removes all elements from origin slice -func Remove[T any](origin []T, elements ...T) []T { - var filtered []T - for _, v := range origin { - if !Contains(elements, v) { - filtered = append(filtered, v) - } - } - return filtered -} - -func Filter[T any](elements []T, predicate func(T) bool) []T { - var filtered []T - for _, v := range elements { - if predicate(v) { - filtered = append(filtered, v) - } - } - return filtered -} diff --git a/pkg/utils/slices_test.go b/pkg/utils/slices_test.go deleted file mode 100644 index d9468afef29..00000000000 --- a/pkg/utils/slices_test.go +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright 2020 Docker Compose CLI authors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package utils - -import ( - "testing" - - specs "github.com/opencontainers/image-spec/specs-go/v1" -) - -func TestContains(t *testing.T) { - source := []specs.Platform{ - { - Architecture: "linux/amd64", - OS: "darwin", - OSVersion: "", - OSFeatures: nil, - Variant: "", - }, - { - Architecture: "linux/arm64", - OS: "linux", - OSVersion: "12", - OSFeatures: nil, - Variant: "v8", - }, - { - Architecture: "", - OS: "", - OSVersion: "", - OSFeatures: nil, - Variant: "", - }, - } - - type args struct { - origin []specs.Platform - element specs.Platform - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "element found", - args: args{ - origin: source, - element: specs.Platform{ - Architecture: "linux/arm64", - OS: "linux", - OSVersion: "12", - OSFeatures: nil, - Variant: "v8", - }, - }, - want: true, - }, - { - name: "element not found", - args: args{ - origin: source, - element: specs.Platform{ - Architecture: "linux/arm64", - OS: "darwin", - OSVersion: "12", - OSFeatures: nil, - Variant: "v8", - }, - }, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := Contains(tt.args.origin, tt.args.element); got != tt.want { - t.Errorf("Contains() = %v, want %v", got, tt.want) - } - }) - } -}