github.com/ohlinux/git-lfs@v1.5.4/tools/iotools.go (about) 1 package tools 2 3 import ( 4 "crypto/sha256" 5 "encoding/hex" 6 "hash" 7 "io" 8 9 "github.com/git-lfs/git-lfs/errors" 10 "github.com/git-lfs/git-lfs/progress" 11 ) 12 13 type readSeekCloserWrapper struct { 14 readSeeker io.ReadSeeker 15 } 16 17 func (r *readSeekCloserWrapper) Read(p []byte) (n int, err error) { 18 return r.readSeeker.Read(p) 19 } 20 21 func (r *readSeekCloserWrapper) Seek(offset int64, whence int) (int64, error) { 22 return r.readSeeker.Seek(offset, whence) 23 } 24 25 func (r *readSeekCloserWrapper) Close() error { 26 return nil 27 } 28 29 // NewReadSeekCloserWrapper wraps an io.ReadSeeker and implements a no-op Close() function 30 // to make it an io.ReadCloser 31 func NewReadSeekCloserWrapper(r io.ReadSeeker) io.ReadCloser { 32 return &readSeekCloserWrapper{r} 33 } 34 35 // CopyWithCallback copies reader to writer while performing a progress callback 36 func CopyWithCallback(writer io.Writer, reader io.Reader, totalSize int64, cb progress.CopyCallback) (int64, error) { 37 if success, _ := CloneFile(writer, reader); success { 38 if cb != nil { 39 cb(totalSize, totalSize, 0) 40 } 41 return totalSize, nil 42 } 43 if cb == nil { 44 return io.Copy(writer, reader) 45 } 46 47 cbReader := &progress.CallbackReader{ 48 C: cb, 49 TotalSize: totalSize, 50 Reader: reader, 51 } 52 return io.Copy(writer, cbReader) 53 } 54 55 // Get a new Hash instance of the type used to hash LFS content 56 func NewLfsContentHash() hash.Hash { 57 return sha256.New() 58 } 59 60 // HashingReader wraps a reader and calculates the hash of the data as it is read 61 type HashingReader struct { 62 reader io.Reader 63 hasher hash.Hash 64 } 65 66 func NewHashingReader(r io.Reader) *HashingReader { 67 return &HashingReader{r, NewLfsContentHash()} 68 } 69 70 func NewHashingReaderPreloadHash(r io.Reader, hash hash.Hash) *HashingReader { 71 return &HashingReader{r, hash} 72 } 73 74 func (r *HashingReader) Hash() string { 75 return hex.EncodeToString(r.hasher.Sum(nil)) 76 } 77 78 func (r *HashingReader) Read(b []byte) (int, error) { 79 w, err := r.reader.Read(b) 80 if err == nil || err == io.EOF { 81 _, e := r.hasher.Write(b[0:w]) 82 if e != nil && err == nil { 83 return w, e 84 } 85 } 86 87 return w, err 88 } 89 90 // RetriableReader wraps a error response of reader as RetriableError() 91 type RetriableReader struct { 92 reader io.Reader 93 } 94 95 func NewRetriableReader(r io.Reader) io.Reader { 96 return &RetriableReader{r} 97 } 98 99 func (r *RetriableReader) Read(b []byte) (int, error) { 100 n, err := r.reader.Read(b) 101 102 // EOF is a successful response as it is used to signal a graceful end 103 // of input c.f. https://git.io/v6riQ 104 // 105 // Otherwise, if the error is non-nil and already retriable (in the 106 // case that the underlying reader `r.reader` is itself a 107 // `*RetriableReader`, return the error wholesale: 108 if err == nil || err == io.EOF || errors.IsRetriableError(err) { 109 return n, err 110 } 111 112 return n, errors.NewRetriableError(err) 113 }