From bcc504b8ccecb21c78f220cc22ec6ea478d7aadc Mon Sep 17 00:00:00 2001 From: Pasha Sviderski Date: Tue, 30 Sep 2025 13:58:34 +1000 Subject: [PATCH] chore: internal Docker client PushImage --- internal/docker/image.go | 67 +++++++++++++++++++++++++++---- internal/machine/docker/client.go | 10 ++--- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/internal/docker/image.go b/internal/docker/image.go index c6c112ad..b4d270d5 100644 --- a/internal/docker/image.go +++ b/internal/docker/image.go @@ -15,15 +15,15 @@ import ( "github.com/docker/docker/pkg/jsonmessage" ) -type PullImageMessage struct { +type PullPushImageMessage struct { Message jsonmessage.JSONMessage Err error } -// PullImage pulls a Docker image and returns a channel to receive progress messages. +// PullImage pulls an image and returns a channel to receive progress messages. func (cli *Client) PullImage( ctx context.Context, image string, opts image.PullOptions, -) (<-chan PullImageMessage, error) { +) (<-chan PullPushImageMessage, error) { if opts.RegistryAuth == "" { // Try to retrieve the authentication token for the image from the default local Docker config file. if encodedAuth, err := RetrieveLocalDockerRegistryAuth(image); err == nil { @@ -37,30 +37,81 @@ func (cli *Client) PullImage( } decoder := json.NewDecoder(respBody) - ch := make(chan PullImageMessage) + ch := make(chan PullPushImageMessage) go func() { defer respBody.Close() defer close(ch) - var jm jsonmessage.JSONMessage for { + var jm jsonmessage.JSONMessage if err = decoder.Decode(&jm); err != nil { if errors.Is(err, io.EOF) { break } - ch <- PullImageMessage{Err: fmt.Errorf("decode image pull message: %w", err)} + ch <- PullPushImageMessage{Err: fmt.Errorf("decode image pull message: %w", err)} break } - msg := PullImageMessage{Message: jm} + msg := PullPushImageMessage{Message: jm} if jm.Error != nil { msg.Err = errors.New(jm.Error.Message) } select { case <-ctx.Done(): - ch <- PullImageMessage{Err: ctx.Err()} + ch <- PullPushImageMessage{Err: ctx.Err()} + return + default: + ch <- msg + } + } + }() + + return ch, nil +} + +// PushImage pushes an image and returns a channel to receive progress messages. +func (cli *Client) PushImage( + ctx context.Context, image string, opts image.PushOptions, +) (<-chan PullPushImageMessage, error) { + if opts.RegistryAuth == "" { + // Try to retrieve the authentication token for the image from the default local Docker config file. + if encodedAuth, err := RetrieveLocalDockerRegistryAuth(image); err == nil { + opts.RegistryAuth = encodedAuth + } + } + + respBody, err := cli.ImagePush(ctx, image, opts) + if err != nil { + return nil, err + } + + decoder := json.NewDecoder(respBody) + ch := make(chan PullPushImageMessage) + + go func() { + defer respBody.Close() + defer close(ch) + + for { + var jm jsonmessage.JSONMessage + if err = decoder.Decode(&jm); err != nil { + if errors.Is(err, io.EOF) { + break + } + ch <- PullPushImageMessage{Err: fmt.Errorf("decode image push message: %w", err)} + break + } + + msg := PullPushImageMessage{Message: jm} + if jm.Error != nil { + msg.Err = errors.New(jm.Error.Message) + } + + select { + case <-ctx.Done(): + ch <- PullPushImageMessage{Err: ctx.Err()} return default: ch <- msg diff --git a/internal/machine/docker/client.go b/internal/machine/docker/client.go index d2b6e4c0..9dbd2895 100644 --- a/internal/machine/docker/client.go +++ b/internal/machine/docker/client.go @@ -206,7 +206,7 @@ type PullOptions struct { Platform string } -func (c *Client) PullImage(ctx context.Context, image string, opts PullOptions) (<-chan docker.PullImageMessage, error) { +func (c *Client) PullImage(ctx context.Context, image string, opts PullOptions) (<-chan docker.PullPushImageMessage, error) { optsBytes, err := json.Marshal(opts) if err != nil { return nil, fmt.Errorf("marshal options: %w", err) @@ -217,7 +217,7 @@ func (c *Client) PullImage(ctx context.Context, image string, opts PullOptions) return nil, err } - ch := make(chan docker.PullImageMessage) + ch := make(chan docker.PullPushImageMessage) go func() { defer close(ch) @@ -228,16 +228,16 @@ func (c *Client) PullImage(ctx context.Context, image string, opts PullOptions) return } if err != nil { - ch <- docker.PullImageMessage{Err: err} + ch <- docker.PullPushImageMessage{Err: err} return } var jm jsonmessage.JSONMessage if err = json.Unmarshal(msg.Message, &jm); err != nil { - ch <- docker.PullImageMessage{Err: fmt.Errorf("unmarshal JSON message: %w", err)} + ch <- docker.PullPushImageMessage{Err: fmt.Errorf("unmarshal JSON message: %w", err)} return } - ch <- docker.PullImageMessage{Message: jm} + ch <- docker.PullPushImageMessage{Message: jm} } }()