github.com/mgoltzsche/ctnr@v0.7.1-alpha/pkg/fs/writer/hashingwriter.go (about)

     1  package writer
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/mgoltzsche/ctnr/pkg/fs"
     7  	"github.com/opencontainers/go-digest"
     8  	//	"github.com/pkg/errors"
     9  )
    10  
    11  type HashingWriter struct {
    12  	fs.Writer
    13  }
    14  
    15  func NewHashingWriter(delegate fs.Writer) fs.Writer {
    16  	return &HashingWriter{delegate}
    17  }
    18  
    19  func (w *HashingWriter) Lazy(path, name string, src fs.LazySource, written map[fs.Source]string) (err error) {
    20  	return src.Expand(path, w, written)
    21  }
    22  
    23  func (w *HashingWriter) File(path string, src fs.FileSource) (fs.Source, error) {
    24  	return w.Writer.File(path, &hashingSource{src, ""})
    25  }
    26  
    27  type hashingSource struct {
    28  	fs.FileSource
    29  	hash string
    30  }
    31  
    32  func (s *hashingSource) HashIfAvailable() string {
    33  	return s.hash
    34  }
    35  
    36  func (s *hashingSource) DeriveAttrs() (a fs.DerivedAttrs, err error) {
    37  	if a, err = s.FileSource.DeriveAttrs(); err == nil {
    38  		a.Hash = s.hash
    39  	}
    40  	return
    41  }
    42  
    43  func (s *hashingSource) Reader() (r io.ReadCloser, err error) {
    44  	if r, err = s.FileSource.Reader(); err != nil || s.hash != "" {
    45  		return
    46  	}
    47  	digester := digest.SHA256.Digester()
    48  	tr := io.TeeReader(r, digester.Hash())
    49  	return &hashAssigningReadCloser{tr, r, digester, &s.hash}, nil
    50  }
    51  
    52  type hashAssigningReadCloser struct {
    53  	io.Reader
    54  	closer   io.Closer
    55  	digester digest.Digester
    56  	hash     *string
    57  }
    58  
    59  func (r *hashAssigningReadCloser) Close() (err error) {
    60  	if err = r.closer.Close(); err == nil {
    61  		*r.hash = r.digester.Digest().String()
    62  	}
    63  	return
    64  }