mirror of https://github.com/docker/compose.git
compose cp doesn't need a full project and can copy from stopped container
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
e2f33af831
commit
c5b7624d10
|
@ -73,12 +73,12 @@ func copyCommand(p *projectOptions, backend api.Service) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCopy(ctx context.Context, backend api.Service, opts copyOptions) error {
|
func runCopy(ctx context.Context, backend api.Service, opts copyOptions) error {
|
||||||
projects, err := opts.toProject(nil)
|
name, err := opts.toProjectName()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return backend.Copy(ctx, projects, api.CopyOptions{
|
return backend.Copy(ctx, name, api.CopyOptions{
|
||||||
Source: opts.source,
|
Source: opts.source,
|
||||||
Destination: opts.destination,
|
Destination: opts.destination,
|
||||||
All: opts.all,
|
All: opts.all,
|
||||||
|
|
|
@ -63,7 +63,7 @@ type Service interface {
|
||||||
// Exec executes a command in a running service container
|
// Exec executes a command in a running service container
|
||||||
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
|
Exec(ctx context.Context, project string, opts RunOptions) (int, error)
|
||||||
// Copy copies a file/folder between a service container and the local filesystem
|
// Copy copies a file/folder between a service container and the local filesystem
|
||||||
Copy(ctx context.Context, project *types.Project, opts CopyOptions) error
|
Copy(ctx context.Context, project string, options CopyOptions) error
|
||||||
// Pause executes the equivalent to a `compose pause`
|
// Pause executes the equivalent to a `compose pause`
|
||||||
Pause(ctx context.Context, project string, options PauseOptions) error
|
Pause(ctx context.Context, project string, options PauseOptions) error
|
||||||
// UnPause executes the equivalent to a `compose unpause`
|
// UnPause executes the equivalent to a `compose unpause`
|
||||||
|
|
|
@ -41,7 +41,7 @@ type ServiceProxy struct {
|
||||||
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
RunOneOffContainerFn func(ctx context.Context, project *types.Project, opts RunOptions) (int, error)
|
||||||
RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error
|
RemoveFn func(ctx context.Context, project *types.Project, options RemoveOptions) error
|
||||||
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
|
ExecFn func(ctx context.Context, project string, opts RunOptions) (int, error)
|
||||||
CopyFn func(ctx context.Context, project *types.Project, opts CopyOptions) error
|
CopyFn func(ctx context.Context, project string, options CopyOptions) error
|
||||||
PauseFn func(ctx context.Context, project string, options PauseOptions) error
|
PauseFn func(ctx context.Context, project string, options PauseOptions) error
|
||||||
UnPauseFn func(ctx context.Context, project string, options PauseOptions) error
|
UnPauseFn func(ctx context.Context, project string, options PauseOptions) error
|
||||||
TopFn func(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy implements Service interface
|
// Copy implements Service interface
|
||||||
func (s *ServiceProxy) Copy(ctx context.Context, project *types.Project, options CopyOptions) error {
|
func (s *ServiceProxy) Copy(ctx context.Context, project string, options CopyOptions) error {
|
||||||
if s.CopyFn == nil {
|
if s.CopyFn == nil {
|
||||||
return ErrNotImplemented
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
for _, i := range s.interceptors {
|
|
||||||
i(ctx, project)
|
|
||||||
}
|
|
||||||
return s.CopyFn(ctx, project, options)
|
return s.CopyFn(ctx, project, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package compose
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
@ -86,6 +87,14 @@ func isNotOneOff(c moby.Container) bool {
|
||||||
return !ok || v == "False"
|
return !ok || v == "False"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func indexed(index int) containerPredicate {
|
||||||
|
return func(c moby.Container) bool {
|
||||||
|
number := c.Labels[api.ContainerNumberLabel]
|
||||||
|
idx, err := strconv.Atoi(number)
|
||||||
|
return err == nil && index == idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// filter return Containers with elements to match predicate
|
// filter return Containers with elements to match predicate
|
||||||
func (containers Containers) filter(predicate containerPredicate) Containers {
|
func (containers Containers) filter(predicate containerPredicate) Containers {
|
||||||
var filtered Containers
|
var filtered Containers
|
||||||
|
|
|
@ -26,11 +26,9 @@ import (
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/compose-spec/compose-go/types"
|
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/compose/v2/pkg/api"
|
"github.com/docker/compose/v2/pkg/api"
|
||||||
moby "github.com/docker/docker/api/types"
|
moby "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -44,7 +42,7 @@ const (
|
||||||
acrossServices = fromService | toService
|
acrossServices = fromService | toService
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *composeService) Copy(ctx context.Context, project *types.Project, opts api.CopyOptions) error {
|
func (s *composeService) Copy(ctx context.Context, project string, opts api.CopyOptions) error {
|
||||||
srcService, srcPath := splitCpArg(opts.Source)
|
srcService, srcPath := splitCpArg(opts.Source)
|
||||||
destService, dstPath := splitCpArg(opts.Destination)
|
destService, dstPath := splitCpArg(opts.Destination)
|
||||||
|
|
||||||
|
@ -64,20 +62,17 @@ func (s *composeService) Copy(ctx context.Context, project *types.Project, opts
|
||||||
serviceName = destService
|
serviceName = destService
|
||||||
}
|
}
|
||||||
|
|
||||||
f := filters.NewArgs(
|
containers, err := s.getContainers(ctx, project, oneOffExclude, true, serviceName)
|
||||||
projectFilter(project.Name),
|
|
||||||
serviceFilter(serviceName),
|
|
||||||
)
|
|
||||||
if !opts.All {
|
|
||||||
f.Add("label", fmt.Sprintf("%s=%d", api.ContainerNumberLabel, opts.Index))
|
|
||||||
}
|
|
||||||
containers, err := s.apiClient.ContainerList(ctx, moby.ContainerListOptions{Filters: f})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(containers) < 1 {
|
if len(containers) < 1 {
|
||||||
return fmt.Errorf("service %s not running", serviceName)
|
return fmt.Errorf("no container found for service %q", serviceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !opts.All {
|
||||||
|
containers = containers.filter(indexed(opts.Index))
|
||||||
}
|
}
|
||||||
|
|
||||||
g := errgroup.Group{}
|
g := errgroup.Group{}
|
||||||
|
|
Loading…
Reference in New Issue