forked from toolshed/abra
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			upgrade-cl
			...
			cp-enhance
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 296b2e0312 | 
							
								
								
									
										372
									
								
								cli/app/cp.go
									
									
									
									
									
								
							
							
						
						
									
										372
									
								
								cli/app/cp.go
									
									
									
									
									
								
							@ -2,19 +2,24 @@ package app
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"coopcloud.tech/abra/cli/internal"
 | 
						"coopcloud.tech/abra/cli/internal"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
						"coopcloud.tech/abra/pkg/autocomplete"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/client"
 | 
						"coopcloud.tech/abra/pkg/client"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/config"
 | 
						containerPkg "coopcloud.tech/abra/pkg/container"
 | 
				
			||||||
	"coopcloud.tech/abra/pkg/container"
 | 
					 | 
				
			||||||
	"coopcloud.tech/abra/pkg/formatter"
 | 
						"coopcloud.tech/abra/pkg/formatter"
 | 
				
			||||||
 | 
						"coopcloud.tech/abra/pkg/upstream/container"
 | 
				
			||||||
 | 
						"github.com/docker/cli/cli/command"
 | 
				
			||||||
	"github.com/docker/docker/api/types"
 | 
						"github.com/docker/docker/api/types"
 | 
				
			||||||
	"github.com/docker/docker/api/types/filters"
 | 
					 | 
				
			||||||
	dockerClient "github.com/docker/docker/client"
 | 
						dockerClient "github.com/docker/docker/client"
 | 
				
			||||||
 | 
						"github.com/docker/docker/errdefs"
 | 
				
			||||||
	"github.com/docker/docker/pkg/archive"
 | 
						"github.com/docker/docker/pkg/archive"
 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
	"github.com/urfave/cli"
 | 
						"github.com/urfave/cli"
 | 
				
			||||||
