summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go')
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go170
1 files changed, 170 insertions, 0 deletions
diff --git a/vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go b/vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go
new file mode 100644
index 0000000000..e9dcbfe49b
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-git.v4/utils/ioutil/common.go
@@ -0,0 +1,170 @@
+// Package ioutil implements some I/O utility functions.
+package ioutil
+
+import (
+ "bufio"
+ "context"
+ "errors"
+ "io"
+
+ "github.com/jbenet/go-context/io"
+)
+
+type readPeeker interface {
+ io.Reader
+ Peek(int) ([]byte, error)
+}
+
+var (
+ ErrEmptyReader = errors.New("reader is empty")
+)
+
+// NonEmptyReader takes a reader and returns it if it is not empty, or
+// `ErrEmptyReader` if it is empty. If there is an error when reading the first
+// byte of the given reader, it will be propagated.
+func NonEmptyReader(r io.Reader) (io.Reader, error) {
+ pr, ok := r.(readPeeker)
+ if !ok {
+ pr = bufio.NewReader(r)
+ }
+
+ _, err := pr.Peek(1)
+ if err == io.EOF {
+ return nil, ErrEmptyReader
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ return pr, nil
+}
+
+type readCloser struct {
+ io.Reader
+ closer io.Closer
+}
+
+func (r *readCloser) Close() error {
+ return r.closer.Close()
+}
+
+// NewReadCloser creates an `io.ReadCloser` with the given `io.Reader` and
+// `io.Closer`.
+func NewReadCloser(r io.Reader, c io.Closer) io.ReadCloser {
+ return &readCloser{Reader: r, closer: c}
+}
+
+type writeCloser struct {
+ io.Writer
+ closer io.Closer
+}
+
+func (r *writeCloser) Close() error {
+ return r.closer.Close()
+}
+
+// NewWriteCloser creates an `io.WriteCloser` with the given `io.Writer` and
+// `io.Closer`.
+func NewWriteCloser(w io.Writer, c io.Closer) io.WriteCloser {
+ return &writeCloser{Writer: w, closer: c}
+}
+
+type writeNopCloser struct {
+ io.Writer
+}
+
+func (writeNopCloser) Close() error { return nil }
+
+// WriteNopCloser returns a WriteCloser with a no-op Close method wrapping
+// the provided Writer w.
+func WriteNopCloser(w io.Writer) io.WriteCloser {
+ return writeNopCloser{w}
+}
+
+// CheckClose calls Close on the given io.Closer. If the given *error points to
+// nil, it will be assigned the error returned by Close. Otherwise, any error
+// returned by Close will be ignored. CheckClose is usually called with defer.
+func CheckClose(c io.Closer, err *error) {
+ if cerr := c.Close(); cerr != nil && *err == nil {
+ *err = cerr
+ }
+}
+
+// NewContextWriter wraps a writer to make it respect given Context.
+// If there is a blocking write, the returned Writer will return whenever the
+// context is cancelled (the return values are n=0 and err=ctx.Err()).
+func NewContextWriter(ctx context.Context, w io.Writer) io.Writer {
+ return ctxio.NewWriter(ctx, w)
+}
+
+// NewContextReader wraps a reader to make it respect given Context.
+// If there is a blocking read, the returned Reader will return whenever the
+// context is cancelled (the return values are n=0 and err=ctx.Err()).
+func NewContextReader(ctx context.Context, r io.Reader) io.Reader {
+ return ctxio.NewReader(ctx, r)
+}
+
+// NewContextWriteCloser as NewContextWriter but with io.Closer interface.
+func NewContextWriteCloser(ctx context.Context, w io.WriteCloser) io.WriteCloser {
+ ctxw := ctxio.NewWriter(ctx, w)
+ return NewWriteCloser(ctxw, w)
+}
+
+// NewContextReadCloser as NewContextReader but with io.Closer interface.
+func NewContextReadCloser(ctx context.Context, r io.ReadCloser) io.ReadCloser {
+ ctxr := ctxio.NewReader(ctx, r)
+ return NewReadCloser(ctxr, r)
+}
+
+type readerOnError struct {
+ io.Reader
+ notify func(error)
+}
+
+// NewReaderOnError returns a io.Reader that call the notify function when an
+// unexpected (!io.EOF) error happens, after call Read function.
+func NewReaderOnError(r io.Reader, notify func(error)) io.Reader {
+ return &readerOnError{r, notify}
+}
+
+// NewReadCloserOnError returns a io.ReadCloser that call the notify function
+// when an unexpected (!io.EOF) error happens, after call Read function.
+func NewReadCloserOnError(r io.ReadCloser, notify func(error)) io.ReadCloser {
+ return NewReadCloser(NewReaderOnError(r, notify), r)
+}
+
+func (r *readerOnError) Read(buf []byte) (n int, err error) {
+ n, err = r.Reader.Read(buf)
+ if err != nil && err != io.EOF {
+ r.notify(err)
+ }
+
+ return
+}
+
+type writerOnError struct {
+ io.Writer
+ notify func(error)
+}
+
+// NewWriterOnError returns a io.Writer that call the notify function when an
+// unexpected (!io.EOF) error happens, after call Write function.
+func NewWriterOnError(w io.Writer, notify func(error)) io.Writer {
+ return &writerOnError{w, notify}
+}
+
+// NewWriteCloserOnError returns a io.WriteCloser that call the notify function
+//when an unexpected (!io.EOF) error happens, after call Write function.
+func NewWriteCloserOnError(w io.WriteCloser, notify func(error)) io.WriteCloser {
+ return NewWriteCloser(NewWriterOnError(w, notify), w)
+}
+
+func (r *writerOnError) Write(p []byte) (n int, err error) {
+ n, err = r.Writer.Write(p)
+ if err != nil && err != io.EOF {
+ r.notify(err)
+ }
+
+ return
+}