forked from toolshed/abra
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.9 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"
 | |
| 	"github.com/docker/docker/api/types"
 | |
| 	"github.com/docker/docker/api/types/filters"
 | |
| 	"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,
 | |
| 	},
 | |
| 	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 {
 | |
| 		app := internal.ValidateApp(c)
 | |
| 
 | |
| 		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)
 | |
| 			}
 | |
| 		}
 | |
| 		err := configureAndCp(c, app, srcPath, dstPath, service, isToContainer)
 | |
| 		if err != nil {
 | |
| 			logrus.Fatal(err)
 | |
| 		}
 | |
| 		return nil
 | |
| 
 | |
| 	},
 | |
| 	BashComplete: autocomplete.AppNameComplete,
 | |
| }
 | |
| 
 | |
| func configureAndCp(
 | |
| 	c *cli.Context,
 | |
| 	app config.App,
 | |
| 	srcPath string,
 | |
| 	dstPath string,
 | |
| 	service string,
 | |
| 	isToContainer bool) error {
 | |
| 	cl, err := client.New(app.Server)
 | |
| 	if err != nil {
 | |
| 		logrus.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	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
 | |
| }
 |