@@ -12,6 +12,7 @@ import (
1212
1313 "github.com/containerd/console"
1414 "github.com/docker/buildx/controller/control"
15+ controllererrors "github.com/docker/buildx/controller/errdefs"
1516 controllerapi "github.com/docker/buildx/controller/pb"
1617 "github.com/docker/buildx/util/ioset"
1718 "github.com/moby/buildkit/identity"
@@ -35,7 +36,7 @@ Available commands are:
3536`
3637
3738// RunMonitor provides an interactive session for running and managing containers via specified IO.
38- func RunMonitor (ctx context.Context , curRef string , options controllerapi.BuildOptions , invokeConfig controllerapi.InvokeConfig , c control.BuildxController , progressMode string , stdin io.ReadCloser , stdout io.WriteCloser , stderr console.File ) error {
39+ func RunMonitor (ctx context.Context , curRef string , options * controllerapi.BuildOptions , invokeConfig controllerapi.InvokeConfig , c control.BuildxController , progressMode string , stdin io.ReadCloser , stdout io.WriteCloser , stderr console.File ) error {
3940 defer func () {
4041 if err := c .Disconnect (ctx , curRef ); err != nil {
4142 logrus .Warnf ("disconnect error: %v" , err )
@@ -84,6 +85,8 @@ func RunMonitor(ctx context.Context, curRef string, options controllerapi.BuildO
8485
8586 // Start container automatically
8687 fmt .Fprintf (stdout , "Launching interactive container. Press Ctrl-a-c to switch to monitor console\n " )
88+ invokeConfig .Rollback = false
89+ invokeConfig .Initial = false
8790 id := m .rollback (ctx , curRef , invokeConfig )
8891 fmt .Fprintf (stdout , "Interactive container was restarted with process %q. Press Ctrl-a-c to switch to the new container\n " , id )
8992
@@ -120,25 +123,58 @@ func RunMonitor(ctx context.Context, curRef string, options controllerapi.BuildO
120123 case "" :
121124 // nop
122125 case "reload" :
126+ var bo * controllerapi.BuildOptions
127+ if curRef != "" {
128+ // Rebuilding an existing session; Restore the build option used for building this session.
129+ res , err := c .Inspect (ctx , curRef )
130+ if err != nil {
131+ fmt .Printf ("failed to inspect the current build session: %v\n " , err )
132+ } else {
133+ bo = res .Options
134+ }
135+ } else {
136+ bo = options
137+ }
138+ if bo == nil {
139+ fmt .Println ("reload: no build option is provided" )
140+ continue
141+ }
123142 if curRef != "" {
124143 if err := c .Disconnect (ctx , curRef ); err != nil {
125144 fmt .Println ("disconnect error" , err )
126145 }
127146 }
128- ref , _ , err := c .Build (ctx , options , nil , stdout , stderr , progressMode ) // TODO: support stdin, hold build ref
147+ var resultUpdated bool
148+ ref , _ , err := c .Build (ctx , * bo , nil , stdout , stderr , progressMode ) // TODO: support stdin, hold build ref
129149 if err != nil {
130- fmt .Printf ("failed to reload: %v\n " , err )
150+ var be * controllererrors.BuildError
151+ if errors .As (err , & be ) {
152+ curRef = be .Ref
153+ resultUpdated = true
154+ } else {
155+ fmt .Printf ("failed to reload: %v\n " , err )
156+ }
131157 } else {
132158 curRef = ref
159+ resultUpdated = true
160+ }
161+ if resultUpdated {
133162 // rollback the running container with the new result
134163 id := m .rollback (ctx , curRef , invokeConfig )
135164 fmt .Fprintf (stdout , "Interactive container was restarted with process %q. Press Ctrl-a-c to switch to the new container\n " , id )
136165 }
137166 case "rollback" :
138167 cfg := invokeConfig
139168 if len (args ) >= 2 {
140- cfg .Entrypoint = []string {args [1 ]}
141- cfg .Cmd = args [2 :]
169+ cmds := args [1 :]
170+ if cmds [0 ] == "--init" {
171+ cfg .Initial = true
172+ cmds = cmds [1 :]
173+ }
174+ if len (cmds ) > 0 {
175+ cfg .Entrypoint = []string {cmds [0 ]}
176+ cfg .Cmd = cmds [1 :]
177+ }
142178 }
143179 id := m .rollback (ctx , curRef , cfg )
144180 fmt .Fprintf (stdout , "Interactive container was restarted with process %q. Press Ctrl-a-c to switch to the new container\n " , id )
@@ -254,10 +290,10 @@ func RunMonitor(ctx context.Context, curRef string, options controllerapi.BuildO
254290 }()
255291 select {
256292 case <- doneCh :
257- m .invokeCancel ()
293+ m .close ()
258294 return nil
259295 case err := <- errCh :
260- m .invokeCancel ()
296+ m .close ()
261297 return err
262298 case <- monitorDisableCh :
263299 }
@@ -293,10 +329,19 @@ func (m *monitor) attach(ctx context.Context, ref, pid string) {
293329 m .startInvoke (ctx , ref , pid , controllerapi.InvokeConfig {})
294330}
295331
332+ func (m * monitor ) close () {
333+ if m .invokeCancel != nil {
334+ m .invokeCancel ()
335+ }
336+ }
337+
296338func (m * monitor ) startInvoke (ctx context.Context , ref , pid string , cfg controllerapi.InvokeConfig ) string {
297339 if m .invokeCancel != nil {
298340 m .invokeCancel () // Finish existing attach
299341 }
342+ if len (cfg .Entrypoint ) == 0 && len (cfg .Cmd ) == 0 {
343+ cfg .Entrypoint = []string {"sh" } // launch shell by default
344+ }
300345 go func () {
301346 // Start a new invoke
302347 if err := m .invoke (ctx , ref , pid , cfg ); err != nil {
@@ -316,6 +361,9 @@ func (m *monitor) invoke(ctx context.Context, ref, pid string, cfg controllerapi
316361 if err := m .muxIO .SwitchTo (1 ); err != nil {
317362 return errors .Errorf ("failed to switch to process IO: %v" , err )
318363 }
364+ if ref == "" {
365+ return nil
366+ }
319367 invokeCtx , invokeCancel := context .WithCancel (ctx )
320368
321369 containerIn , containerOut := ioset .Pipe ()
0 commit comments