From 3600ebca76752c08fab9671f02ec0b1494aade5e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Mon, 14 Jul 2025 22:09:31 +0200 Subject: [PATCH] remove uses of github.com/docker/docker/pkg/ioutils ReadCloserWrapper It was the only utility we consumed from the package, and it's trivial to implement, so let's create local copies of it. Signed-off-by: Sebastiaan van Stijn --- cli/command/container/hijack.go | 18 ++- cli/command/image/build/context.go | 29 ++++- .../pkg/ioutils/fswriters_deprecated.go | 44 ------- .../docker/docker/pkg/ioutils/readers.go | 118 ------------------ .../docker/docker/pkg/ioutils/writeflusher.go | 96 -------------- .../docker/docker/pkg/ioutils/writers.go | 28 ----- vendor/modules.txt | 1 - 7 files changed, 41 insertions(+), 293 deletions(-) delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/readers.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go delete mode 100644 vendor/github.com/docker/docker/pkg/ioutils/writers.go diff --git a/cli/command/container/hijack.go b/cli/command/container/hijack.go index 4d5ad26786..8e725cb444 100644 --- a/cli/command/container/hijack.go +++ b/cli/command/container/hijack.go @@ -9,7 +9,6 @@ import ( "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" - "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/stdcopy" "github.com/moby/term" "github.com/sirupsen/logrus" @@ -19,6 +18,18 @@ import ( // TODO: This could be moved to `pkg/term`. var defaultEscapeKeys = []byte{16, 17} +// readCloserWrapper wraps an io.Reader, and implements an io.ReadCloser +// It calls the given callback function when closed. +type readCloserWrapper struct { + io.Reader + closer func() error +} + +// Close calls back the passed closer function +func (r *readCloserWrapper) Close() error { + return r.closer() +} + // A hijackedIOStreamer handles copying input to and output from streams to the // connection. type hijackedIOStreamer struct { @@ -100,7 +111,10 @@ func (h *hijackedIOStreamer) setupInput() (restore func(), err error) { } } - h.inputStream = ioutils.NewReadCloserWrapper(term.NewEscapeProxy(h.inputStream, escapeKeys), h.inputStream.Close) + h.inputStream = &readCloserWrapper{ + Reader: term.NewEscapeProxy(h.inputStream, escapeKeys), + closer: h.inputStream.Close, + } return restore, nil } diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index 4a6abf1515..f1ecfb6821 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -15,7 +15,6 @@ import ( "time" "github.com/docker/docker/builder/remotecontext/git" - "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/stringid" @@ -108,7 +107,7 @@ func DetectArchiveReader(input io.ReadCloser) (rc io.ReadCloser, isArchive bool, return nil, false, errors.Errorf("failed to peek context header from STDIN: %v", err) } - return ioutils.NewReadCloserWrapper(buf, func() error { return input.Close() }), IsArchive(magic), nil + return newReadCloserWrapper(buf, func() error { return input.Close() }), IsArchive(magic), nil } // WriteTempDockerfile writes a Dockerfile stream to a temporary file with a @@ -169,7 +168,7 @@ func GetContextFromReader(rc io.ReadCloser, dockerfileName string) (out io.ReadC return nil, "", err } - return ioutils.NewReadCloserWrapper(tarArchive, func() error { + return newReadCloserWrapper(tarArchive, func() error { err := tarArchive.Close() os.RemoveAll(dockerfileDir) return err @@ -227,7 +226,7 @@ func GetContextFromURL(out io.Writer, remoteURL, dockerfileName string) (io.Read // Pass the response body through a progress reader. progReader := progress.NewProgressReader(response.Body, progressOutput, response.ContentLength, "", "Downloading build context from remote url: "+remoteURL) - return GetContextFromReader(ioutils.NewReadCloserWrapper(progReader, func() error { return response.Body.Close() }), dockerfileName) + return GetContextFromReader(newReadCloserWrapper(progReader, func() error { return response.Body.Close() }), dockerfileName) } // getWithStatusError does an http.Get() and returns an error if the @@ -444,3 +443,25 @@ func Compress(buildCtx io.ReadCloser) (io.ReadCloser, error) { return pipeReader, nil } + +// readCloserWrapper wraps an io.Reader, and implements an io.ReadCloser +// It calls the given callback function when closed. It should be constructed +// with [newReadCloserWrapper]. +type readCloserWrapper struct { + io.Reader + closer func() error +} + +// Close calls back the passed closer function +func (r *readCloserWrapper) Close() error { + return r.closer() +} + +// newReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser. +// It calls the given callback function when closed. +func newReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { + return &readCloserWrapper{ + Reader: r, + closer: closer, + } +} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go b/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go deleted file mode 100644 index f34e06911c..0000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/fswriters_deprecated.go +++ /dev/null @@ -1,44 +0,0 @@ -package ioutils - -import ( - "io" - "os" - - "github.com/moby/sys/atomicwriter" -) - -// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a -// temporary file and closing it atomically changes the temporary file to -// destination path. Writing and closing concurrently is not allowed. -// NOTE: umask is not considered for the file's permissions. -// -// Deprecated: use [atomicwriter.New] instead. -func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) { - return atomicwriter.New(filename, perm) -} - -// AtomicWriteFile atomically writes data to a file named by filename and with the specified permission bits. -// NOTE: umask is not considered for the file's permissions. -// -// Deprecated: use [atomicwriter.WriteFile] instead. -func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error { - return atomicwriter.WriteFile(filename, data, perm) -} - -// AtomicWriteSet is used to atomically write a set -// of files and ensure they are visible at the same time. -// Must be committed to a new directory. -// -// Deprecated: use [atomicwriter.WriteSet] instead. -type AtomicWriteSet = atomicwriter.WriteSet - -// NewAtomicWriteSet creates a new atomic write set to -// atomically create a set of files. The given directory -// is used as the base directory for storing files before -// commit. If no temporary directory is given the system -// default is used. -// -// Deprecated: use [atomicwriter.NewWriteSet] instead. -func NewAtomicWriteSet(tmpDir string) (*atomicwriter.WriteSet, error) { - return atomicwriter.NewWriteSet(tmpDir) -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/readers.go b/vendor/github.com/docker/docker/pkg/ioutils/readers.go deleted file mode 100644 index 21c7a2f688..0000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/readers.go +++ /dev/null @@ -1,118 +0,0 @@ -package ioutils - -import ( - "context" - "io" - "runtime/debug" - "sync/atomic" - - "github.com/containerd/log" -) - -// readCloserWrapper wraps an io.Reader, and implements an io.ReadCloser -// It calls the given callback function when closed. It should be constructed -// with NewReadCloserWrapper -type readCloserWrapper struct { - io.Reader - closer func() error - closed atomic.Bool -} - -// Close calls back the passed closer function -func (r *readCloserWrapper) Close() error { - if !r.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("ReadCloserWrapper") - return nil - } - return r.closer() -} - -// NewReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser. -// It calls the given callback function when closed. -func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { - return &readCloserWrapper{ - Reader: r, - closer: closer, - } -} - -// cancelReadCloser wraps an io.ReadCloser with a context for cancelling read -// operations. -type cancelReadCloser struct { - cancel func() - pR *io.PipeReader // Stream to read from - pW *io.PipeWriter - closed atomic.Bool -} - -// NewCancelReadCloser creates a wrapper that closes the ReadCloser when the -// context is cancelled. The returned io.ReadCloser must be closed when it is -// no longer needed. -func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { - pR, pW := io.Pipe() - - // Create a context used to signal when the pipe is closed - doneCtx, cancel := context.WithCancel(context.Background()) - - p := &cancelReadCloser{ - cancel: cancel, - pR: pR, - pW: pW, - } - - go func() { - _, err := io.Copy(pW, in) - select { - case <-ctx.Done(): - // If the context was closed, p.closeWithError - // was already called. Calling it again would - // change the error that Read returns. - default: - p.closeWithError(err) - } - in.Close() - }() - go func() { - for { - select { - case <-ctx.Done(): - p.closeWithError(ctx.Err()) - case <-doneCtx.Done(): - return - } - } - }() - - return p -} - -// Read wraps the Read method of the pipe that provides data from the wrapped -// ReadCloser. -func (p *cancelReadCloser) Read(buf []byte) (int, error) { - return p.pR.Read(buf) -} - -// closeWithError closes the wrapper and its underlying reader. It will -// cause future calls to Read to return err. -func (p *cancelReadCloser) closeWithError(err error) { - _ = p.pW.CloseWithError(err) - p.cancel() -} - -// Close closes the wrapper its underlying reader. It will cause -// future calls to Read to return io.EOF. -func (p *cancelReadCloser) Close() error { - if !p.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("cancelReadCloser") - return nil - } - p.closeWithError(io.EOF) - return nil -} - -func subsequentCloseWarn(name string) { - log.G(context.TODO()).Error("subsequent attempt to close " + name) - if log.GetLevel() >= log.DebugLevel { - log.G(context.TODO()).Errorf("stack trace: %s", string(debug.Stack())) - } -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go b/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go deleted file mode 100644 index 8d60ef2f62..0000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writeflusher.go +++ /dev/null @@ -1,96 +0,0 @@ -package ioutils - -import ( - "io" - "sync" -) - -// WriteFlusher wraps the Write and Flush operation ensuring that every write -// is a flush. In addition, the Close method can be called to intercept -// Read/Write calls if the targets lifecycle has already ended. -type WriteFlusher struct { - w io.Writer - flusher flusher - flushed chan struct{} - flushedOnce sync.Once - closed chan struct{} - closeLock sync.Mutex -} - -type flusher interface { - Flush() -} - -func (wf *WriteFlusher) Write(b []byte) (int, error) { - select { - case <-wf.closed: - return 0, io.EOF - default: - } - - n, err := wf.w.Write(b) - wf.Flush() // every write is a flush. - return n, err -} - -// Flush the stream immediately. -func (wf *WriteFlusher) Flush() { - select { - case <-wf.closed: - return - default: - } - - wf.flushedOnce.Do(func() { - close(wf.flushed) - }) - wf.flusher.Flush() -} - -// Flushed returns the state of flushed. -// If it's flushed, return true, or else it return false. -func (wf *WriteFlusher) Flushed() bool { - // BUG(stevvooe): Remove this method. Its use is inherently racy. Seems to - // be used to detect whether or a response code has been issued or not. - // Another hook should be used instead. - var flushed bool - select { - case <-wf.flushed: - flushed = true - default: - } - return flushed -} - -// Close closes the write flusher, disallowing any further writes to the -// target. After the flusher is closed, all calls to write or flush will -// result in an error. -func (wf *WriteFlusher) Close() error { - wf.closeLock.Lock() - defer wf.closeLock.Unlock() - - select { - case <-wf.closed: - return io.EOF - default: - close(wf.closed) - } - return nil -} - -// nopFlusher represents a type which flush operation is nop. -type nopFlusher struct{} - -// Flush is a nop operation. -func (f *nopFlusher) Flush() {} - -// NewWriteFlusher returns a new WriteFlusher. -func NewWriteFlusher(w io.Writer) *WriteFlusher { - var fl flusher - if f, ok := w.(flusher); ok { - fl = f - } else { - fl = &nopFlusher{} - } - return &WriteFlusher{w: w, flusher: fl, closed: make(chan struct{}), flushed: make(chan struct{})} -} diff --git a/vendor/github.com/docker/docker/pkg/ioutils/writers.go b/vendor/github.com/docker/docker/pkg/ioutils/writers.go deleted file mode 100644 index 4cf2d4de95..0000000000 --- a/vendor/github.com/docker/docker/pkg/ioutils/writers.go +++ /dev/null @@ -1,28 +0,0 @@ -package ioutils - -import ( - "io" - "sync/atomic" -) - -type writeCloserWrapper struct { - io.Writer - closer func() error - closed atomic.Bool -} - -func (r *writeCloserWrapper) Close() error { - if !r.closed.CompareAndSwap(false, true) { - subsequentCloseWarn("WriteCloserWrapper") - return nil - } - return r.closer() -} - -// NewWriteCloserWrapper returns a new io.WriteCloser. -func NewWriteCloserWrapper(r io.Writer, closer func() error) io.WriteCloser { - return &writeCloserWrapper{ - Writer: r, - closer: closer, - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1abd3baaaa..5d59a5f392 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -95,7 +95,6 @@ github.com/docker/docker/client github.com/docker/docker/internal/lazyregexp github.com/docker/docker/internal/multierror github.com/docker/docker/pkg/homedir -github.com/docker/docker/pkg/ioutils github.com/docker/docker/pkg/jsonmessage github.com/docker/docker/pkg/longpath github.com/docker/docker/pkg/process