@@ -22,18 +22,19 @@ import (
22
22
"os"
23
23
"path/filepath"
24
24
25
- "github.com/docker/buildx/builder"
26
- "github.com/docker/compose/v2/internal/tracing"
27
-
28
- "github.com/docker/buildx/controller/pb"
29
-
30
25
"github.com/compose-spec/compose-go/types"
31
26
"github.com/containerd/containerd/platforms"
32
27
"github.com/docker/buildx/build"
33
- _ "github.com/docker/buildx/driver/docker" // required to get default driver registered
28
+ "github.com/docker/buildx/builder"
29
+ "github.com/docker/buildx/controller/pb"
34
30
"github.com/docker/buildx/store/storeutil"
35
31
"github.com/docker/buildx/util/buildflags"
36
32
xprogress "github.com/docker/buildx/util/progress"
33
+ "github.com/docker/cli/cli/command"
34
+ "github.com/docker/compose/v2/internal/tracing"
35
+ "github.com/docker/compose/v2/pkg/api"
36
+ "github.com/docker/compose/v2/pkg/progress"
37
+ "github.com/docker/compose/v2/pkg/utils"
37
38
"github.com/docker/docker/builder/remotecontext/urlutil"
38
39
bclient "github.com/moby/buildkit/client"
39
40
"github.com/moby/buildkit/session"
@@ -45,9 +46,8 @@ import (
45
46
"github.com/pkg/errors"
46
47
"github.com/sirupsen/logrus"
47
48
48
- "github.com/docker/compose/v2/pkg/api"
49
- "github.com/docker/compose/v2/pkg/progress"
50
- "github.com/docker/compose/v2/pkg/utils"
49
+ // required to get default driver registered
50
+ _ "github.com/docker/buildx/driver/docker"
51
51
)
52
52
53
53
func (s * composeService ) Build (ctx context.Context , project * types.Project , options api.BuildOptions ) error {
@@ -61,9 +61,8 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
61
61
}, s .stdinfo (), "Building" )
62
62
}
63
63
64
- func (s * composeService ) build (ctx context.Context , project * types.Project , options api.BuildOptions ) (map [string ]string , error ) { //nolint:gocyclo
65
- args := options .Args .Resolve (envResolver (project .Environment ))
66
-
64
+ //nolint:gocyclo
65
+ func (s * composeService ) build (ctx context.Context , project * types.Project , options api.BuildOptions ) (map [string ]string , error ) {
67
66
buildkitEnabled , err := s .dockerCli .BuildKitEnabled ()
68
67
if err != nil {
69
68
return nil , err
@@ -119,12 +118,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
119
118
}
120
119
121
120
if ! buildkitEnabled {
122
- if service .Build .Args == nil {
123
- service .Build .Args = args
124
- } else {
125
- service .Build .Args = service .Build .Args .OverrideBy (args )
126
- }
127
- id , err := s .doBuildClassic (ctx , project .Name , service , options )
121
+ id , err := s .doBuildClassic (ctx , project , service , options )
128
122
if err != nil {
129
123
return err
130
124
}
@@ -144,7 +138,6 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
144
138
if err != nil {
145
139
return err
146
140
}
147
- buildOptions .BuildArgs = mergeArgs (buildOptions .BuildArgs , flatten (args ))
148
141
149
142
digest , err := s .doBuildBuildkit (ctx , service .Name , buildOptions , w , nodes )
150
143
if err != nil {
@@ -337,15 +330,37 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
337
330
return images , nil
338
331
}
339
332
340
- func (s * composeService ) toBuildOptions (project * types.Project , service types.ServiceConfig , options api.BuildOptions ) (build.Options , error ) {
341
- buildArgs := flatten (service .Build .Args .Resolve (envResolver (project .Environment )))
342
-
343
- for k , v := range storeutil .GetProxyConfig (s .dockerCli ) {
344
- if _ , ok := buildArgs [k ]; ! ok {
345
- buildArgs [k ] = v
346
- }
347
- }
333
+ // resolveAndMergeBuildArgs returns the final set of build arguments to use for the service image build.
334
+ //
335
+ // First, args directly defined via `build.args` in YAML are considered.
336
+ // Then, any explicitly passed args in opts (e.g. via `--build-arg` on the CLI) are merged, overwriting any
337
+ // keys that already exist.
338
+ // Next, any keys without a value are resolved using the project environment.
339
+ //
340
+ // Finally, standard proxy variables based on the Docker client configuration are added, but will not overwrite
341
+ // any values if already present.
342
+ func resolveAndMergeBuildArgs (
343
+ dockerCli command.Cli ,
344
+ project * types.Project ,
345
+ service types.ServiceConfig ,
346
+ opts api.BuildOptions ,
347
+ ) types.MappingWithEquals {
348
+ result := make (types.MappingWithEquals ).
349
+ OverrideBy (service .Build .Args ).
350
+ OverrideBy (opts .Args ).
351
+ Resolve (envResolver (project .Environment ))
352
+
353
+ // proxy arguments do NOT override and should NOT have env resolution applied,
354
+ // so they're handled last
355
+ for k , v := range storeutil .GetProxyConfig (dockerCli ) {
356
+ if _ , ok := result [k ]; ! ok {
357
+ result [k ] = & v
358
+ }
359
+ }
360
+ return result
361
+ }
348
362
363
+ func (s * composeService ) toBuildOptions (project * types.Project , service types.ServiceConfig , options api.BuildOptions ) (build.Options , error ) {
349
364
plats , err := addPlatforms (project , service )
350
365
if err != nil {
351
366
return build.Options {}, err
@@ -418,7 +433,7 @@ func (s *composeService) toBuildOptions(project *types.Project, service types.Se
418
433
CacheTo : pb .CreateCaches (cacheTo ),
419
434
NoCache : service .Build .NoCache ,
420
435
Pull : service .Build .Pull ,
421
- BuildArgs : buildArgs ,
436
+ BuildArgs : flatten ( resolveAndMergeBuildArgs ( s . dockerCli , project , service , options )) ,
422
437
Tags : tags ,
423
438
Target : service .Build .Target ,
424
439
Exports : exports ,
@@ -445,16 +460,6 @@ func flatten(in types.MappingWithEquals) types.Mapping {
445
460
return out
446
461
}
447
462
448
- func mergeArgs (m ... types.Mapping ) types.Mapping {
449
- merged := types.Mapping {}
450
- for _ , mapping := range m {
451
- for key , val := range mapping {
452
- merged [key ] = val
453
- }
454
- }
455
- return merged
456
- }
457
-
458
463
func dockerFilePath (ctxName string , dockerfile string ) string {
459
464
if dockerfile == "" {
460
465
return ""
0 commit comments