@ -49,46 +54,14 @@ And if you want to copy that file back to your current working directory locally
 | 
				
			|||||||
		dst := c.Args().Get(2)
 | 
							dst := c.Args().Get(2)
 | 
				
			||||||
		if src == "" {
 | 
							if src == "" {
 | 
				
			||||||
			logrus.Fatal("missing <src> argument")
 | 
								logrus.Fatal("missing <src> argument")
 | 
				
			||||||
		} else if dst == "" {
 | 
							}
 | 
				
			||||||
 | 
							if dst == "" {
 | 
				
			||||||
			logrus.Fatal("missing <dest> argument")
 | 
								logrus.Fatal("missing <dest> argument")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		parsedSrc := strings.SplitN(src, ":", 2)
 | 
							srcPath, dstPath, service, toContainer, err := parseSrcAndDst(src, dst)
 | 
				
			||||||
		parsedDst := strings.SplitN(dst, ":", 2)
 | 
							if err != nil {
 | 
				
			||||||
		errorMsg := "one of <src>/<dest> arguments must take $SERVICE:$PATH form"
 | 
								logrus.Fatal(err)
 | 
				
			||||||
		if len(parsedSrc) == 2 && len(parsedDst) == 2 {
 | 
					 | 
				
			||||||
			logrus.Fatal(errorMsg)
 | 
					 | 
				
			||||||
		} else if len(parsedSrc) != 2 {
 | 
					 | 
				
			||||||
			if len(parsedDst) != 2 {
 | 
					 | 
				
			||||||
				logrus.Fatal(errorMsg)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		} else if len(parsedDst) != 2 {
 | 
					 | 
				
			||||||
			if len(parsedSrc) != 2 {
 | 
					 | 
				
			||||||
				logrus.Fatal(errorMsg)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var service string
 | 
					 | 
				
			||||||
		var srcPath string
 | 
					 | 
				
			||||||
		var dstPath string
 | 
					 | 
				
			||||||
		isToContainer := false // <container:src> <dst>
 | 
					 | 
				
			||||||
		if len(parsedSrc) == 2 {
 | 
					 | 
				
			||||||
			service = parsedSrc[0]
 | 
					 | 
				
			||||||
			srcPath = parsedSrc[1]
 | 
					 | 
				
			||||||
			dstPath = dst
 | 
					 | 
				
			||||||
			logrus.Debugf("assuming transfer is coming FROM the container")
 | 
					 | 
				
			||||||
		} else if len(parsedDst) == 2 {
 | 
					 | 
				
			||||||
			service = parsedDst[0]
 | 
					 | 
				
			||||||
			dstPath = parsedDst[1]
 | 
					 | 
				
			||||||
			srcPath = src
 | 
					 | 
				
			||||||
			isToContainer = true // <src> <container:dst>
 | 
					 | 
				
			||||||
			logrus.Debugf("assuming transfer is going TO the container")
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if isToContainer {
 | 
					 | 
				
			||||||
			if _, err := os.Stat(srcPath); os.IsNotExist(err) {
 | 
					 | 
				
			||||||
				logrus.Fatalf("%s does not exist locally?", srcPath)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cl, err := client.New(app.Server)
 | 
							cl, err := client.New(app.Server)
 | 
				
			||||||
@ -96,7 +69,18 @@ And if you want to copy that file back to your current working directory locally
 | 
				
			|||||||
			logrus.Fatal(err)
 | 
								logrus.Fatal(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := configureAndCp(c, cl, app, srcPath, dstPath, service, isToContainer); err != nil {
 | 
							container, err := containerPkg.GetContainerFromStackAndService(cl, app.StackName(), service)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								logrus.Fatal(err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							logrus.Debugf("retrieved %s as target container on %s", formatter.ShortenID(container.ID), app.Server)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if toContainer {
 | 
				
			||||||
 | 
								err = copyToContainer(cl, container.ID, srcPath, dstPath)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								err = copyFromContainer(cl, container.ID, srcPath, dstPath)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
			logrus.Fatal(err)
 | 
								logrus.Fatal(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -104,46 +88,292 @@ And if you want to copy that file back to your current working directory locally
 | 
				
			|||||||
	},
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func configureAndCp(
 | 
					var errServiceMissing = errors.New("one of <src>/<dest> arguments must take $SERVICE:$PATH form")
 | 
				
			||||||
	c *cli.Context,
 | 
					 | 
				
			||||||
	cl *dockerClient.Client,
 | 
					 | 
				
			||||||
	app config.App,
 | 
					 | 
				
			||||||
	srcPath string,
 | 
					 | 
				
			||||||
	dstPath string,
 | 
					 | 
				
			||||||
	service string,
 | 
					 | 
				
			||||||
	isToContainer bool) error {
 | 
					 | 
				
			||||||
	filters := filters.NewArgs()
 | 
					 | 
				
			||||||
	filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), service))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	container, err := container.GetContainer(context.Background(), cl, filters, internal.NoInput)
 | 
					// parseSrcAndDst parses src and dest string. One of src or dst must be of the form $SERVICE:$PATH
 | 
				
			||||||
 | 
					func parseSrcAndDst(src, dst string) (srcPath string, dstPath string, service string, toContainer bool, err error) {
 | 
				
			||||||
 | 
						parsedSrc := strings.SplitN(src, ":", 2)
 | 
				
			||||||
 | 
						parsedDst := strings.SplitN(dst, ":", 2)
 | 
				
			||||||
 | 
						if len(parsedSrc)+len(parsedDst) != 3 {
 | 
				
			||||||
 | 
							return "", "", "", false, errServiceMissing
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(parsedSrc) == 2 {
 | 
				
			||||||
 | 
							return parsedSrc[1], dst, parsedSrc[0], false, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(parsedDst) == 2 {
 | 
				
			||||||
 | 
							return src, parsedDst[1], parsedDst[0], true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return "", "", "", false, errServiceMissing
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copyToContainer copies a file or directory from the local file system to the container.
 | 
				
			||||||
 | 
					// See the possible copy modes and their documentation.
 | 
				
			||||||
 | 
					func copyToContainer(cl *dockerClient.Client, containerID, srcPath, dstPath string) error {
 | 
				
			||||||
 | 
						srcStat, err := os.Stat(srcPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		logrus.Fatal(err)
 | 
							return fmt.Errorf("local %s ", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	logrus.Debugf("retrieved %s as target container on %s", formatter.ShortenID(container.ID), app.Server)
 | 
						dstStat, err := cl.ContainerStatPath(context.Background(), containerID, dstPath)
 | 
				
			||||||
 | 
						dstExists := true
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if errdefs.IsNotFound(err) {
 | 
				
			||||||
 | 
								dstExists = false
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("remote path: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if isToContainer {
 | 
						mode, err := copyMode(srcPath, dstPath, srcStat.Mode(), dstStat.Mode, dstExists)
 | 
				
			||||||
		toTarOpts := &archive.TarOptions{NoOverwriteDirNonDir: true, Compression: archive.Gzip}
 | 
						if err != nil {
 | 
				
			||||||
		content, err := archive.TarWithOptions(srcPath, toTarOpts)
 | 
							return err
 | 
				
			||||||
		if err != nil {
 | 
						}
 | 
				
			||||||
			logrus.Fatal(err)
 | 
						movePath := ""
 | 
				
			||||||
		}
 | 
						switch mode {
 | 
				
			||||||
 | 
						case CopyModeDirToDir:
 | 
				
			||||||
 | 
							// Add the src directory to the destination path
 | 
				
			||||||
 | 
							_, srcDir := path.Split(srcPath)
 | 
				
			||||||
 | 
							dstPath = path.Join(dstPath, srcDir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
 | 
							// Make sure the dst directory exits.
 | 
				
			||||||
		if err := cl.CopyToContainer(context.Background(), container.ID, dstPath, content, copyOpts); err != nil {
 | 
							dcli, err := command.NewDockerCli()
 | 
				
			||||||
			logrus.Fatal(err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		content, _, err := cl.CopyFromContainer(context.Background(), container.ID, srcPath)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			logrus.Fatal(err)
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		defer content.Close()
 | 
							if err := container.RunExec(dcli, cl, containerID, &types.ExecConfig{
 | 
				
			||||||
		fromTarOpts := &archive.TarOptions{NoOverwriteDirNonDir: true, Compression: archive.Gzip}
 | 
								AttachStderr: true,
 | 
				
			||||||
		if err := archive.Untar(content, dstPath, fromTarOpts); err != nil {
 | 
								AttachStdin:  true,
 | 
				
			||||||
			logrus.Fatal(err)
 | 
								AttachStdout: true,
 | 
				
			||||||
 | 
								Cmd:          []string{"mkdir", "-p", dstPath},
 | 
				
			||||||
 | 
								Detach:       false,
 | 
				
			||||||
 | 
								Tty:          true,
 | 
				
			||||||
 | 
							}); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("create remote directory: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case CopyModeFileToFile:
 | 
				
			||||||
 | 
							// Remove the file component from the path, since docker can only copy
 | 
				
			||||||
 | 
							// to a directory.
 | 
				
			||||||
 | 
							dstPath, _ = path.Split(dstPath)
 | 
				
			||||||
 | 
						case CopyModeFileToFileRename:
 | 
				
			||||||
 | 
							// Copy the file to the temp directory and move it to its dstPath
 | 
				
			||||||
 | 
							// afterwards.
 | 
				
			||||||
 | 
							movePath = dstPath
 | 
				
			||||||
 | 
							dstPath = "/tmp"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						toTarOpts := &archive.TarOptions{IncludeSourceDir: true, NoOverwriteDirNonDir: true, Compression: archive.Gzip}
 | 
				
			||||||
 | 
						content, err := archive.TarWithOptions(srcPath, toTarOpts)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logrus.Debugf("copy %s from local to %s on container", srcPath, dstPath)
 | 
				
			||||||
 | 
						copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
 | 
				
			||||||
 | 
						if err := cl.CopyToContainer(context.Background(), containerID, dstPath, content, copyOpts); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if movePath != "" {
 | 
				
			||||||
 | 
							_, srcFile := path.Split(srcPath)
 | 
				
			||||||
 | 
							dcli, err := command.NewDockerCli()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err := container.RunExec(dcli, cl, containerID, &types.ExecConfig{
 | 
				
			||||||
 | 
								AttachStderr: true,
 | 
				
			||||||
 | 
								AttachStdin:  true,
 | 
				
			||||||
 | 
								AttachStdout: true,
 | 
				
			||||||
 | 
								Cmd:          []string{"mv", path.Join("/tmp", srcFile), movePath},
 | 
				
			||||||
 | 
								Detach:       false,
 | 
				
			||||||
 | 
								Tty:          true,
 | 
				
			||||||
 | 
							}); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("create remote directory: %s", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copyFromContainer copies a file or directory from the given container to the local file system.
 | 
				
			||||||
 | 
					// See the possible copy modes and their documentation.
 | 
				
			||||||
 | 
					func copyFromContainer(cl *dockerClient.Client, containerID, srcPath, dstPath string) error {
 | 
				
			||||||
 | 
						srcStat, err := cl.ContainerStatPath(context.Background(), containerID, srcPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if errdefs.IsNotFound(err) {
 | 
				
			||||||
 | 
								return fmt.Errorf("remote: %s does not exist", srcPath)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("remote path: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dstStat, err := os.Stat(dstPath)
 | 
				
			||||||
 | 
						dstExists := true
 | 
				
			||||||
 | 
						var dstMode os.FileMode
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if os.IsNotExist(err) {
 | 
				
			||||||
 | 
								dstExists = false
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return fmt.Errorf("remote path: %s", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							dstMode = dstStat.Mode()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mode, err := copyMode(srcPath, dstPath, srcStat.Mode, dstMode, dstExists)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						moveDstDir := ""
 | 
				
			||||||
 | 
						moveDstFile := ""
 | 
				
			||||||
 | 
						switch mode {
 | 
				
			||||||
 | 
						case CopyModeFileToFile:
 | 
				
			||||||
 | 
							// Remove the file component from the path, since docker can only copy
 | 
				
			||||||
 | 
							// to a directory.
 | 
				
			||||||
 | 
							dstPath, _ = path.Split(dstPath)
 | 
				
			||||||
 | 
						case CopyModeFileToFileRename:
 | 
				
			||||||
 | 
							// Copy the file to the temp directory and move it to its dstPath
 | 
				
			||||||
 | 
							// afterwards.
 | 
				
			||||||
 | 
							moveDstFile = dstPath
 | 
				
			||||||
 | 
							dstPath = "/tmp"
 | 
				
			||||||
 | 
						case CopyModeFilesToDir:
 | 
				
			||||||
 | 
							// Copy the directory to the temp directory and move it to its
 | 
				
			||||||
 | 
							// dstPath afterwards.
 | 
				
			||||||
 | 
							moveDstDir = path.Join(dstPath, "/")
 | 
				
			||||||
 | 
							dstPath = "/tmp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Make sure the temp directory always gets removed
 | 
				
			||||||
 | 
							defer os.Remove(path.Join("/tmp"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						content, _, err := cl.CopyFromContainer(context.Background(), containerID, srcPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("copy: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer content.Close()
 | 
				
			||||||
 | 
						if err := archive.Untar(content, dstPath, &archive.TarOptions{
 | 
				
			||||||
 | 
							NoOverwriteDirNonDir: true,
 | 
				
			||||||
 | 
							Compression:          archive.Gzip,
 | 
				
			||||||
 | 
							NoLchown:             true,
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("untar: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if moveDstFile != "" {
 | 
				
			||||||
 | 
							_, srcFile := path.Split(strings.TrimSuffix(srcPath, "/"))
 | 
				
			||||||
 | 
							if err := moveFile(path.Join("/tmp", srcFile), moveDstFile); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if moveDstDir != "" {
 | 
				
			||||||
 | 
							_, srcDir := path.Split(strings.TrimSuffix(srcPath, "/"))
 | 
				
			||||||
 | 
							if err := moveDir(path.Join("/tmp", srcDir), moveDstDir); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var (
 | 
				
			||||||
 | 
						ErrCopyDirToFile  = fmt.Errorf("can't copy dir to file")
 | 
				
			||||||
 | 
						ErrDstDirNotExist = fmt.Errorf("destination directory does not exist")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type CopyMode int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// Copy a src file to a dest file. The src and dest file names are the same.
 | 
				
			||||||
 | 
						//  <dir_src>/<file> + <dir_dst>/<file> -> <dir_dst>/<file>
 | 
				
			||||||
 | 
						CopyModeFileToFile = CopyMode(iota)
 | 
				
			||||||
 | 
						// Copy a src file to a dest file. The src and dest file names are  not the same.
 | 
				
			||||||
 | 
						//  <dir_src>/<file_src> + <dir_dst>/<file_dst> -> <dir_dst>/<file_dst>
 | 
				
			||||||
 | 
						CopyModeFileToFileRename
 | 
				
			||||||
 | 
						// Copy a src file to dest directory. The dest file gets created in the dest
 | 
				
			||||||
 | 
						// folder with the src filename.
 | 
				
			||||||
 | 
						//  <dir_src>/<file> + <dir_dst> -> <dir_dst>/<file>
 | 
				
			||||||
 | 
						CopyModeFileToDir
 | 
				
			||||||
 | 
						// Copy a src directory to dest directory.
 | 
				
			||||||
 | 
						//  <dir_src> + <dir_dst> -> <dir_dst>/<dir_src>
 | 
				
			||||||
 | 
						CopyModeDirToDir
 | 
				
			||||||
 | 
						// Copy all files in the src directory to the dest directory. This works recursively.
 | 
				
			||||||
 | 
						//  <dir_src>/ + <dir_dst> -> <dir_dst>/<files_from_dir_src>
 | 
				
			||||||
 | 
						CopyModeFilesToDir
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copyMode takes a src and dest path and file mode to determine the copy mode.
 | 
				
			||||||
 | 
					// See the possible copy modes and their documentation.
 | 
				
			||||||
 | 
					func copyMode(srcPath, dstPath string, srcMode os.FileMode, dstMode os.FileMode, dstExists bool) (CopyMode, error) {
 | 
				
			||||||
 | 
						_, srcFile := path.Split(srcPath)
 | 
				
			||||||
 | 
						_, dstFile := path.Split(dstPath)
 | 
				
			||||||
 | 
						if srcMode.IsDir() {
 | 
				
			||||||
 | 
							if !dstExists {
 | 
				
			||||||
 | 
								return -1, ErrDstDirNotExist
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if dstMode.IsDir() {
 | 
				
			||||||
 | 
								if strings.HasSuffix(srcPath, "/") {
 | 
				
			||||||
 | 
									return CopyModeFilesToDir, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return CopyModeDirToDir, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return -1, ErrCopyDirToFile
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if dstMode.IsDir() {
 | 
				
			||||||
 | 
							return CopyModeFileToDir, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if srcFile != dstFile {
 | 
				
			||||||
 | 
							return CopyModeFileToFileRename, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CopyModeFileToFile, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// moveDir moves all files from a source path to the destination path recursively.
 | 
				
			||||||
 | 
					func moveDir(sourcePath, destPath string) error {
 | 
				
			||||||
 | 
						return filepath.Walk(sourcePath, func(p string, info os.FileInfo, err error) error {
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							newPath := path.Join(destPath, strings.TrimPrefix(p, sourcePath))
 | 
				
			||||||
 | 
							if info.IsDir() {
 | 
				
			||||||
 | 
								err := os.Mkdir(newPath, info.Mode())
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									if os.IsExist(err) {
 | 
				
			||||||
 | 
										return nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if info.Mode().IsRegular() {
 | 
				
			||||||
 | 
								return moveFile(p, newPath)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// moveFile moves a file from a source path to a destination path.
 | 
				
			||||||
 | 
					func moveFile(sourcePath, destPath string) error {
 | 
				
			||||||
 | 
						inputFile, err := os.Open(sourcePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						outputFile, err := os.Create(destPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							inputFile.Close()
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer outputFile.Close()
 | 
				
			||||||
 | 
						_, err = io.Copy(outputFile, inputFile)
 | 
				
			||||||
 | 
						inputFile.Close()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Remove file after succesfull copy.
 | 
				
			||||||
 | 
						err = os.Remove(sourcePath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										113
									
								
								cli/app/cp_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								cli/app/cp_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					package app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestParse(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							src         string
 | 
				
			||||||
 | 
							dst         string
 | 
				
			||||||
 | 
							srcPath     string
 | 
				
			||||||
 | 
							dstPath     string
 | 
				
			||||||
 | 
							service     string
 | 
				
			||||||
 | 
							toContainer bool
 | 
				
			||||||
 | 
							err         error
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{src: "foo", dst: "bar", err: errServiceMissing},
 | 
				
			||||||
 | 
							{src: "app:foo", dst: "app:bar", err: errServiceMissing},
 | 
				
			||||||
 | 
							{src: "app:foo", dst: "bar", srcPath: "foo", dstPath: "bar", service: "app", toContainer: false},
 | 
				
			||||||
 | 
							{src: "foo", dst: "app:bar", srcPath: "foo", dstPath: "bar", service: "app", toContainer: true},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, tc := range tests {
 | 
				
			||||||
 | 
							srcPath, dstPath, service, toContainer, err := parseSrcAndDst(tc.src, tc.dst)
 | 
				
			||||||
 | 
							if srcPath != tc.srcPath {
 | 
				
			||||||
 | 
								t.Errorf("[%d] srcPath: want (%s), got(%s)", i, tc.srcPath, srcPath)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if dstPath != tc.dstPath {
 | 
				
			||||||
 | 
								t.Errorf("[%d] dstPath: want (%s), got(%s)", i, tc.dstPath, dstPath)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if service != tc.service {
 | 
				
			||||||
 | 
								t.Errorf("[%d] service: want (%s), got(%s)", i, tc.service, service)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if toContainer != tc.toContainer {
 | 
				
			||||||
 | 
								t.Errorf("[%d] toConainer: want (%t), got(%t)", i, tc.toContainer, toContainer)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err == nil && tc.err != nil && err.Error() != tc.err.Error() {
 | 
				
			||||||
 | 
								t.Errorf("[%d] err: want (%s), got(%s)", i, tc.err, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestCopyMode(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							srcPath   string
 | 
				
			||||||
 | 
							dstPath   string
 | 
				
			||||||
 | 
							srcMode   os.FileMode
 | 
				
			||||||
 | 
							dstMode   os.FileMode
 | 
				
			||||||
 | 
							dstExists bool
 | 
				
			||||||
 | 
							mode      CopyMode
 | 
				
			||||||
 | 
							err       error
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo.txt",
 | 
				
			||||||
 | 
								dstPath:   "foo.txt",
 | 
				
			||||||
 | 
								srcMode:   os.ModePerm,
 | 
				
			||||||
 | 
								dstMode:   os.ModePerm,
 | 
				
			||||||
 | 
								dstExists: true,
 | 
				
			||||||
 | 
								mode:      CopyModeFileToFile,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo.txt",
 | 
				
			||||||
 | 
								dstPath:   "bar.txt",
 | 
				
			||||||
 | 
								srcMode:   os.ModePerm,
 | 
				
			||||||
 | 
								dstExists: true,
 | 
				
			||||||
 | 
								mode:      CopyModeFileToFileRename,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo",
 | 
				
			||||||
 | 
								dstPath:   "foo",
 | 
				
			||||||
 | 
								srcMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstExists: true,
 | 
				
			||||||
 | 
								mode:      CopyModeDirToDir,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo/",
 | 
				
			||||||
 | 
								dstPath:   "foo",
 | 
				
			||||||
 | 
								srcMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstExists: true,
 | 
				
			||||||
 | 
								mode:      CopyModeFilesToDir,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo",
 | 
				
			||||||
 | 
								dstPath:   "foo",
 | 
				
			||||||
 | 
								srcMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstExists: false,
 | 
				
			||||||
 | 
								mode:      -1,
 | 
				
			||||||
 | 
								err:       ErrDstDirNotExist,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								srcPath:   "foo",
 | 
				
			||||||
 | 
								dstPath:   "foo",
 | 
				
			||||||
 | 
								srcMode:   os.ModeDir,
 | 
				
			||||||
 | 
								dstMode:   os.ModePerm,
 | 
				
			||||||
 | 
								dstExists: true,
 | 
				
			||||||
 | 
								mode:      -1,
 | 
				
			||||||
 | 
								err:       ErrCopyDirToFile,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i, tc := range tests {
 | 
				
			||||||
 | 
							mode, err := copyMode(tc.srcPath, tc.dstPath, tc.srcMode, tc.dstMode, tc.dstExists)
 | 
				
			||||||
 | 
							if mode != tc.mode {
 | 
				
			||||||
 | 
								t.Errorf("[%d] mode: want (%d), got(%d)", i, tc.mode, mode)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != tc.err {
 | 
				
			||||||
 | 
								t.Errorf("[%d] err: want (%s), got(%s)", i, tc.err, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.sum
									
									
									
									
									
								
							@ -1315,6 +1315,7 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			|||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
					golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
 | 
					golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
				
			||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
 | 
					golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
 | 
				
			||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
					golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
				
			||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
					golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
				
			||||||
 | 
				
			|||||||
@ -68,3 +68,15 @@ func GetContainer(c context.Context, cl *client.Client, filters filters.Args, no
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return containers[0], nil
 | 
						return containers[0], nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetContainerFromStackAndService retrieves the container for the given stack and service.
 | 
				
			||||||
 | 
					func GetContainerFromStackAndService(cl *client.Client, stack, service string) (types.Container, error) {
 | 
				
			||||||
 | 
						filters := filters.NewArgs()
 | 
				
			||||||
 | 
						filters.Add("name", fmt.Sprintf("^%s_%s", stack, service))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						container, err := GetContainer(context.Background(), cl, filters, true)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return types.Container{}, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return container, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,9 +5,11 @@ setup_file(){
 | 
				
			|||||||
  _common_setup
 | 
					  _common_setup
 | 
				
			||||||
  _add_server
 | 
					  _add_server
 | 
				
			||||||
  _new_app
 | 
					  _new_app
 | 
				
			||||||
 | 
					  _deploy_app
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
teardown_file(){
 | 
					teardown_file(){
 | 
				
			||||||
 | 
					  _undeploy_app
 | 
				
			||||||
  _rm_app
 | 
					  _rm_app
 | 
				
			||||||
  _rm_server
 | 
					  _rm_server
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -17,11 +19,29 @@ setup(){
 | 
				
			|||||||
  _common_setup
 | 
					  _common_setup
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
teardown(){
 | 
					_mkfile() {
 | 
				
			||||||
  # https://github.com/bats-core/bats-core/issues/383#issuecomment-738628888
 | 
					  run bash -c "echo $2 > $1"
 | 
				
			||||||
  if [[ -z "${BATS_TEST_COMPLETED}" ]]; then
 | 
					  assert_success
 | 
				
			||||||
    _undeploy_app
 | 
					}
 | 
				
			||||||
  fi
 | 
					
 | 
				
			||||||
 | 
					_mkfile_remote() {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app "bash -c \"echo $2 > $1\""
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_mkdir() {
 | 
				
			||||||
 | 
					  run bash -c "mkdir -p $1"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_rm() {
 | 
				
			||||||
 | 
					  run rm -rf "$1"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_rm_remote() {
 | 
				
			||||||
 | 
					  run "$ABRA" app run "$TEST_APP_DOMAIN" app rm -rf "$1"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@test "validate app argument" {
 | 
					@test "validate app argument" {
 | 
				
			||||||
@ -54,68 +74,120 @@ teardown(){
 | 
				
			|||||||
  assert_output --partial 'arguments must take $SERVICE:$PATH form'
 | 
					  assert_output --partial 'arguments must take $SERVICE:$PATH form'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@test "detect 'coming FROM' syntax" {
 | 
					 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" app:/myfile.txt . --debug
 | 
					 | 
				
			||||||
  assert_failure
 | 
					 | 
				
			||||||
  assert_output --partial 'coming FROM the container'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@test "detect 'going TO' syntax" {
 | 
					 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" myfile.txt app:/somewhere --debug
 | 
					 | 
				
			||||||
  assert_failure
 | 
					 | 
				
			||||||
  assert_output --partial 'going TO the container'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@test "error if local file missing" {
 | 
					@test "error if local file missing" {
 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" myfile.txt app:/somewhere
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" thisfileshouldnotexist.txt app:/somewhere
 | 
				
			||||||
  assert_failure
 | 
					  assert_failure
 | 
				
			||||||
  assert_output --partial 'myfile.txt does not exist locally?'
 | 
					  assert_output --partial 'local stat thisfileshouldnotexist.txt: no such file or directory'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# bats test_tags=slow
 | 
					# bats test_tags=slow
 | 
				
			||||||
@test "error if service doesn't exist" {
 | 
					@test "error if service doesn't exist" {
 | 
				
			||||||
  _deploy_app
 | 
					  _mkfile "$BATS_TMPDIR/myfile.txt" "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run bash -c "echo foo >> $BATS_TMPDIR/myfile.txt"
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" doesnt_exist:/ --debug
 | 
				
			||||||
  assert_success
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" doesnt_exist:/
 | 
					 | 
				
			||||||
  assert_failure
 | 
					  assert_failure
 | 
				
			||||||
  assert_output --partial 'no containers matching'
 | 
					  assert_output --partial 'no containers matching'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run rm -rf "$BATS_TMPDIR/myfile.txt"
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
  assert_success
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  _undeploy_app
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# bats test_tags=slow
 | 
					# bats test_tags=slow
 | 
				
			||||||
@test "copy to container" {
 | 
					@test "copy local file to container directory" {
 | 
				
			||||||
  _deploy_app
 | 
					  _mkfile "$BATS_TMPDIR/myfile.txt" "foo"
 | 
				
			||||||
 | 
					 | 
				
			||||||
  run bash -c "echo foo >> $BATS_TMPDIR/myfile.txt"
 | 
					 | 
				
			||||||
  assert_success
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run rm -rf "$BATS_TMPDIR/myfile.txt"
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app cat /etc/myfile.txt
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _undeploy_app
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# bats test_tags=slow
 | 
					# bats test_tags=slow
 | 
				
			||||||
@test "copy from container" {
 | 
					@test "copy local file to container file (and override on remote)" {
 | 
				
			||||||
  _deploy_app
 | 
					  _mkfile "$BATS_TMPDIR/myfile.txt" "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run bash -c "echo foo >> $BATS_TMPDIR/myfile.txt"
 | 
					  # create
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc/myfile.txt
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app cat /etc/myfile.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _mkfile "$BATS_TMPDIR/myfile.txt" "bar"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # override
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc/myfile.txt
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run rm -rf "$BATS_TMPDIR/myfile.txt"
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app cat /etc/myfile.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "bar"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy local file to container file (and rename)" {
 | 
				
			||||||
 | 
					  _mkfile "$BATS_TMPDIR/myfile.txt" "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # rename
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/myfile.txt" app:/etc/myfile2.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app cat /etc/myfile2.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile2.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy local directory to container directory (and creates missing directory)" {
 | 
				
			||||||
 | 
					  _mkdir "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _mkfile "$BATS_TMPDIR/mydir/myfile.txt" "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/mydir" app:/etc
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app ls /etc/mydir
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "myfile.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/mydir"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy local files to container directory" {
 | 
				
			||||||
 | 
					  _mkdir "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _mkfile "$BATS_TMPDIR/mydir/myfile.txt" "foo"
 | 
				
			||||||
 | 
					  _mkfile "$BATS_TMPDIR/mydir/myfile2.txt" "foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" "$BATS_TMPDIR/mydir/" app:/etc
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app ls /etc/myfile.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "myfile.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app ls /etc/myfile2.txt
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_output --partial "myfile2.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile*"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy container file to local directory" {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo foo > /etc/myfile.txt"
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc/myfile.txt "$BATS_TMPDIR"
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc/myfile.txt "$BATS_TMPDIR"
 | 
				
			||||||
@ -123,8 +195,76 @@ teardown(){
 | 
				
			|||||||
  assert_exists "$BATS_TMPDIR/myfile.txt"
 | 
					  assert_exists "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
  assert bash -c "cat $BATS_TMPDIR/myfile.txt | grep -q foo"
 | 
					  assert bash -c "cat $BATS_TMPDIR/myfile.txt | grep -q foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  run rm -rf "$BATS_TMPDIR/myfile.txt"
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy container file to local file" {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo foo > /etc/myfile.txt"
 | 
				
			||||||
  assert_success
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _undeploy_app
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc/myfile.txt "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  assert bash -c "cat $BATS_TMPDIR/myfile.txt | grep -q foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy container file to local file and rename" {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo foo > /etc/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc/myfile.txt "$BATS_TMPDIR/myfile2.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/myfile2.txt"
 | 
				
			||||||
 | 
					  assert bash -c "cat $BATS_TMPDIR/myfile2.txt | grep -q foo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/myfile2.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy container directory to local directory" {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo foo > /etc/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo bar > /etc/myfile2.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mkdir "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/mydir/etc/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/mydir/etc/myfile2.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile2.txt"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# bats test_tags=slow
 | 
				
			||||||
 | 
					@test "copy container files to local directory" {
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo foo > /etc/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app run "$TEST_APP_DOMAIN" app bash -c "echo bar > /etc/myfile2.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mkdir "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run $ABRA app cp "$TEST_APP_DOMAIN" app:/etc/ "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/mydir/myfile.txt"
 | 
				
			||||||
 | 
					  assert_success
 | 
				
			||||||
 | 
					  assert_exists "$BATS_TMPDIR/mydir/myfile2.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rm "$BATS_TMPDIR/mydir"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile.txt"
 | 
				
			||||||
 | 
					  _rm_remote "/etc/myfile2.txt"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user