diff --git a/diff/apply/apply.go b/diff/apply/apply.go index 50ee057f9..7a6b65c3e 100644 --- a/diff/apply/apply.go +++ b/diff/apply/apply.go @@ -76,11 +76,14 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [ } defer ra.Close() + var processors []diff.StreamProcessor processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra)) + processors = append(processors, processor) for { if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil { return emptyDesc, errors.Wrapf(err, "failed to get stream processor for %s", desc.MediaType) } + processors = append(processors, processor) if processor.MediaType() == ocispec.MediaTypeImageLayer { break } @@ -102,6 +105,16 @@ func (s *fsApplier) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [ }); err != nil { return emptyDesc, err } + + for _, p := range processors { + if ep, ok := p.(interface { + Err() error + }); ok { + if err := ep.Err(); err != nil { + return emptyDesc, err + } + } + } return ocispec.Descriptor{ MediaType: ocispec.MediaTypeImageLayer, Size: rc.c, diff --git a/diff/stream_unix.go b/diff/stream_unix.go index 75d1001f6..28f38d998 100644 --- a/diff/stream_unix.go +++ b/diff/stream_unix.go @@ -25,14 +25,17 @@ import ( "io" "os" "os/exec" + "sync" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/types" + "github.com/pkg/errors" ) // NewBinaryProcessor returns a binary processor for use with processing content streams func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) { cmd := exec.CommandContext(ctx, name, args...) + cmd.Env = os.Environ() var payloadC io.Closer if payload != nil { @@ -71,10 +74,19 @@ func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProce } cmd.Stdout = w + stderr := bytes.NewBuffer(nil) + cmd.Stderr = stderr + if err := cmd.Start(); err != nil { return nil, err } - go cmd.Wait() + p := &binaryProcessor{ + cmd: cmd, + r: r, + mt: rmt, + stderr: stderr, + } + go p.wait() // close after start and dup w.Close() @@ -84,17 +96,33 @@ func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProce if payloadC != nil { payloadC.Close() } - return &binaryProcessor{ - cmd: cmd, - r: r, - mt: rmt, - }, nil + return p, nil } type binaryProcessor struct { - cmd *exec.Cmd - r *os.File - mt string + cmd *exec.Cmd + r *os.File + mt string + stderr *bytes.Buffer + + mu sync.Mutex + err error +} + +func (c *binaryProcessor) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *binaryProcessor) wait() { + if err := c.cmd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); ok { + c.mu.Lock() + c.err = errors.New(c.stderr.String()) + c.mu.Unlock() + } + } } func (c *binaryProcessor) File() *os.File { diff --git a/diff/stream_windows.go b/diff/stream_windows.go index ba139b849..8dadd72c9 100644 --- a/diff/stream_windows.go +++ b/diff/stream_windows.go @@ -27,10 +27,12 @@ import ( "os" "os/exec" "path/filepath" + "sync" winio "github.com/Microsoft/go-winio" "github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/types" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -39,6 +41,7 @@ const processorPipe = "STREAM_PROCESSOR_PIPE" // NewBinaryProcessor returns a binary processor for use with processing content streams func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProcessor, name string, args []string, payload *types.Any) (StreamProcessor, error) { cmd := exec.CommandContext(ctx, name, args...) + cmd.Env = os.Environ() if payload != nil { data, err := proto.Marshal(payload) @@ -84,28 +87,52 @@ func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProce return nil, err } cmd.Stdout = w + stderr := bytes.NewBuffer(nil) + cmd.Stderr = stderr if err := cmd.Start(); err != nil { return nil, err } - go cmd.Wait() + p := &binaryProcessor{ + cmd: cmd, + r: r, + mt: rmt, + stderr: stderr, + } + go p.wait() // close after start and dup w.Close() if closer != nil { closer() } - return &binaryProcessor{ - cmd: cmd, - r: r, - mt: rmt, - }, nil + return p, nil } type binaryProcessor struct { - cmd *exec.Cmd - r *os.File - mt string + cmd *exec.Cmd + r *os.File + mt string + stderr *bytes.Buffer + + mu sync.Mutex + err error +} + +func (c *binaryProcessor) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *binaryProcessor) wait() { + if err := c.cmd.Wait(); err != nil { + if _, ok := err.(*exec.ExitError); ok { + c.mu.Lock() + c.err = errors.New(c.stderr.String()) + c.mu.Unlock() + } + } } func (c *binaryProcessor) File() *os.File {