Merge pull request #11065 from vrothberg/cp-cleanups

cp: consolidate and simplify
This commit is contained in:
OpenShift Merge Robot
2021-07-28 15:07:27 +02:00
committed by GitHub

View File

@ -131,43 +131,17 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer) return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer)
} }
var destContainerBaseName string destContainerBaseName, destContainerInfo, destResolvedToParentDir, err := resolvePathOnDestinationContainer(destContainer, destPath, false)
destContainerInfo, destContainerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, destPath)
if destContainerInfoErr != nil {
if strings.HasSuffix(destPath, "/") {
return errors.Wrapf(destContainerInfoErr, "%q could not be found on container %s", destPath, destContainer)
}
// NOTE: containerInfo may actually be set. That happens when
// the container path is a symlink into nirvana. In that case,
// we must use the symlinked path instead.
path := destPath
if destContainerInfo != nil {
destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
path = destContainerInfo.LinkTarget
} else {
destContainerBaseName = filepath.Base(destPath)
}
parentDir, err := containerParentDir(destContainer, path)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, destContainer) return err
}
destContainerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, parentDir)
if err != nil {
return errors.Wrapf(err, "%q could not be found on container %s", destPath, destContainer)
}
} else {
// If the specified path exists on the container, we must use
// its base path as it may have changed due to symlink
// evaluations.
destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
} }
if sourceContainerInfo.IsDir && !destContainerInfo.IsDir { if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
return errors.New("destination must be a directory when copying a directory") return errors.New("destination must be a directory when copying a directory")
} }
sourceContainerTarget, destContainerTarget := sourceContainerInfo.LinkTarget, destContainerInfo.LinkTarget sourceContainerTarget := sourceContainerInfo.LinkTarget
destContainerTarget := destContainerInfo.LinkTarget
if !destContainerInfo.IsDir { if !destContainerInfo.IsDir {
destContainerTarget = filepath.Dir(destPath) destContainerTarget = filepath.Dir(destPath)
} }
@ -180,7 +154,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
// Hence, whenever "." is the source and the destination does not // Hence, whenever "." is the source and the destination does not
// exist, we copy the source's parent and let the copier package create // exist, we copy the source's parent and let the copier package create
// the destination via the Rename option. // the destination via the Rename option.
if destContainerInfoErr != nil && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") { if destResolvedToParentDir && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
sourceContainerTarget = filepath.Dir(sourceContainerTarget) sourceContainerTarget = filepath.Dir(sourceContainerTarget)
} }
@ -202,7 +176,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
defer reader.Close() defer reader.Close()
copyOptions := entities.CopyOptions{Chown: chown} copyOptions := entities.CopyOptions{Chown: chown}
if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destContainerInfoErr != nil { if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destResolvedToParentDir {
// If we're having a file-to-file copy, make sure to // If we're having a file-to-file copy, make sure to
// rename accordingly. // rename accordingly.
copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName} copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName}
@ -239,6 +213,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
} }
var hostBaseName string var hostBaseName string
var resolvedToHostParentDir bool
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath) hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
if hostInfoErr != nil { if hostInfoErr != nil {
if strings.HasSuffix(hostPath, "/") { if strings.HasSuffix(hostPath, "/") {
@ -254,6 +229,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// it'll be created while copying. Hence, we use it as the // it'll be created while copying. Hence, we use it as the
// base path. // base path.
hostBaseName = filepath.Base(hostPath) hostBaseName = filepath.Base(hostPath)
resolvedToHostParentDir = true
} else { } else {
// If the specified path exists on the host, we must use its // If the specified path exists on the host, we must use its
// base path as it may have changed due to symlink evaluations. // base path as it may have changed due to symlink evaluations.
@ -281,7 +257,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// we copy the source's parent and let the copier package create the // we copy the source's parent and let the copier package create the
// destination via the Rename option. // destination via the Rename option.
containerTarget := containerInfo.LinkTarget containerTarget := containerInfo.LinkTarget
if hostInfoErr != nil && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") { if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
containerTarget = filepath.Dir(containerTarget) containerTarget = filepath.Dir(containerTarget)
} }
@ -322,7 +298,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
ChownFiles: &idPair, ChownFiles: &idPair,
IgnoreDevices: true, IgnoreDevices: true,
} }
if (!containerInfo.IsDir && !hostInfo.IsDir) || hostInfoErr != nil { if (!containerInfo.IsDir && !hostInfo.IsDir) || resolvedToHostParentDir {
// If we're having a file-to-file copy, make sure to // If we're having a file-to-file copy, make sure to
// rename accordingly. // rename accordingly.
putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName} putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName}
@ -369,42 +345,9 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return errors.Wrapf(err, "%q could not be found on the host", hostPath) return errors.Wrapf(err, "%q could not be found on the host", hostPath)
} }
// If the path on the container does not exist. We need to make sure containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin)
// that it's parent directory exists. The destination may be created
// while copying.
var containerBaseName string
containerInfo, containerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
if containerInfoErr != nil {
if strings.HasSuffix(containerPath, "/") {
return errors.Wrapf(containerInfoErr, "%q could not be found on container %s", containerPath, container)
}
if isStdin {
return errors.New("destination must be a directory when copying from stdin")
}
// NOTE: containerInfo may actually be set. That happens when
// the container path is a symlink into nirvana. In that case,
// we must use the symlinked path instead.
path := containerPath
if containerInfo != nil {
containerBaseName = filepath.Base(containerInfo.LinkTarget)
path = containerInfo.LinkTarget
} else {
containerBaseName = filepath.Base(containerPath)
}
parentDir, err := containerParentDir(container, path)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container) return err
}
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
if err != nil {
return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
}
} else {
// If the specified path exists on the container, we must use
// its base path as it may have changed due to symlink
// evaluations.
containerBaseName = filepath.Base(containerInfo.LinkTarget)
} }
// If we copy a directory via the "." notation and the container path // If we copy a directory via the "." notation and the container path
@ -416,7 +359,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// exist, we copy the source's parent and let the copier package create // exist, we copy the source's parent and let the copier package create
// the destination via the Rename option. // the destination via the Rename option.
hostTarget := hostInfo.LinkTarget hostTarget := hostInfo.LinkTarget
if containerInfoErr != nil && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") { if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
hostTarget = filepath.Dir(hostTarget) hostTarget = filepath.Dir(hostTarget)
} }
@ -468,7 +411,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// copy the base directory. // copy the base directory.
KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".", KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".",
} }
if (!hostInfo.IsDir && !containerInfo.IsDir) || containerInfoErr != nil { if (!hostInfo.IsDir && !containerInfo.IsDir) || containerResolvedToParentDir {
// If we're having a file-to-file copy, make sure to // If we're having a file-to-file copy, make sure to
// rename accordingly. // rename accordingly.
getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName} getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName}
@ -499,6 +442,52 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return doCopy(hostCopy, containerCopy) return doCopy(hostCopy, containerCopy)
} }
// resolvePathOnDestinationContainer resolves the specified path on the
// container. If the path does not exist, it attempts to use the parent
// directory.
func resolvePathOnDestinationContainer(container string, containerPath string, isStdin bool) (baseName string, containerInfo *entities.ContainerStatReport, resolvedToParentDir bool, err error) {
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
if err == nil {
baseName = filepath.Base(containerInfo.LinkTarget)
return
}
if strings.HasSuffix(containerPath, "/") {
err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
return
}
if isStdin {
err = errors.New("destination must be a directory when copying from stdin")
return
}
// NOTE: containerInfo may actually be set. That happens when
// the container path is a symlink into nirvana. In that case,
// we must use the symlinked path instead.
path := containerPath
if containerInfo != nil {
baseName = filepath.Base(containerInfo.LinkTarget)
path = containerInfo.LinkTarget
} else {
baseName = filepath.Base(containerPath)
}
parentDir, err := containerParentDir(container, path)
if err != nil {
err = errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
return
}
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
if err != nil {
err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
return
}
resolvedToParentDir = true
return baseName, containerInfo, resolvedToParentDir, nil
}
// containerParentDir returns the parent directory of the specified path on the // containerParentDir returns the parent directory of the specified path on the
// container. If the path is relative, it will be resolved relative to the // container. If the path is relative, it will be resolved relative to the
// container's working directory (or "/" if the work dir isn't set). // container's working directory (or "/" if the work dir isn't set).