@@ -32,12 +32,13 @@ import (
3232)
3333
3434type buildOptions struct {
35- noCache bool
36- progress string
37- pull bool
38- tag string
39- folder string
40- args []string
35+ noCache bool
36+ progress string
37+ pull bool
38+ tag string
39+ folder string
40+ imageIDFile string
41+ args []string
4142}
4243
4344func Cmd (dockerCli command.Cli ) * cobra.Command {
@@ -48,11 +49,7 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
4849 Example : `$ docker app build --tag my/app:1.0.0 .` ,
4950 Args : cli .ExactArgs (1 ),
5051 RunE : func (cmd * cobra.Command , args []string ) error {
51- ref , err := runBuild (dockerCli , args [0 ], opts )
52- if err == nil {
53- fmt .Printf ("Successfully build %s\n " , ref .String ())
54- }
55- return err
52+ return runBuild (dockerCli , args [0 ], opts )
5653 },
5754 }
5855
@@ -63,49 +60,78 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
6360 flags .StringVarP (& opts .folder , "folder" , "f" , "" , "Docker app folder containing application definition" )
6461 flags .BoolVar (& opts .pull , "pull" , false , "Always attempt to pull a newer version of the image" )
6562 flags .StringArrayVar (& opts .args , "build-arg" , []string {}, "Set build-time variables" )
63+ flags .StringVar (& opts .imageIDFile , "iidfile" , "" , "Write the app image ID to the file" )
6664
6765 return cmd
6866}
6967
70- func runBuild (dockerCli command.Cli , contextPath string , opt buildOptions ) (reference. Reference , error ) {
68+ func runBuild (dockerCli command.Cli , contextPath string , opt buildOptions ) error {
7169 err := checkMinimalEngineVersion (dockerCli )
7270 if err != nil {
73- return nil , err
71+ return err
7472 }
7573
76- if err = checkBuildArgsUniqueness (opt .args ); err != nil {
77- return nil , err
74+ if opt .imageIDFile != "" {
75+ // Avoid leaving a stale file if we eventually fail
76+ if err := os .Remove (opt .imageIDFile ); err != nil && ! os .IsNotExist (err ) {
77+ return err
78+ }
7879 }
7980
80- var ref reference.Reference
81- ref , err = packager .GetNamedTagged (opt .tag )
82- if err != nil {
83- return nil , err
81+ if err = checkBuildArgsUniqueness (opt .args ); err != nil {
82+ return err
8483 }
8584
8685 application , err := getAppFolder (opt , contextPath )
8786 if err != nil {
88- return nil , err
87+ return err
8988 }
9089
9190 app , err := packager .Extract (application )
9291 if err != nil {
93- return nil , err
92+ return err
9493 }
9594 defer app .Cleanup ()
9695
96+ bundle , err := buildImageUsingBuildx (app , contextPath , opt , dockerCli )
97+ if err != nil {
98+ return err
99+ }
100+
101+ var ref reference.Reference
102+ ref , err = packager .GetNamedTagged (opt .tag )
103+ if err != nil {
104+ return err
105+ }
106+
107+ id , err := packager .PersistInBundleStore (ref , bundle )
108+ if err != nil {
109+ return err
110+ }
111+
112+ if opt .imageIDFile != "" {
113+ if err = ioutil .WriteFile (opt .imageIDFile , []byte (id .String ()), 0644 ); err != nil {
114+ fmt .Fprintf (dockerCli .Err (), "Failed to write application image id in %s: %s" , opt .imageIDFile , err )
115+ }
116+ }
117+
118+ fmt .Printf ("Successfully built %s\n " , id )
119+ if ref != nil {
120+ fmt .Printf ("Successfully tagged %s\n " , ref .String ())
121+ }
122+ return err
123+ }
124+
125+ func buildImageUsingBuildx (app * types.App , contextPath string , opt buildOptions , dockerCli command.Cli ) (* bundle.Bundle , error ) {
97126 buildopts , err := parseCompose (app , contextPath , opt )
98127 if err != nil {
99128 return nil , err
100129 }
101-
102130 buildopts ["com.docker.app.invocation-image" ], err = createInvocationImageBuildOptions (dockerCli , app )
103131 if err != nil {
104132 return nil , err
105133 }
106-
107134 debugBuildOpts (buildopts )
108-
109135 ctx , cancel := context .WithCancel (appcontext .Context ())
110136 defer cancel ()
111137 const drivername = "buildx_buildkit_default"
@@ -119,9 +145,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
119145 Driver : d ,
120146 },
121147 }
122-
123148 pw := progress .NewPrinter (ctx , os .Stderr , opt .progress )
124-
125149 // We rely on buildx "docker" builder integrated in docker engine, so don't need a DockerAPI here
126150 resp , err := build .Build (ctx , driverInfo , buildopts , nil , dockerCli .ConfigFile (), pw )
127151 if err != nil {
@@ -137,8 +161,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
137161 if err != nil {
138162 return nil , err
139163 }
140-
141- return packager .PersistInBundleStore (ref , bundle )
164+ return bundle , nil
142165}
143166
144167func getAppFolder (opt buildOptions , contextPath string ) (string , error ) {
0 commit comments