Skip to content

Commit a0f877d

Browse files
authored
Merge pull request moby#51316 from austinvazquez/refactor-client-container-export
client: refactor `ContainerExport` to wrap options/result structs
2 parents c438b3f + 749c980 commit a0f877d

File tree

9 files changed

+95
-19
lines changed

9 files changed

+95
-19
lines changed

client/client_interfaces.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ type ContainerAPIClient interface {
5959
ContainerCreate(ctx context.Context, options ContainerCreateOptions) (ContainerCreateResult, error)
6060
ContainerDiff(ctx context.Context, container string, options ContainerDiffOptions) (ContainerDiffResult, error)
6161
ExecAPIClient
62-
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
62+
ContainerExport(ctx context.Context, container string, options ContainerExportOptions) (ContainerExportResult, error)
6363
ContainerInspect(ctx context.Context, container string, options ContainerInspectOptions) (ContainerInspectResult, error)
6464
ContainerKill(ctx context.Context, container string, options ContainerKillOptions) (ContainerKillResult, error)
6565
ContainerList(ctx context.Context, options ContainerListOptions) (ContainerListResult, error)

client/container_export.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,59 @@ import (
44
"context"
55
"io"
66
"net/url"
7+
"sync"
78
)
89

10+
// ContainerExportOptions specifies options for container export operations.
11+
type ContainerExportOptions struct {
12+
// Currently no options are defined for ContainerExport
13+
}
14+
15+
// ContainerExportResult represents the result of a container export operation.
16+
type ContainerExportResult struct {
17+
rc io.ReadCloser
18+
close func() error
19+
}
20+
921
// ContainerExport retrieves the raw contents of a container
1022
// and returns them as an [io.ReadCloser]. It's up to the caller
1123
// to close the stream.
12-
func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) {
24+
func (cli *Client) ContainerExport(ctx context.Context, containerID string, options ContainerExportOptions) (ContainerExportResult, error) {
1325
containerID, err := trimID("container", containerID)
1426
if err != nil {
15-
return nil, err
27+
return ContainerExportResult{}, err
1628
}
1729

1830
resp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
1931
if err != nil {
20-
return nil, err
32+
return ContainerExportResult{}, err
33+
}
34+
35+
return newContainerExportResult(resp.Body), nil
36+
}
37+
38+
func newContainerExportResult(rc io.ReadCloser) ContainerExportResult {
39+
if rc == nil {
40+
panic("nil io.ReadCloser")
41+
}
42+
return ContainerExportResult{
43+
rc: rc,
44+
close: sync.OnceValue(rc.Close),
2145
}
46+
}
2247

23-
return resp.Body, nil
48+
// Read implements io.ReadCloser
49+
func (r ContainerExportResult) Read(p []byte) (n int, err error) {
50+
if r.rc == nil {
51+
return 0, io.EOF
52+
}
53+
return r.rc.Read(p)
54+
}
55+
56+
// Close implements io.ReadCloser
57+
func (r ContainerExportResult) Close() error {
58+
if r.close == nil {
59+
return nil
60+
}
61+
return r.close()
2462
}

client/container_export_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ func TestContainerExportError(t *testing.T) {
1717
)
1818
assert.NilError(t, err)
1919

20-
_, err = client.ContainerExport(context.Background(), "nothing")
20+
_, err = client.ContainerExport(context.Background(), "nothing", ContainerExportOptions{})
2121
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
2222

23-
_, err = client.ContainerExport(context.Background(), "")
23+
_, err = client.ContainerExport(context.Background(), "", ContainerExportOptions{})
2424
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
2525
assert.Check(t, is.ErrorContains(err, "value is empty"))
2626

27-
_, err = client.ContainerExport(context.Background(), " ")
27+
_, err = client.ContainerExport(context.Background(), " ", ContainerExportOptions{})
2828
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
2929
assert.Check(t, is.ErrorContains(err, "value is empty"))
3030
}
@@ -40,7 +40,7 @@ func TestContainerExport(t *testing.T) {
4040
}),
4141
)
4242
assert.NilError(t, err)
43-
body, err := client.ContainerExport(context.Background(), "container_id")
43+
body, err := client.ContainerExport(context.Background(), "container_id", ContainerExportOptions{})
4444
assert.NilError(t, err)
4545
defer body.Close()
4646
content, err := io.ReadAll(body)

integration-cli/docker_api_containers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (s *DockerAPISuite) TestContainerAPIGetExport(c *testing.T) {
103103
assert.NilError(c, err)
104104
defer apiClient.Close()
105105

106-
body, err := apiClient.ContainerExport(testutil.GetContext(c), name)
106+
body, err := apiClient.ContainerExport(testutil.GetContext(c), name, client.ContainerExportOptions{})
107107
assert.NilError(c, err)
108108
defer body.Close()
109109
found := false

integration/container/export_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestExportContainerAndImportImage(t *testing.T) {
2727
poll.WaitOn(t, container.IsStopped(ctx, apiClient, cID))
2828

2929
reference := "repo/" + strings.ToLower(t.Name()) + ":v1"
30-
exportRes, err := apiClient.ContainerExport(ctx, cID)
30+
exportRes, err := apiClient.ContainerExport(ctx, cID, client.ContainerExportOptions{})
3131
assert.NilError(t, err)
3232
importRes, err := apiClient.ImageImport(ctx, client.ImageImportSource{
3333
Source: exportRes,
@@ -70,6 +70,6 @@ func TestExportContainerAfterDaemonRestart(t *testing.T) {
7070

7171
d.Restart(t)
7272

73-
_, err := c.ContainerExport(ctx, ctrID)
73+
_, err := c.ContainerExport(ctx, ctrID, client.ContainerExportOptions{})
7474
assert.NilError(t, err)
7575
}

integration/container/overlayfs_linux_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func TestNoOverlayfsWarningsAboutUndefinedBehaviors(t *testing.T) {
3232
return err
3333
}},
3434
{name: "export", operation: func(*testing.T) error {
35-
rc, err := apiClient.ContainerExport(ctx, cID)
35+
rc, err := apiClient.ContainerExport(ctx, cID, client.ContainerExportOptions{})
3636
if err == nil {
3737
defer rc.Close()
3838
_, err = io.Copy(io.Discard, rc)

integration/plugin/authz/authz_plugin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ func TestAuthZPluginEnsureLoadImportWorking(t *testing.T) {
362362

363363
cID := container.Run(ctx, t, c)
364364

365-
responseReader, err := c.ContainerExport(ctx, cID)
365+
responseReader, err := c.ContainerExport(ctx, cID, client.ContainerExportOptions{})
366366
assert.NilError(t, err)
367367
defer responseReader.Close()
368368
file, err := os.Create(exportedImagePath)

vendor/github.com/moby/moby/client/client_interfaces.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/moby/moby/client/container_export.go

Lines changed: 42 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)