github.com/damirazo/docker@v1.9.0/pkg/ioutils/readers.go (about)

     1  package ioutils
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/hex"
     6  	"io"
     7  	"sync"
     8  )
     9  
    10  type readCloserWrapper struct {
    11  	io.Reader
    12  	closer func() error
    13  }
    14  
    15  func (r *readCloserWrapper) Close() error {
    16  	return r.closer()
    17  }
    18  
    19  // NewReadCloserWrapper returns a new io.ReadCloser.
    20  func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser {
    21  	return &readCloserWrapper{
    22  		Reader: r,
    23  		closer: closer,
    24  	}
    25  }
    26  
    27  type readerErrWrapper struct {
    28  	reader io.Reader
    29  	closer func()
    30  }
    31  
    32  func (r *readerErrWrapper) Read(p []byte) (int, error) {
    33  	n, err := r.reader.Read(p)
    34  	if err != nil {
    35  		r.closer()
    36  	}
    37  	return n, err
    38  }
    39  
    40  // NewReaderErrWrapper returns a new io.Reader.
    41  func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader {
    42  	return &readerErrWrapper{
    43  		reader: r,
    44  		closer: closer,
    45  	}
    46  }
    47  
    48  // bufReader allows the underlying reader to continue to produce
    49  // output by pre-emptively reading from the wrapped reader.
    50  // This is achieved by buffering this data in bufReader's
    51  // expanding buffer.
    52  type bufReader struct {
    53  	sync.Mutex
    54  	buf      io.ReadWriter
    55  	reader   io.Reader
    56  	err      error
    57  	wait     sync.Cond
    58  	drainBuf []byte
    59  }
    60  
    61  // NewBufReader returns a new bufReader.
    62  func NewBufReader(r io.Reader) io.ReadCloser {
    63  	reader := &bufReader{
    64  		buf:      NewBytesPipe(nil),
    65  		reader:   r,
    66  		drainBuf: make([]byte, 1024),
    67  	}
    68  	reader.wait.L = &reader.Mutex
    69  	go reader.drain()
    70  	return reader
    71  }
    72  
    73  // NewBufReaderWithDrainbufAndBuffer returns a BufReader with drainBuffer and buffer.
    74  func NewBufReaderWithDrainbufAndBuffer(r io.Reader, drainBuffer []byte, buffer io.ReadWriter) io.ReadCloser {
    75  	reader := &bufReader{
    76  		buf:      buffer,
    77  		drainBuf: drainBuffer,
    78  		reader:   r,
    79  	}
    80  	reader.wait.L = &reader.Mutex
    81  	go reader.drain()
    82  	return reader
    83  }
    84  
    85  func (r *bufReader) drain() {
    86  	for {
    87  		//Call to scheduler is made to yield from this goroutine.
    88  		//This avoids goroutine looping here when n=0,err=nil, fixes code hangs when run with GCC Go.
    89  		callSchedulerIfNecessary()
    90  		n, err := r.reader.Read(r.drainBuf)
    91  		r.Lock()
    92  		if err != nil {
    93  			r.err = err
    94  		} else {
    95  			if n == 0 {
    96  				// nothing written, no need to signal
    97  				r.Unlock()
    98  				continue
    99  			}
   100  			r.buf.Write(r.drainBuf[:n])
   101  		}
   102  		r.wait.Signal()
   103  		r.Unlock()
   104  		if err != nil {
   105  			break
   106  		}
   107  	}
   108  }
   109  
   110  func (r *bufReader) Read(p []byte) (n int, err error) {
   111  	r.Lock()
   112  	defer r.Unlock()
   113  	for {
   114  		n, err = r.buf.Read(p)
   115  		if n > 0 {
   116  			return n, err
   117  		}
   118  		if r.err != nil {
   119  			return 0, r.err
   120  		}
   121  		r.wait.Wait()
   122  	}
   123  }
   124  
   125  // Close closes the bufReader
   126  func (r *bufReader) Close() error {
   127  	closer, ok := r.reader.(io.ReadCloser)
   128  	if !ok {
   129  		return nil
   130  	}
   131  	return closer.Close()
   132  }
   133  
   134  // HashData returns the sha256 sum of src.
   135  func HashData(src io.Reader) (string, error) {
   136  	h := sha256.New()
   137  	if _, err := io.Copy(h, src); err != nil {
   138  		return "", err
   139  	}
   140  	return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
   141  }
   142  
   143  // OnEOFReader wraps a io.ReadCloser and a function
   144  // the function will run at the end of file or close the file.
   145  type OnEOFReader struct {
   146  	Rc io.ReadCloser
   147  	Fn func()
   148  }
   149  
   150  func (r *OnEOFReader) Read(p []byte) (n int, err error) {
   151  	n, err = r.Rc.Read(p)
   152  	if err == io.EOF {
   153  		r.runFunc()
   154  	}
   155  	return
   156  }
   157  
   158  // Close closes the file and run the function.
   159  func (r *OnEOFReader) Close() error {
   160  	err := r.Rc.Close()
   161  	r.runFunc()
   162  	return err
   163  }
   164  
   165  func (r *OnEOFReader) runFunc() {
   166  	if fn := r.Fn; fn != nil {
   167  		fn()
   168  		r.Fn = nil
   169  	}
   170  }