forked from toolshed/abra
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package app
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"coopcloud.tech/abra/cli/internal"
 | 
						|
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
						|
	"coopcloud.tech/abra/pkg/client"
 | 
						|
	"coopcloud.tech/abra/pkg/config"
 | 
						|
	"coopcloud.tech/abra/pkg/container"
 | 
						|
	"coopcloud.tech/abra/pkg/formatter"
 | 
						|
	"coopcloud.tech/abra/pkg/runtime"
 | 
						|
	"github.com/docker/docker/api/types"
 | 
						|
	"github.com/docker/docker/api/types/filters"
 | 
						|
	dockerClient "github.com/docker/docker/client"
 | 
						|
	"github.com/docker/docker/pkg/archive"
 | 
						|
	"github.com/sirupsen/logrus"
 | 
						|
	"github.com/urfave/cli"
 | 
						|
)
 | 
						|
 | 
						|
var appCpCommand = cli.Command{
 | 
						|
	Name:      "cp",
 | 
						|
	Aliases:   []string{"c"},
 | 
						|
	ArgsUsage: "<domain> <src> <dst>",
 | 
						|
	Flags: []cli.Flag{
 | 
						|
		internal.DebugFlag,
 | 
						|
		internal.NoInputFlag,
 | 
						|
		internal.OfflineFlag,
 | 
						|
	},
 | 
						|
	Before: internal.SubCommandBefore,
 | 
						|
	Usage:  "Copy files to/from a running app service",
 | 
						|
	Description: `
 | 
						|
Copy files to and from any app service file system.
 | 
						|
 | 
						|
If you want to copy a myfile.txt to the root of the app service:
 | 
						|
 | 
						|
    abra app cp <domain> myfile.txt app:/
 | 
						|
 | 
						|
And if you want to copy that file back to your current working directory locally:
 | 
						|
 | 
						|
		abra app cp <domain> app:/myfile.txt .
 | 
						|
`,
 | 
						|
	Action: func(c *cli.Context) error {
 | 
						|
		conf := runtime.New(runtime.WithOffline(internal.Offline))
 | 
						|
		app := internal.ValidateApp(c, conf)
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		src := c.Args().Get(1)
 | 
						|
		dst := c.Args().Get(2)
 | 
						|
		if src == "" {
 | 
						|
			logrus.Fatal("missing <src> argument")
 | 
						|
		} else if dst == "" {
 | 
						|
			logrus.Fatal("missing <dest> argument")
 | 
						|
		}
 | 
						|
 | 
						|
		parsedSrc := strings.SplitN(src, ":", 2)
 | 
						|
		parsedDst := strings.SplitN(dst, ":", 2)
 | 
						|
		errorMsg := "one of <src>/<dest> arguments must take $SERVICE:$PATH form"
 | 
						|
		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(dstPath); os.IsNotExist(err) {
 | 
						|
				logrus.Fatalf("%s does not exist locally?", dstPath)
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if err := configureAndCp(c, cl, app, srcPath, dstPath, service, isToContainer); err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		return nil
 | 
						|
	},
 | 
						|
	BashComplete: autocomplete.AppNameComplete,
 | 
						|
}
 | 
						|
 | 
						|
func configureAndCp(
 | 
						|
	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)
 | 
						|
	if err != nil {
 | 
						|
		logrus.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	logrus.Debugf("retrieved %s as target container on %s", formatter.ShortenID(container.ID), app.Server)
 | 
						|
 | 
						|
	if isToContainer {
 | 
						|
		if _, err := os.Stat(srcPath); err != nil {
 | 
						|
			logrus.Fatalf("%s does not exist?", srcPath)
 | 
						|
		}
 | 
						|
 | 
						|
		toTarOpts := &archive.TarOptions{NoOverwriteDirNonDir: true, Compression: archive.Gzip}
 | 
						|
		content, err := archive.TarWithOptions(srcPath, toTarOpts)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		copyOpts := types.CopyToContainerOptions{AllowOverwriteDirWithFile: false, CopyUIDGID: false}
 | 
						|
		if err := cl.CopyToContainer(context.Background(), container.ID, dstPath, content, copyOpts); err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		content, _, err := cl.CopyFromContainer(context.Background(), container.ID, srcPath)
 | 
						|
		if err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
		defer content.Close()
 | 
						|
		fromTarOpts := &archive.TarOptions{NoOverwriteDirNonDir: true, Compression: archive.Gzip}
 | 
						|
		if err := archive.Untar(content, dstPath, fromTarOpts); err != nil {
 | 
						|
			logrus.Fatal(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |