diff options
-rw-r--r-- | pkg/copy/parse.go | 61 | ||||
-rw-r--r-- | pkg/domain/infra/abi/cp.go | 60 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 3 |
3 files changed, 88 insertions, 36 deletions
diff --git a/pkg/copy/parse.go b/pkg/copy/parse.go new file mode 100644 index 000000000..39e0e1547 --- /dev/null +++ b/pkg/copy/parse.go @@ -0,0 +1,61 @@ +package copy + +import ( + "strings" + + "github.com/pkg/errors" +) + +// ParseSourceAndDestination parses the source and destination input into a +// possibly specified container and path. The input format is described in +// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long +// they start with a dot or slash. +// +// It returns, in order, the source container and path, followed by the +// destination container and path, and an error. Note that exactly one +// container must be specified. +func ParseSourceAndDestination(source, destination string) (string, string, string, string, error) { + sourceContainer, sourcePath := parseUserInput(source) + destContainer, destPath := parseUserInput(destination) + + numContainers := 0 + if len(sourceContainer) > 0 { + numContainers++ + } + if len(destContainer) > 0 { + numContainers++ + } + + if numContainers != 1 { + return "", "", "", "", errors.Errorf("invalid arguments %q, %q: exactly 1 container expected but %d specified", source, destination, numContainers) + } + + if len(sourcePath) == 0 || len(destPath) == 0 { + return "", "", "", "", errors.Errorf("invalid arguments %q, %q: you must specify paths", source, destination) + } + + return sourceContainer, sourcePath, destContainer, destPath, nil +} + +// parseUserInput parses the input string and returns, if specified, the name +// or ID of the container and the path. The input format is described in +// podman-cp(1) as "[nameOrID:]path". Colons in paths are supported as long +// they start with a dot or slash. +func parseUserInput(input string) (container string, path string) { + if len(input) == 0 { + return + } + path = input + + // If the input starts with a dot or slash, it cannot refer to a + // container. + if input[0] == '.' || input[0] == '/' { + return + } + + if spl := strings.SplitN(path, ":", 2); len(spl) == 2 { + container = spl[0] + path = spl[1] + } + return +} diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go index 9409df743..7cc3005c1 100644 --- a/pkg/domain/infra/abi/cp.go +++ b/pkg/domain/infra/abi/cp.go @@ -2,46 +2,53 @@ package abi import ( "context" - "strings" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/pkg/copy" "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/pkg/errors" ) func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error { - srcCtr, srcPath := parsePath(ic.Libpod, source) - destCtr, destPath := parsePath(ic.Libpod, dest) - - if srcCtr != nil && destCtr != nil { - return errors.Errorf("invalid arguments %q, %q: you must use just one container", source, dest) + // Parse user input. + sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest) + if err != nil { + return err } - if srcCtr == nil && destCtr == nil { - return errors.Errorf("invalid arguments %q, %q: you must specify one container", source, dest) + + // Look up containers. + var sourceContainer, destContainer *libpod.Container + if len(sourceContainerStr) > 0 { + sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr) + if err != nil { + return err + } } - if len(srcPath) == 0 || len(destPath) == 0 { - return errors.Errorf("invalid arguments %q, %q: you must specify paths", source, dest) + if len(destContainerStr) > 0 { + destContainer, err = ic.Libpod.LookupContainer(destContainerStr) + if err != nil { + return err + } } var sourceItem, destinationItem copy.CopyItem - var err error - // Copy from the container to the host. - if srcCtr != nil { - sourceItem, err = copy.CopyItemForContainer(srcCtr, srcPath, options.Pause, true) + + // Source ... container OR host. + if sourceContainer != nil { + sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true) defer sourceItem.CleanUp() if err != nil { return err } } else { - sourceItem, err = copy.CopyItemForHost(srcPath, true) + sourceItem, err = copy.CopyItemForHost(sourcePath, true) if err != nil { return err } } - if destCtr != nil { - destinationItem, err = copy.CopyItemForContainer(destCtr, destPath, options.Pause, false) + // Destination ... container OR host. + if destContainer != nil { + destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false) defer destinationItem.CleanUp() if err != nil { return err @@ -57,20 +64,3 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, // Copy from the host to the container. return copy.Copy(&sourceItem, &destinationItem, options.Extract) } - -func parsePath(runtime *libpod.Runtime, path string) (*libpod.Container, string) { - if len(path) == 0 { - return nil, "" - } - if path[0] == '.' || path[0] == '/' { // A path cannot point to a container. - return nil, path - } - pathArr := strings.SplitN(path, ":", 2) - if len(pathArr) == 2 { - ctr, err := runtime.LookupContainer(pathArr[0]) - if err == nil { - return ctr, pathArr[1] - } - } - return nil, path -} diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 3584668c7..e65fef0a4 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -732,7 +732,8 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o } func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error { - return errors.New("not implemented") + return nil + // return containers.Copy(ic.ClientCxt, source, dest, options) } // Shutdown Libpod engine |