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 }