diff --git a/pkg/compose/build.go b/pkg/compose/build.go index 8cb9950c22..a64c41a60d 100644 --- a/pkg/compose/build.go +++ b/pkg/compose/build.go @@ -22,6 +22,7 @@ import ( "fmt" "os" "path/filepath" + "sync" "github.com/compose-spec/compose-go/types" "github.com/containerd/containerd/platforms" @@ -33,6 +34,10 @@ import ( xprogress "github.com/docker/buildx/util/progress" "github.com/docker/cli/cli/command" cliopts "github.com/docker/cli/opts" + "github.com/docker/compose/v2/internal/tracing" + "github.com/docker/compose/v2/pkg/api" + "github.com/docker/compose/v2/pkg/progress" + "github.com/docker/compose/v2/pkg/utils" "github.com/docker/docker/builder/remotecontext/urlutil" "github.com/docker/go-units" bclient "github.com/moby/buildkit/client" @@ -44,11 +49,6 @@ import ( specs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" - "github.com/docker/compose/v2/internal/tracing" - "github.com/docker/compose/v2/pkg/api" - "github.com/docker/compose/v2/pkg/progress" - "github.com/docker/compose/v2/pkg/utils" - // required to get default driver registered _ "github.com/docker/buildx/driver/docker" ) @@ -64,6 +64,11 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti }, s.stdinfo(), "Building") } +type serviceToBuild struct { + idx int + service types.ServiceConfig +} + //nolint:gocyclo func (s *composeService) build(ctx context.Context, project *types.Project, options api.BuildOptions, localImages map[string]string) (map[string]string, error) { buildkitEnabled, err := s.dockerCli.BuildKitEnabled() @@ -71,6 +76,36 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti return nil, err } + imageIDs := map[string]string{} + serviceToBeBuild := map[string]serviceToBuild{} + mapServiceMutx := sync.Mutex{} + err = InDependencyOrder(ctx, project, func(ctx context.Context, name string) error { + if len(options.Services) > 0 && !utils.Contains(options.Services, name) { + return nil + } + service, idx := getServiceIndex(project, name) + + if service.Build == nil { + return nil + } + + image := api.GetImageNameOrDefault(service, project.Name) + _, localImagePresent := localImages[image] + if localImagePresent && service.PullPolicy != types.PullPolicyBuild { + return nil + } + mapServiceMutx.Lock() + serviceToBeBuild[name] = serviceToBuild{idx: idx, service: service} + mapServiceMutx.Unlock() + return nil + }, func(traversal *graphTraversal) { + traversal.maxConcurrency = s.maxConcurrency + }) + + if err != nil || len(serviceToBeBuild) == 0 { + return imageIDs, err + } + // Initialize buildkit nodes var ( b *builder.Builder @@ -114,17 +149,12 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti if len(options.Services) > 0 && !utils.Contains(options.Services, name) { return nil } - service, idx := getServiceIndex(project, name) - - if service.Build == nil { - return nil - } - - image := api.GetImageNameOrDefault(service, project.Name) - _, localImagePresent := localImages[image] - if localImagePresent && service.PullPolicy != types.PullPolicyBuild { + serviceToBuild, ok := serviceToBeBuild[name] + if !ok { return nil } + service := serviceToBuild.service + idx := serviceToBuild.idx if !buildkitEnabled { id, err := s.doBuildClassic(ctx, project, service, options) @@ -170,7 +200,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti return nil, err } - imageIDs := map[string]string{} for i, imageDigest := range builtDigests { if imageDigest != "" { imageRef := api.GetImageNameOrDefault(project.Services[i], project.Name)