@@ -22,6 +22,7 @@ import (
22
22
"fmt"
23
23
"os"
24
24
"path/filepath"
25
+ "sync"
25
26
26
27
"github.com/compose-spec/compose-go/types"
27
28
"github.com/containerd/containerd/platforms"
@@ -33,6 +34,10 @@ import (
33
34
xprogress "github.com/docker/buildx/util/progress"
34
35
"github.com/docker/cli/cli/command"
35
36
cliopts "github.com/docker/cli/opts"
37
+ "github.com/docker/compose/v2/internal/tracing"
38
+ "github.com/docker/compose/v2/pkg/api"
39
+ "github.com/docker/compose/v2/pkg/progress"
40
+ "github.com/docker/compose/v2/pkg/utils"
36
41
"github.com/docker/docker/builder/remotecontext/urlutil"
37
42
"github.com/docker/go-units"
38
43
bclient "github.com/moby/buildkit/client"
@@ -44,11 +49,6 @@ import (
44
49
specs "github.com/opencontainers/image-spec/specs-go/v1"
45
50
"github.com/sirupsen/logrus"
46
51
47
- "github.com/docker/compose/v2/internal/tracing"
48
- "github.com/docker/compose/v2/pkg/api"
49
- "github.com/docker/compose/v2/pkg/progress"
50
- "github.com/docker/compose/v2/pkg/utils"
51
-
52
52
// required to get default driver registered
53
53
_ "github.com/docker/buildx/driver/docker"
54
54
)
@@ -64,13 +64,48 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
64
64
}, s .stdinfo (), "Building" )
65
65
}
66
66
67
+ type serviceToBuild struct {
68
+ idx int
69
+ service types.ServiceConfig
70
+ }
71
+
67
72
//nolint:gocyclo
68
73
func (s * composeService ) build (ctx context.Context , project * types.Project , options api.BuildOptions , localImages map [string ]string ) (map [string ]string , error ) {
69
74
buildkitEnabled , err := s .dockerCli .BuildKitEnabled ()
70
75
if err != nil {
71
76
return nil , err
72
77
}
73
78
79
+ imageIDs := map [string ]string {}
80
+ serviceToBeBuild := map [string ]serviceToBuild {}
81
+ mapServiceMutx := sync.Mutex {}
82
+ err = InDependencyOrder (ctx , project , func (ctx context.Context , name string ) error {
83
+ if len (options .Services ) > 0 && ! utils .Contains (options .Services , name ) {
84
+ return nil
85
+ }
86
+ service , idx := getServiceIndex (project , name )
87
+
88
+ if service .Build == nil {
89
+ return nil
90
+ }
91
+
92
+ image := api .GetImageNameOrDefault (service , project .Name )
93
+ _ , localImagePresent := localImages [image ]
94
+ if localImagePresent && service .PullPolicy != types .PullPolicyBuild {
95
+ return nil
96
+ }
97
+ mapServiceMutx .Lock ()
98
+ serviceToBeBuild [name ] = serviceToBuild {idx : idx , service : service }
99
+ mapServiceMutx .Unlock ()
100
+ return nil
101
+ }, func (traversal * graphTraversal ) {
102
+ traversal .maxConcurrency = s .maxConcurrency
103
+ })
104
+
105
+ if err != nil || len (serviceToBeBuild ) == 0 {
106
+ return imageIDs , err
107
+ }
108
+
74
109
// Initialize buildkit nodes
75
110
var (
76
111
b * builder.Builder
@@ -114,17 +149,12 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
114
149
if len (options .Services ) > 0 && ! utils .Contains (options .Services , name ) {
115
150
return nil
116
151
}
117
- service , idx := getServiceIndex (project , name )
118
-
119
- if service .Build == nil {
120
- return nil
121
- }
122
-
123
- image := api .GetImageNameOrDefault (service , project .Name )
124
- _ , localImagePresent := localImages [image ]
125
- if localImagePresent && service .PullPolicy != types .PullPolicyBuild {
152
+ serviceToBuild , ok := serviceToBeBuild [name ]
153
+ if ! ok {
126
154
return nil
127
155
}
156
+ service := serviceToBuild .service
157
+ idx := serviceToBuild .idx
128
158
129
159
if ! buildkitEnabled {
130
160
id , err := s .doBuildClassic (ctx , project , service , options )
@@ -170,7 +200,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
170
200
return nil , err
171
201
}
172
202
173
- imageIDs := map [string ]string {}
174
203
for i , imageDigest := range builtDigests {
175
204
if imageDigest != "" {
176
205
imageRef := api .GetImageNameOrDefault (project .Services [i ], project .Name )
0 commit comments