mirror of https://github.com/containers/podman.git
pkg/copy: add parsing API
Add an API for parsing user input into a possibly specified container and path. This allows for sharing the parsing code between the local and the remote client (and bindings) in the future. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
parent
dd295f297b
commit
8472efdbd1
|
@ -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
|
||||||
|
}
|
|
@ -2,46 +2,53 @@ package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
"github.com/containers/podman/v2/pkg/copy"
|
"github.com/containers/podman/v2/pkg/copy"
|
||||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
"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 {
|
func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) error {
|
||||||
srcCtr, srcPath := parsePath(ic.Libpod, source)
|
// Parse user input.
|
||||||
destCtr, destPath := parsePath(ic.Libpod, dest)
|
sourceContainerStr, sourcePath, destContainerStr, destPath, err := copy.ParseSourceAndDestination(source, dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if srcCtr != nil && destCtr != nil {
|
// Look up containers.
|
||||||
return errors.Errorf("invalid arguments %q, %q: you must use just one container", source, dest)
|
var sourceContainer, destContainer *libpod.Container
|
||||||
|
if len(sourceContainerStr) > 0 {
|
||||||
|
sourceContainer, err = ic.Libpod.LookupContainer(sourceContainerStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if srcCtr == nil && destCtr == nil {
|
if len(destContainerStr) > 0 {
|
||||||
return errors.Errorf("invalid arguments %q, %q: you must specify one container", source, dest)
|
destContainer, err = ic.Libpod.LookupContainer(destContainerStr)
|
||||||
}
|
if err != nil {
|
||||||
if len(srcPath) == 0 || len(destPath) == 0 {
|
return err
|
||||||
return errors.Errorf("invalid arguments %q, %q: you must specify paths", source, dest)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sourceItem, destinationItem copy.CopyItem
|
var sourceItem, destinationItem copy.CopyItem
|
||||||
var err error
|
|
||||||
// Copy from the container to the host.
|
// Source ... container OR host.
|
||||||
if srcCtr != nil {
|
if sourceContainer != nil {
|
||||||
sourceItem, err = copy.CopyItemForContainer(srcCtr, srcPath, options.Pause, true)
|
sourceItem, err = copy.CopyItemForContainer(sourceContainer, sourcePath, options.Pause, true)
|
||||||
defer sourceItem.CleanUp()
|
defer sourceItem.CleanUp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sourceItem, err = copy.CopyItemForHost(srcPath, true)
|
sourceItem, err = copy.CopyItemForHost(sourcePath, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if destCtr != nil {
|
// Destination ... container OR host.
|
||||||
destinationItem, err = copy.CopyItemForContainer(destCtr, destPath, options.Pause, false)
|
if destContainer != nil {
|
||||||
|
destinationItem, err = copy.CopyItemForContainer(destContainer, destPath, options.Pause, false)
|
||||||
defer destinationItem.CleanUp()
|
defer destinationItem.CleanUp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -57,20 +64,3 @@ func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string,
|
||||||
// Copy from the host to the container.
|
// Copy from the host to the container.
|
||||||
return copy.Copy(&sourceItem, &destinationItem, options.Extract)
|
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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 {
|
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
|
// Shutdown Libpod engine
|
||||||
|
|
Loading…
Reference in New Issue