diff --git a/client/image_save.go b/client/image_save.go index 5be9864186..1a2bc1fc6e 100644 --- a/client/image_save.go +++ b/client/image_save.go @@ -2,9 +2,14 @@ package client import ( "context" + "io" "net/url" ) +type ImageSaveResult interface { + io.ReadCloser +} + // ImageSave retrieves one or more images from the docker host as an // [ImageSaveResult]. // @@ -15,7 +20,7 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts .. var opts imageSaveOpts for _, opt := range saveOpts { if err := opt.Apply(&opts); err != nil { - return ImageSaveResult{}, err + return nil, err } } @@ -25,18 +30,44 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts .. if len(opts.apiOptions.Platforms) > 0 { if err := cli.requiresVersion(ctx, "1.48", "platform"); err != nil { - return ImageSaveResult{}, err + return nil, err } p, err := encodePlatforms(opts.apiOptions.Platforms...) if err != nil { - return ImageSaveResult{}, err + return nil, err } query["platform"] = p } resp, err := cli.get(ctx, "/images/get", query, nil) if err != nil { - return ImageSaveResult{}, err + return nil, err } - return newImageSaveResult(resp.Body), nil + return &imageSaveResult{ + body: resp.Body, + }, nil +} + +type imageSaveResult struct { + // body must be closed to avoid a resource leak + body io.ReadCloser +} + +var ( + _ io.ReadCloser = (*imageSaveResult)(nil) + _ ImageSaveResult = (*imageSaveResult)(nil) +) + +func (r *imageSaveResult) Read(p []byte) (int, error) { + if r == nil || r.body == nil { + return 0, io.EOF + } + return r.body.Read(p) +} + +func (r *imageSaveResult) Close() error { + if r == nil || r.body == nil { + return nil + } + return r.body.Close() } diff --git a/client/image_save_opts.go b/client/image_save_opts.go index 480126544d..c51c2d5354 100644 --- a/client/image_save_opts.go +++ b/client/image_save_opts.go @@ -2,8 +2,6 @@ package client import ( "fmt" - "io" - "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -38,34 +36,3 @@ type imageSaveOptions struct { // multi-platform image and has multiple variants. Platforms []ocispec.Platform } - -func newImageSaveResult(rc io.ReadCloser) ImageSaveResult { - if rc == nil { - panic("nil io.ReadCloser") - } - return ImageSaveResult{ - rc: rc, - close: sync.OnceValue(rc.Close), - } -} - -type ImageSaveResult struct { - rc io.ReadCloser - close func() error -} - -// Read implements io.ReadCloser -func (r ImageSaveResult) Read(p []byte) (n int, err error) { - if r.rc == nil { - return 0, io.EOF - } - return r.rc.Read(p) -} - -// Close implements io.ReadCloser -func (r ImageSaveResult) Close() error { - if r.close == nil { - return nil - } - return r.close() -} diff --git a/vendor/github.com/moby/moby/client/image_save.go b/vendor/github.com/moby/moby/client/image_save.go index 5be9864186..1a2bc1fc6e 100644 --- a/vendor/github.com/moby/moby/client/image_save.go +++ b/vendor/github.com/moby/moby/client/image_save.go @@ -2,9 +2,14 @@ package client import ( "context" + "io" "net/url" ) +type ImageSaveResult interface { + io.ReadCloser +} + // ImageSave retrieves one or more images from the docker host as an // [ImageSaveResult]. // @@ -15,7 +20,7 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts .. var opts imageSaveOpts for _, opt := range saveOpts { if err := opt.Apply(&opts); err != nil { - return ImageSaveResult{}, err + return nil, err } } @@ -25,18 +30,44 @@ func (cli *Client) ImageSave(ctx context.Context, imageIDs []string, saveOpts .. if len(opts.apiOptions.Platforms) > 0 { if err := cli.requiresVersion(ctx, "1.48", "platform"); err != nil { - return ImageSaveResult{}, err + return nil, err } p, err := encodePlatforms(opts.apiOptions.Platforms...) if err != nil { - return ImageSaveResult{}, err + return nil, err } query["platform"] = p } resp, err := cli.get(ctx, "/images/get", query, nil) if err != nil { - return ImageSaveResult{}, err + return nil, err } - return newImageSaveResult(resp.Body), nil + return &imageSaveResult{ + body: resp.Body, + }, nil +} + +type imageSaveResult struct { + // body must be closed to avoid a resource leak + body io.ReadCloser +} + +var ( + _ io.ReadCloser = (*imageSaveResult)(nil) + _ ImageSaveResult = (*imageSaveResult)(nil) +) + +func (r *imageSaveResult) Read(p []byte) (int, error) { + if r == nil || r.body == nil { + return 0, io.EOF + } + return r.body.Read(p) +} + +func (r *imageSaveResult) Close() error { + if r == nil || r.body == nil { + return nil + } + return r.body.Close() } diff --git a/vendor/github.com/moby/moby/client/image_save_opts.go b/vendor/github.com/moby/moby/client/image_save_opts.go index 480126544d..c51c2d5354 100644 --- a/vendor/github.com/moby/moby/client/image_save_opts.go +++ b/vendor/github.com/moby/moby/client/image_save_opts.go @@ -2,8 +2,6 @@ package client import ( "fmt" - "io" - "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -38,34 +36,3 @@ type imageSaveOptions struct { // multi-platform image and has multiple variants. Platforms []ocispec.Platform } - -func newImageSaveResult(rc io.ReadCloser) ImageSaveResult { - if rc == nil { - panic("nil io.ReadCloser") - } - return ImageSaveResult{ - rc: rc, - close: sync.OnceValue(rc.Close), - } -} - -type ImageSaveResult struct { - rc io.ReadCloser - close func() error -} - -// Read implements io.ReadCloser -func (r ImageSaveResult) Read(p []byte) (n int, err error) { - if r.rc == nil { - return 0, io.EOF - } - return r.rc.Read(p) -} - -// Close implements io.ReadCloser -func (r ImageSaveResult) Close() error { - if r.close == nil { - return nil - } - return r.close() -}