@@ -19,6 +19,7 @@ package compose
19
19
import (
20
20
"context"
21
21
"fmt"
22
+ "os"
22
23
"path/filepath"
23
24
24
25
"github.com/compose-spec/compose-go/types"
@@ -53,68 +54,83 @@ func (s *composeService) Build(ctx context.Context, project *types.Project, opti
53
54
}, s .stderr (), "Building" )
54
55
}
55
56
56
- func (s * composeService ) build (ctx context.Context , project * types.Project , options api.BuildOptions ) (map [string ]string , error ) {
57
+ func (s * composeService ) build (ctx context.Context , project * types.Project , options api.BuildOptions ) (map [string ]string , error ) { //nolint:gocyclo
57
58
args := options .Args .Resolve (envResolver (project .Environment ))
58
59
59
60
buildkitEnabled , err := s .dockerCli .BuildKitEnabled ()
60
61
if err != nil {
61
62
return nil , err
62
63
}
64
+
65
+ // Progress needs its own context that lives longer than the
66
+ // build one otherwise it won't read all the messages from
67
+ // build and will lock
68
+ progressCtx , cancel := context .WithCancel (context .Background ())
69
+ defer cancel ()
70
+ w , err := xprogress .NewPrinter (progressCtx , s .stdout (), os .Stdout , options .Progress )
71
+ if err != nil {
72
+ return nil , err
73
+ }
74
+
63
75
builtIDs := make ([]string , len (project .Services ))
64
76
err = InDependencyOrder (ctx , project , func (ctx context.Context , name string ) error {
65
77
if len (options .Services ) > 0 && ! utils .Contains (options .Services , name ) {
66
78
return nil
67
79
}
68
- for i , service := range project .Services {
69
- if service .Name != name {
70
- continue
71
- }
72
-
73
- if service .Build == nil {
74
- return nil
75
- }
80
+ service , idx := getServiceIndex (project , name )
76
81
77
- if ! buildkitEnabled {
78
- if service .Build .Args == nil {
79
- service .Build .Args = args
80
- } else {
81
- service .Build .Args = service .Build .Args .OverrideBy (args )
82
- }
83
- id , err := s .doBuildClassic (ctx , service , options )
84
- if err != nil {
85
- return err
86
- }
87
- builtIDs [i ] = id
88
-
89
- if options .Push {
90
- return s .push (ctx , project , api.PushOptions {})
91
- }
92
- return nil
93
- }
82
+ if service .Build == nil {
83
+ return nil
84
+ }
94
85
95
- if options .Memory != 0 {
96
- fmt .Fprintln (s .stderr (), "WARNING: --memory is not supported by BuildKit and will be ignored." )
86
+ if ! buildkitEnabled {
87
+ if service .Build .Args == nil {
88
+ service .Build .Args = args
89
+ } else {
90
+ service .Build .Args = service .Build .Args .OverrideBy (args )
97
91
}
98
-
99
- buildOptions , err := s .toBuildOptions (project , service , options )
92
+ id , err := s .doBuildClassic (ctx , service , options )
100
93
if err != nil {
101
94
return err
102
95
}
103
- buildOptions .BuildArgs = mergeArgs (buildOptions .BuildArgs , flatten (args ))
104
- opts := map [string ]build.Options {service .Name : buildOptions }
96
+ builtIDs [idx ] = id
105
97
106
- ids , err := s .doBuildBuildkit (ctx , opts , options .Progress )
107
- if err != nil {
108
- return err
98
+ if options .Push {
99
+ return s .push (ctx , project , api.PushOptions {})
109
100
}
110
- builtIDs [i ] = ids [service .Name ]
111
101
return nil
112
102
}
103
+
104
+ if options .Memory != 0 {
105
+ fmt .Fprintln (s .stderr (), "WARNING: --memory is not supported by BuildKit and will be ignored." )
106
+ }
107
+
108
+ buildOptions , err := s .toBuildOptions (project , service , options )
109
+ if err != nil {
110
+ return err
111
+ }
112
+ buildOptions .BuildArgs = mergeArgs (buildOptions .BuildArgs , flatten (args ))
113
+
114
+ ids , err := s .doBuildBuildkit (ctx , service .Name , buildOptions , w )
115
+ if err != nil {
116
+ return err
117
+ }
118
+ builtIDs [idx ] = ids [service .Name ]
119
+
113
120
return nil
114
121
}, func (traversal * graphTraversal ) {
115
122
traversal .maxConcurrency = s .maxConcurrency
116
123
})
117
124
125
+ // enforce all build event get consumed
126
+ if errw := w .Wait (); errw != nil {
127
+ return nil , errw
128
+ }
129
+
130
+ if err != nil {
131
+ return nil , err
132
+ }
133
+
118
134
imageIDs := map [string ]string {}
119
135
for i , d := range builtIDs {
120
136
if d != "" {
@@ -124,6 +140,18 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
124
140
return imageIDs , err
125
141
}
126
142
143
+ func getServiceIndex (project * types.Project , name string ) (types.ServiceConfig , int ) {
144
+ var service types.ServiceConfig
145
+ var idx int
146
+ for i , s := range project .Services {
147
+ if s .Name == name {
148
+ idx , service = i , s
149
+ break
150
+ }
151
+ }
152
+ return service , idx
153
+ }
154
+
127
155
func (s * composeService ) ensureImagesExists (ctx context.Context , project * types.Project , quietPull bool ) error {
128
156
for _ , service := range project .Services {
129
157
if service .Image == "" && service .Build == nil {
0 commit comments