@@ -12,10 +12,12 @@ import (
1212 "github.com/google/go-dap"
1313 "github.com/moby/buildkit/client/llb"
1414 gateway "github.com/moby/buildkit/frontend/gateway/client"
15+ gwpb "github.com/moby/buildkit/frontend/gateway/pb"
1516 "github.com/moby/buildkit/solver/errdefs"
1617 "github.com/moby/buildkit/solver/pb"
1718 "github.com/opencontainers/go-digest"
1819 "github.com/pkg/errors"
20+ "github.com/tonistiigi/fsutil/types"
1921 "golang.org/x/sync/errgroup"
2022)
2123
@@ -323,16 +325,12 @@ func (t *thread) pause(c Context, k string, refs map[string]gateway.Reference, e
323325 }
324326 t .paused = make (chan stepType , 1 )
325327
328+ t .prepareResultHandle (c , k , refs , err )
329+
326330 ctx , cancel := context .WithCancelCause (c )
327331 t .collectStackTrace (ctx , pos , refs )
328332 t .cancel = cancel
329333
330- // Used for exec. Only works if there was an error or if the step returns
331- // a root mount.
332- if ref , ok := refs [k ]; ok || err != nil {
333- t .prepareResultHandle (c , ref , err )
334- }
335-
336334 event .ThreadId = t .id
337335 c .C () <- & dap.StoppedEvent {
338336 Event : dap.Event {Event : "stopped" },
@@ -341,7 +339,15 @@ func (t *thread) pause(c Context, k string, refs map[string]gateway.Reference, e
341339 return t .paused
342340}
343341
344- func (t * thread ) prepareResultHandle (c Context , ref gateway.Reference , err error ) {
342+ func (t * thread ) prepareResultHandle (c Context , k string , refs map [string ]gateway.Reference , err error ) {
343+ var ref gateway.Reference
344+ if err == nil {
345+ var ok bool
346+ if ref , ok = refs [k ]; ! ok {
347+ return
348+ }
349+ }
350+
345351 // Create a context for cancellations and make the cancel function
346352 // block on the wait group.
347353 var wg sync.WaitGroup
@@ -353,6 +359,28 @@ func (t *thread) prepareResultHandle(c Context, ref gateway.Reference, err error
353359
354360 t .rCtx = build .NewResultHandle (ctx , t .c , ref , t .meta , err )
355361
362+ if err != nil {
363+ gwcaps := t .c .BuildOpts ().Caps
364+
365+ var solveErr * errdefs.SolveError
366+ if gwcaps .Supports (gwpb .CapGatewayExecFilesystem ) != nil && errors .As (err , & solveErr ) {
367+ if exec , ok := solveErr .Op .Op .(* pb.Op_Exec ); ok {
368+ rCtx := t .rCtx
369+
370+ getContainer := sync .OnceValues (func () (gateway.Container , error ) {
371+ return rCtx .NewContainer (ctx , & build.InvokeConfig {})
372+ })
373+
374+ for i , m := range exec .Exec .Mounts {
375+ refs [m .Dest ] = & mountReference {
376+ getContainer : getContainer ,
377+ index : i ,
378+ }
379+ }
380+ }
381+ }
382+ }
383+
356384 // Start the attach. Use the context we created and perform it in
357385 // a goroutine. We aren't necessarily assuming this will actually work.
358386 wg .Go (func () {
@@ -678,3 +706,52 @@ func (t *thread) rewind(ctx Context, inErr error) (k string, result *step, mount
678706 }
679707 return k , result , mounts , inErr
680708}
709+
710+ type mountReference struct {
711+ getContainer func () (gateway.Container , error )
712+ index int
713+ }
714+
715+ func (r * mountReference ) ToState () (llb.State , error ) {
716+ return llb.State {}, errors .New ("unimplemented" )
717+ }
718+
719+ func (r * mountReference ) Evaluate (ctx context.Context ) error {
720+ return nil
721+ }
722+
723+ func (r * mountReference ) ReadFile (ctx context.Context , req gateway.ReadRequest ) ([]byte , error ) {
724+ ctr , err := r .getContainer ()
725+ if err != nil {
726+ return nil , err
727+ }
728+
729+ return ctr .ReadFile (ctx , gateway.ReadContainerRequest {
730+ ReadRequest : req ,
731+ Index : r .index ,
732+ })
733+ }
734+
735+ func (r * mountReference ) StatFile (ctx context.Context , req gateway.StatRequest ) (* types.Stat , error ) {
736+ ctr , err := r .getContainer ()
737+ if err != nil {
738+ return nil , err
739+ }
740+
741+ return ctr .StatFile (ctx , gateway.StatContainerRequest {
742+ StatRequest : req ,
743+ Index : r .index ,
744+ })
745+ }
746+
747+ func (r * mountReference ) ReadDir (ctx context.Context , req gateway.ReadDirRequest ) ([]* types.Stat , error ) {
748+ ctr , err := r .getContainer ()
749+ if err != nil {
750+ return nil , err
751+ }
752+
753+ return ctr .ReadDir (ctx , gateway.ReadDirContainerRequest {
754+ ReadDirRequest : req ,
755+ Index : r .index ,
756+ })
757+ }
0 commit comments