abra/cli/app/cp.go

157 lines
4.1 KiB
Go
Raw Normal View History

package app
2021-08-29 11:41:29 +00:00
import (
"context"
"fmt"
2021-08-29 11:41:29 +00:00
"os"
"strings"
"coopcloud.tech/abra/cli/internal"
2021-12-11 23:17:39 +00:00
"coopcloud.tech/abra/pkg/autocomplete"
"coopcloud.tech/abra/pkg/client"
"coopcloud.tech/abra/pkg/config"
"coopcloud.tech/abra/pkg/container"
2021-12-28 00:24:23 +00:00
"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"
2021-08-29 11:41:29 +00:00
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
2021-08-29 11:41:29 +00:00
)
var appCpCommand = cli.Command{
Name: "cp",
2021-09-04 23:34:56 +00:00
Aliases: []string{"c"},
2022-01-25 12:48:04 +00:00
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: `
2022-05-13 14:44:49 +00:00
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:
2022-01-25 12:48:04 +00:00
abra app cp <domain> myfile.txt app:/
And if you want to copy that file back to your current working directory locally:
2022-01-25 12:48:04 +00:00
abra app cp <domain> app:/myfile.txt .
`,
2021-08-29 11:41:29 +00:00
Action: func(c *cli.Context) error {
conf := runtime.New(runtime.WithOffline(internal.Offline))
app := internal.ValidateApp(c, conf)
2021-08-29 11:41:29 +00:00
cl, err := client.New(app.Server)
if err != nil {
logrus.Fatal(err)
}
2021-08-29 11:41:29 +00:00
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")
2021-08-29 11:41:29 +00:00
} 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")
2021-08-29 11:41:29 +00:00
}
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 {
2021-08-29 11:41:29 +00:00
logrus.Fatal(err)
}
return nil
2021-08-29 11:41:29 +00:00
},
2021-12-11 23:17:39 +00:00
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
}