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  }