github.com/YousefHaggyHeroku/pack@v1.5.5/internal/blob/blob.go (about)

     1  package blob
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"io"
     7  	"os"
     8  
     9  	"github.com/docker/docker/pkg/ioutils"
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/YousefHaggyHeroku/pack/internal/archive"
    13  )
    14  
    15  type Blob interface {
    16  	Open() (io.ReadCloser, error)
    17  }
    18  
    19  type blob struct {
    20  	path string
    21  }
    22  
    23  func NewBlob(path string) Blob {
    24  	return &blob{path: path}
    25  }
    26  
    27  // Open returns an io.ReadCloser whose contents are in tar archive format
    28  func (b blob) Open() (r io.ReadCloser, err error) {
    29  	fi, err := os.Stat(b.path)
    30  	if err != nil {
    31  		return nil, errors.Wrapf(err, "read blob at path '%s'", b.path)
    32  	}
    33  	if fi.IsDir() {
    34  		return archive.ReadDirAsTar(b.path, ".", 0, 0, -1, true, nil), nil
    35  	}
    36  
    37  	fh, err := os.Open(b.path)
    38  	if err != nil {
    39  		return nil, errors.Wrap(err, "open buildpack archive")
    40  	}
    41  	defer func() {
    42  		if err != nil {
    43  			fh.Close()
    44  		}
    45  	}()
    46  
    47  	if ok, err := isGZip(fh); err != nil {
    48  		return nil, errors.Wrap(err, "check header")
    49  	} else if !ok {
    50  		return fh, nil
    51  	}
    52  	gzr, err := gzip.NewReader(fh)
    53  	if err != nil {
    54  		return nil, errors.Wrap(err, "create gzip reader")
    55  	}
    56  
    57  	rc := ioutils.NewReadCloserWrapper(gzr, func() error {
    58  		defer fh.Close()
    59  		return gzr.Close()
    60  	})
    61  
    62  	return rc, nil
    63  }
    64  
    65  func isGZip(file io.ReadSeeker) (bool, error) {
    66  	b := make([]byte, 3)
    67  	if _, err := file.Seek(0, 0); err != nil {
    68  		return false, err
    69  	}
    70  	_, err := file.Read(b)
    71  	if err != nil && err != io.EOF {
    72  		return false, err
    73  	} else if err == io.EOF {
    74  		return false, nil
    75  	}
    76  	if _, err := file.Seek(0, 0); err != nil {
    77  		return false, err
    78  	}
    79  	return bytes.Equal(b, []byte("\x1f\x8b\x08")), nil
    80  }