@@ -5,8 +5,11 @@ import (
55 "context"
66 "encoding/json"
77 "fmt"
8+ "github.com/deislabs/cnab-go/bundle"
89 "github.com/docker/app/internal/packager"
10+ "github.com/docker/app/types"
911 "github.com/docker/distribution/reference"
12+ "github.com/moby/buildkit/client"
1013 "github.com/moby/buildkit/session"
1114 "github.com/moby/buildkit/session/auth/authprovider"
1215 "github.com/opencontainers/go-digest"
@@ -26,7 +29,6 @@ import (
2629 _ "github.com/docker/buildx/driver/docker" // required to get default driver registered, see driver/docker/factory.go:14
2730 "github.com/docker/cli/cli"
2831 "github.com/docker/cli/cli/command"
29- dockerclient "github.com/docker/docker/client"
3032 "github.com/moby/buildkit/util/appcontext"
3133 "github.com/spf13/cobra"
3234)
@@ -45,7 +47,7 @@ func buildCmd(dockerCli command.Cli) *cobra.Command {
4547 Use : "build [APPLICATION]" ,
4648 Short : "Build service images for the application" ,
4749 Example : `$ docker app build myapp.dockerapp` ,
48- Args : cli .RequiresRangeArgs ( 1 , 1 ),
50+ Args : cli .ExactArgs ( 1 ),
4951 RunE : func (cmd * cobra.Command , args []string ) error {
5052 tag , err := runBuild (dockerCli , args [0 ], opts )
5153 if err == nil {
@@ -73,33 +75,20 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
7375 defer app .Cleanup ()
7476 appname := app .Name
7577
76- bundle , err := makeBundleFromApp (dockerCli , app , nil )
78+ bundle , err := packager . MakeBundleFromApp (dockerCli , app , nil )
7779 if err != nil {
7880 return nil , err
7981 }
8082
81- ctx := appcontext .Context ()
82-
83- compose , err := bake .ParseCompose (app .Composes ()[0 ]) // Fixme can have > 1 composes ?
83+ targets , err := parseCompose (app )
8484 if err != nil {
8585 return nil , err
8686 }
8787
88- targets := map [string ]bake.Target {}
89- for _ , n := range compose .ResolveGroup ("default" ) {
90- t , err := compose .ResolveTarget (n )
91- if err != nil {
92- return nil , err
93- }
94- if t != nil {
95- targets [n ] = * t
96- }
97- }
98-
9988 for service , t := range targets {
10089 if strings .HasPrefix (* t .Context , "." ) {
10190 // Relative path in compose file under x.dockerapp refers to parent folder
102- // FIXME docker app init should maybe udate them ?
91+ // FIXME docker app init should maybe update them ?
10392 path , err := filepath .Abs (appname + "/../" + (* t .Context )[1 :])
10493 if err != nil {
10594 return nil , err
@@ -108,33 +97,19 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
10897 targets [service ] = t
10998 }
11099 }
111-
112- if logrus .IsLevelEnabled (logrus .DebugLevel ) {
113- dt , err := json .MarshalIndent (targets , "" , " " )
114- if err != nil {
115- return nil , err
116- }
117- logrus .Debug (string (dt ))
118- }
100+ debugTargets (targets )
119101
120102 buildopts , err := bake .TargetsToBuildOpt (targets , opt .noCache , opt .pull )
121103 if err != nil {
122104 return nil , err
123105 }
124106
125- buildContext := bytes . NewBuffer ( nil )
126- if err := packager . PackInvocationImageContext ( dockerCli , app , buildContext ); err != nil {
107+ buildopts [ "invocation-image" ], err = createInvocationImageBuildOptions ( dockerCli , app )
108+ if err != nil {
127109 return nil , err
128110 }
129111
130- buildopts ["invocation-image" ] = build.Options {
131- Inputs : build.Inputs {
132- InStream : buildContext ,
133- ContextPath : "-" ,
134- },
135- Session : []session.Attachable {authprovider .NewDockerAuthProvider (os .Stderr )},
136- }
137-
112+ ctx := appcontext .Context ()
138113 d , err := driver .GetDriver (ctx , "buildx_buildkit_default" , nil , dockerCli .Client (), nil , "" , nil )
139114 if err != nil {
140115 return nil , err
@@ -146,23 +121,19 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
146121 },
147122 }
148123
149- ctx2 , cancel := context .WithCancel (context . TODO () )
124+ ctx2 , cancel := context .WithCancel (ctx )
150125 defer cancel ()
151126
152127 pw := progress .NewPrinter (ctx2 , os .Stderr , opt .progress )
153- resp , err := build .Build (ctx2 , driverInfo , buildopts , dockerAPI (dockerCli ), dockerCli .ConfigFile (), pw )
128+
129+ // We rely on buildx "docker" builder integrated in docker engine, so don't nee a DockerAPI here
130+ resp , err := build .Build (ctx2 , driverInfo , buildopts , nil , dockerCli .ConfigFile (), pw )
154131 if err != nil {
155132 return nil , err
156133 }
157134
158135 fmt .Println ("Successfully built service images" )
159- if logrus .IsLevelEnabled (logrus .DebugLevel ) {
160- dt , err := json .MarshalIndent (resp , "" , " " )
161- if err != nil {
162- return nil , err
163- }
164- logrus .Debug (string (dt ))
165- }
136+ debugSolveResponses (resp )
166137
167138 for service , r := range resp {
168139 digest := r .ExporterResponse ["containerimage.digest" ]
@@ -175,33 +146,21 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
175146 image .Digest = digest
176147 bundle .Images [service ] = image
177148 }
178- fmt .Printf (" - %s : %s\n " , service , digest )
179- }
180-
181- if logrus .IsLevelEnabled (logrus .DebugLevel ) {
182- dt , err := json .MarshalIndent (resp , "" , " " )
183- if err != nil {
184- return nil , err
185- }
186- logrus .Debug (string (dt ))
149+ fmt .Fprintf (dockerCli .Out (), " - %s : %s\n " , service , digest )
187150 }
151+ debugBundle (bundle )
188152
189153 var ref reference.Named
190- ref , err = getNamedTagged (opt .tag )
154+ ref , err = packager . GetNamedTagged (opt .tag )
191155 if err != nil {
192156 return nil , err
193157 }
194158 if ref == nil {
195- b := bytes.Buffer {}
196- _ , err := bundle .WriteTo (& b )
197- if err != nil {
159+ if ref , err = computeDigest (bundle ); err != nil {
198160 return nil , err
199161 }
200- digest := digest .SHA256 .FromBytes (b .Bytes ())
201- ref = sha {digest }
202162 }
203163
204-
205164 if opt .out != "" {
206165 b , err := json .MarshalIndent (bundle , "" , " " )
207166 if err != nil {
@@ -215,45 +174,110 @@ func runBuild(dockerCli command.Cli, application string, opt buildOptions) (refe
215174 return ref , err
216175 }
217176
218- if err := persistInBundleStore (ref , bundle ); err != nil {
177+ if err := packager . PersistInBundleStore (ref , bundle ); err != nil {
219178 return ref , err
220179 }
221180
222181 return ref , nil
223182}
224183
225- type sha struct {
226- d digest.Digest
184+ func computeDigest (bundle * bundle.Bundle ) (reference.Named , error ) {
185+ b := bytes.Buffer {}
186+ _ , err := bundle .WriteTo (& b )
187+ if err != nil {
188+ return nil , err
189+ }
190+ digest := digest .SHA256 .FromBytes (b .Bytes ())
191+ ref := sha {digest }
192+ return ref , nil
227193}
228194
229- func (s sha ) Digest () digest.Digest {
230- return s .d
195+ func createInvocationImageBuildOptions (dockerCli command.Cli , app * types.App ) (build.Options , error ) {
196+ buildContext := bytes .NewBuffer (nil )
197+ if err := packager .PackInvocationImageContext (dockerCli , app , buildContext ); err != nil {
198+ return build.Options {}, err
199+ }
200+ return build.Options {
201+ Inputs : build.Inputs {
202+ InStream : buildContext ,
203+ ContextPath : "-" ,
204+ },
205+ Session : []session.Attachable {authprovider .NewDockerAuthProvider (os .Stderr )},
206+ }, nil
231207}
232208
233- func (s sha ) String () string {
234- return s .d .String ()
209+ func debugTargets (targets map [string ]bake.Target ) {
210+ if logrus .IsLevelEnabled (logrus .DebugLevel ) {
211+ dt , err := json .MarshalIndent (targets , "" , " " )
212+ if err != nil {
213+ logrus .Debugf ("Failed to marshal Buildx response: %s" , err .Error ())
214+ } else {
215+ logrus .Debug (string (dt ))
216+ }
217+ }
235218}
236219
237- func (s sha ) Name () string {
238- return s .d .String ()
220+ func debugBundle (bundle * bundle.Bundle ) {
221+ if logrus .IsLevelEnabled (logrus .DebugLevel ) {
222+ dt , err := json .MarshalIndent (bundle , "" , " " )
223+ if err != nil {
224+ logrus .Debugf ("Failed to marshal Bundle: %s" , err .Error ())
225+ } else {
226+ logrus .Debug (string (dt ))
227+ }
228+ }
239229}
240230
231+ func debugSolveResponses (resp map [string ]* client.SolveResponse ) {
232+ if logrus .IsLevelEnabled (logrus .DebugLevel ) {
233+ dt , err := json .MarshalIndent (resp , "" , " " )
234+ if err != nil {
235+ logrus .Debugf ("Failed to marshal Buildx response: %s" , err .Error ())
236+ } else {
237+ logrus .Debug (string (dt ))
238+ }
239+ }
240+ }
241+
242+ // parseCompose do parse app compose file and extract buildx targets
243+ func parseCompose (app * types.App ) (map [string ]bake.Target , error ) {
244+ compose , err := bake .ParseCompose (app .Composes ()[0 ])
245+ // Fixme can have > 1 composes ?
246+ if err != nil {
247+ return nil , err
248+ }
249+ targets := map [string ]bake.Target {}
250+ for _ , n := range compose .ResolveGroup ("default" ) {
251+ t , err := compose .ResolveTarget (n )
252+ if err != nil {
253+ return nil , err
254+ }
255+ if t != nil {
256+ targets [n ] = * t
257+ }
258+ }
259+ return targets , nil
260+ }
261+
262+
263+ type sha struct {
264+ d digest.Digest
265+ }
241266var _ reference.Named = sha {"" }
242267var _ reference.Digested = sha {"" }
243268
244-
245- /// FIXME copy from vendor/github.com/docker/buildx/commands/util.go:318 could probably be made public
246- func dockerAPI (dockerCli command.Cli ) * api {
247- return & api {dockerCli : dockerCli }
269+ // Digest implement Digested.Digest()
270+ func (s sha ) Digest () digest.Digest {
271+ return s .d
248272}
249273
250- type api struct {
251- dockerCli command.Cli
274+ // Digest implement Named.String()
275+ func (s sha ) String () string {
276+ return s .d .String ()
252277}
253278
254- func (a * api ) DockerAPI (name string ) (dockerclient.APIClient , error ) {
255- if name == "" {
256- name = a .dockerCli .CurrentContext ()
257- }
258- return nil , fmt .Errorf ("Only support default context in this prototype" )
279+ // Digest implement Named.Name()
280+ func (s sha ) Name () string {
281+ return s .d .String ()
259282}
283+
0 commit comments