Skip to content

Commit c5b7624

Browse files
committed
compose cp doesn't need a full project and can copy from stopped container
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent e2f33af commit c5b7624

File tree

5 files changed

+21
-20
lines changed

5 files changed

+21
-20
lines changed

cmd/compose/cp.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command {
7373
}
7474

7575
func runCopy(ctx context.Context, backend api.Service, opts copyOptions) error {
76-
projects, err := opts.toProject(nil)
76+
name, err := opts.toProjectName()
7777
if err != nil {
7878
return err
7979
}
8080

81-
return backend.Copy(ctx, projects, api.CopyOptions{
81+
return backend.Copy(ctx, name, api.CopyOptions{
8282
Source: opts.source,
8383
Destination: opts.destination,
8484
All: opts.all,

pkg/api/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ type Service interface {
6363
// Exec executes a command in a running service container
6464
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
6565
// Copy copies a file/folder between a service container and the local filesystem
66-
Copy(ctx context.Context, project *types.Project, opts CopyOptions) error
66+
Copy(ctx context.Context, project string, options CopyOptions) error
6767
// Pause executes the equivalent to a `compose pause`
6868
Pause(ctx context.Context, project string, options PauseOptions) error
6969
// UnPause executes the equivalent to a `compose unpause`

pkg/api/proxy.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type ServiceProxy struct {
4141
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
4242
RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error
4343
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
44-
CopyFn func(ctx context.Context, project *types.Project, opts CopyOptions) error
44+
CopyFn func(ctx context.Context, project string, options CopyOptions) error
4545
PauseFn func(ctx context.Context, project string, options PauseOptions) error
4646
UnPauseFn func(ctx context.Context, project string, options PauseOptions) error
4747
TopFn func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
@@ -269,13 +269,10 @@ func (s *ServiceProxy) Exec(ctx context.Context, project string, options RunOpti
269269
}
270270

271271
// Copy implements Service interface
272-
func (s *ServiceProxy) Copy(ctx context.Context, project *types.Project, options CopyOptions) error {
272+
func (s *ServiceProxy) Copy(ctx context.Context, project string, options CopyOptions) error {
273273
if s.CopyFn == nil {
274274
return ErrNotImplemented
275275
}
276-
for _, i := range s.interceptors {
277-
i(ctx, project)
278-
}
279276
return s.CopyFn(ctx, project, options)
280277
}
281278

pkg/compose/containers.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package compose
1919
import (
2020
"context"
2121
"sort"
22+
"strconv"
2223

2324
moby "github.com/docker/docker/api/types"
2425
"github.com/docker/docker/api/types/filters"
@@ -86,6 +87,14 @@ func isNotOneOff(c moby.Container) bool {
8687
return !ok || v == "False"
8788
}
8889

90+
func indexed(index int) containerPredicate {
91+
return func(c moby.Container) bool {
92+
number := c.Labels[api.ContainerNumberLabel]
93+
idx, err := strconv.Atoi(number)
94+
return err == nil && index == idx
95+
}
96+
}
97+
8998
// filter return Containers with elements to match predicate
9099
func (containers Containers) filter(predicate containerPredicate) Containers {
91100
var filtered Containers

pkg/compose/cp.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ import (
2626

2727
"golang.org/x/sync/errgroup"
2828

29-
"github.com/compose-spec/compose-go/types"
3029
"github.com/docker/cli/cli/command"
3130
"github.com/docker/compose/v2/pkg/api"
3231
moby "github.com/docker/docker/api/types"
33-
"github.com/docker/docker/api/types/filters"
3432
"github.com/docker/docker/pkg/archive"
3533
"github.com/docker/docker/pkg/system"
3634
"github.com/pkg/errors"
@@ -44,7 +42,7 @@ const (
4442
acrossServices = fromService | toService
4543
)
4644

47-
func (s *composeService) Copy(ctx context.Context, project *types.Project, opts api.CopyOptions) error {
45+
func (s *composeService) Copy(ctx context.Context, project string, opts api.CopyOptions) error {
4846
srcService, srcPath := splitCpArg(opts.Source)
4947
destService, dstPath := splitCpArg(opts.Destination)
5048

@@ -64,20 +62,17 @@ func (s *composeService) Copy(ctx context.Context, project *types.Project, opts
6462
serviceName = destService
6563
}
6664

67-
f := filters.NewArgs(
68-
projectFilter(project.Name),
69-
serviceFilter(serviceName),
70-
)
71-
if !opts.All {
72-
f.Add("label", fmt.Sprintf("%s=%d", api.ContainerNumberLabel, opts.Index))
73-
}
74-
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{Filters: f})
65+
containers, err := s.getContainers(ctx, project, oneOffExclude, true, serviceName)
7566
if err != nil {
7667
return err
7768
}
7869

7970
if len(containers) < 1 {
80-
return fmt.Errorf("service %s not running", serviceName)
71+
return fmt.Errorf("no container found for service %q", serviceName)
72+
}
73+
74+
if !opts.All {
75+
containers = containers.filter(indexed(opts.Index))
8176
}
8277

8378
g := errgroup.Group{}

0 commit comments

Comments
 (0)