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 }