Skip to content

Commit 4c95f10

Browse files
committed
add rsync flag option to copy files using rsync
Signed-off-by: olalekan odukoya <odukoyaonline@gmail.com>
1 parent ccd3c0c commit 4c95f10

File tree

1 file changed

+58
-18
lines changed

1 file changed

+58
-18
lines changed

cmd/limactl/copy.go

+58-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ Prefix guest filenames with the instance name and a colon.
2121
Example: limactl copy default:/etc/os-release .
2222
`
2323

24+
type copyTool string
25+
26+
const (
27+
Rsync copyTool = "rsync"
28+
Scp copyTool = "scp"
29+
)
30+
2431
func newCopyCommand() *cobra.Command {
2532
copyCommand := &cobra.Command{
2633
Use: "copy SOURCE ... TARGET",
@@ -49,13 +56,20 @@ func copyAction(cmd *cobra.Command, args []string) error {
4956
return err
5057
}
5158

52-
arg0, err := exec.LookPath("scp")
53-
if err != nil {
54-
return err
59+
defaultTool := Rsync
60+
arg0, err := exec.LookPath(string(defaultTool))
61+
if err != nil || !strings.HasSuffix(arg0, "rsync") {
62+
defaultTool = Scp
63+
arg0, err = exec.LookPath(string(defaultTool))
64+
if err != nil {
65+
return err
66+
}
5567
}
68+
logrus.Infof("using copy tool %q", arg0)
69+
5670
instances := make(map[string]*store.Instance)
57-
scpFlags := []string{}
58-
scpArgs := []string{}
71+
copyToolFlags := []string{}
72+
copyToolArgs := []string{}
5973
debug, err := cmd.Flags().GetBool("debug")
6074
if err != nil {
6175
return err
@@ -65,22 +79,28 @@ func copyAction(cmd *cobra.Command, args []string) error {
6579
verbose = true
6680
}
6781

82+
useRsync := isCopyToolRsync(defaultTool)
83+
6884
if verbose {
69-
scpFlags = append(scpFlags, "-v")
70-
} else {
71-
scpFlags = append(scpFlags, "-q")
85+
copyToolFlags = append(copyToolFlags, "-v")
86+
if useRsync {
87+
copyToolFlags = append(copyToolFlags, "--progress")
88+
}
89+
}
90+
if !verbose {
91+
copyToolFlags = append(copyToolFlags, "-q")
7292
}
7393

7494
if recursive {
75-
scpFlags = append(scpFlags, "-r")
95+
copyToolFlags = append(copyToolFlags, "-r")
7696
}
7797
// this assumes that ssh and scp come from the same place, but scp has no -V
7898
legacySSH := sshutil.DetectOpenSSHVersion("ssh").LessThan(*semver.New("8.0.0"))
7999
for _, arg := range args {
80100
path := strings.Split(arg, ":")
81101
switch len(path) {
82102
case 1:
83-
scpArgs = append(scpArgs, arg)
103+
copyToolArgs = append(copyToolArgs, arg)
84104
case 2:
85105
instName := path[0]
86106
inst, err := store.Inspect(instName)
@@ -93,11 +113,15 @@ func copyAction(cmd *cobra.Command, args []string) error {
93113
if inst.Status == store.StatusStopped {
94114
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
95115
}
96-
if legacySSH {
97-
scpFlags = append(scpFlags, "-P", fmt.Sprintf("%d", inst.SSHLocalPort))
98-
scpArgs = append(scpArgs, fmt.Sprintf("%s@127.0.0.1:%s", *inst.Config.User.Name, path[1]))
116+
if useRsync {
117+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("%s@127.0.0.1:%s", *inst.Config.User.Name, path[1]))
99118
} else {
100-
scpArgs = append(scpArgs, fmt.Sprintf("scp://%s@127.0.0.1:%d/%s", *inst.Config.User.Name, inst.SSHLocalPort, path[1]))
119+
if legacySSH {
120+
copyToolFlags = append(copyToolFlags, "-P", fmt.Sprintf("%d", inst.SSHLocalPort))
121+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("%s@127.0.0.1:%s", *inst.Config.User.Name, path[1]))
122+
} else {
123+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("scp://%s@127.0.0.1:%d/%s", *inst.Config.User.Name, inst.SSHLocalPort, path[1]))
124+
}
101125
}
102126
instances[instName] = inst
103127
default:
@@ -107,8 +131,10 @@ func copyAction(cmd *cobra.Command, args []string) error {
107131
if legacySSH && len(instances) > 1 {
108132
return errors.New("more than one (instance) host is involved in this command, this is only supported for openSSH v8.0 or higher")
109133
}
110-
scpFlags = append(scpFlags, "-3", "--")
111-
scpArgs = append(scpFlags, scpArgs...)
134+
if !useRsync {
135+
copyToolFlags = append(copyToolFlags, "-3", "--")
136+
}
137+
copyToolArgs = append(copyToolFlags, copyToolArgs...)
112138

113139
var sshOpts []string
114140
if len(instances) == 1 {
@@ -128,14 +154,28 @@ func copyAction(cmd *cobra.Command, args []string) error {
128154
return err
129155
}
130156
}
157+
131158
sshArgs := sshutil.SSHArgsFromOpts(sshOpts)
132159

133-
sshCmd := exec.Command(arg0, append(sshArgs, scpArgs...)...)
160+
sshCmd := exec.Command(arg0, createArgs(sshArgs, copyToolArgs, defaultTool)...)
134161
sshCmd.Stdin = cmd.InOrStdin()
135162
sshCmd.Stdout = cmd.OutOrStdout()
136163
sshCmd.Stderr = cmd.ErrOrStderr()
137-
logrus.Debugf("executing scp (may take a long time): %+v", sshCmd.Args)
164+
logrus.Debugf("executing %s (may take a long time): %+v", arg0, sshCmd.Args)
138165

139166
// TODO: use syscall.Exec directly (results in losing tty?)
140167
return sshCmd.Run()
141168
}
169+
170+
func isCopyToolRsync(copyTool copyTool) bool {
171+
return copyTool == Rsync
172+
}
173+
174+
func createArgs(sshArgs, copyToolArgs []string, copyTool copyTool) []string {
175+
if isCopyToolRsync(copyTool) {
176+
rsyncFlags := []string{"-e", fmt.Sprintf("ssh %s", strings.Join(sshArgs, " "))}
177+
return append(rsyncFlags, copyToolArgs...)
178+
}
179+
180+
return append(sshArgs, copyToolArgs...)
181+
}

0 commit comments

Comments
 (0)