Skip to content

Commit aa5cf22

Browse files
committed
add rsync flag option to copy files using rsync
Signed-off-by: olalekan odukoya <[email protected]>
1 parent ccd3c0c commit aa5cf22

File tree

1 file changed

+54
-17
lines changed

1 file changed

+54
-17
lines changed

cmd/limactl/copy.go

+54-17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ 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 Rsync copyTool = "rsync"
27+
const Scp copyTool = "scp"
28+
2429
func newCopyCommand() *cobra.Command {
2530
copyCommand := &cobra.Command{
2631
Use: "copy SOURCE ... TARGET",
@@ -49,13 +54,19 @@ func copyAction(cmd *cobra.Command, args []string) error {
4954
return err
5055
}
5156

52-
arg0, err := exec.LookPath("scp")
57+
defaultTool := Rsync
58+
arg0, err := exec.LookPath(string(defaultTool))
5359
if err != nil {
54-
return err
60+
defaultTool = Scp
61+
arg0, err = exec.LookPath(string(defaultTool))
62+
if err != nil {
63+
return err
64+
}
5565
}
66+
5667
instances := make(map[string]*store.Instance)
57-
scpFlags := []string{}
58-
scpArgs := []string{}
68+
copyToolFlags := []string{}
69+
copyToolArgs := []string{}
5970
debug, err := cmd.Flags().GetBool("debug")
6071
if err != nil {
6172
return err
@@ -65,22 +76,28 @@ func copyAction(cmd *cobra.Command, args []string) error {
6576
verbose = true
6677
}
6778

79+
useRsync := isCopyToolRsync(defaultTool)
80+
6881
if verbose {
69-
scpFlags = append(scpFlags, "-v")
70-
} else {
71-
scpFlags = append(scpFlags, "-q")
82+
copyToolFlags = append(copyToolFlags, "-v")
83+
if useRsync {
84+
copyToolFlags = append(copyToolFlags, "--progress")
85+
}
86+
}
87+
if !verbose {
88+
copyToolFlags = append(copyToolFlags, "-q")
7289
}
7390

7491
if recursive {
75-
scpFlags = append(scpFlags, "-r")
92+
copyToolFlags = append(copyToolFlags, "-r")
7693
}
7794
// this assumes that ssh and scp come from the same place, but scp has no -V
7895
legacySSH := sshutil.DetectOpenSSHVersion("ssh").LessThan(*semver.New("8.0.0"))
7996
for _, arg := range args {
8097
path := strings.Split(arg, ":")
8198
switch len(path) {
8299
case 1:
83-
scpArgs = append(scpArgs, arg)
100+
copyToolArgs = append(copyToolArgs, arg)
84101
case 2:
85102
instName := path[0]
86103
inst, err := store.Inspect(instName)
@@ -93,11 +110,15 @@ func copyAction(cmd *cobra.Command, args []string) error {
93110
if inst.Status == store.StatusStopped {
94111
return fmt.Errorf("instance %q is stopped, run `limactl start %s` to start the instance", instName, instName)
95112
}
96-
if legacySSH {
97-
scpFlags = append(scpFlags, "-P", fmt.Sprintf("%d", inst.SSHLocalPort))
98-
scpArgs = append(scpArgs, fmt.Sprintf("%[email protected]:%s", *inst.Config.User.Name, path[1]))
113+
if useRsync {
114+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("%[email protected]:%s", *inst.Config.User.Name, path[1]))
99115
} else {
100-
scpArgs = append(scpArgs, fmt.Sprintf("scp://%[email protected]:%d/%s", *inst.Config.User.Name, inst.SSHLocalPort, path[1]))
116+
if legacySSH {
117+
copyToolFlags = append(copyToolFlags, "-P", fmt.Sprintf("%d", inst.SSHLocalPort))
118+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("%[email protected]:%s", *inst.Config.User.Name, path[1]))
119+
} else {
120+
copyToolArgs = append(copyToolArgs, fmt.Sprintf("scp://%[email protected]:%d/%s", *inst.Config.User.Name, inst.SSHLocalPort, path[1]))
121+
}
101122
}
102123
instances[instName] = inst
103124
default:
@@ -107,8 +128,10 @@ func copyAction(cmd *cobra.Command, args []string) error {
107128
if legacySSH && len(instances) > 1 {
108129
return errors.New("more than one (instance) host is involved in this command, this is only supported for openSSH v8.0 or higher")
109130
}
110-
scpFlags = append(scpFlags, "-3", "--")
111-
scpArgs = append(scpFlags, scpArgs...)
131+
if !useRsync {
132+
copyToolFlags = append(copyToolFlags, "-3", "--")
133+
}
134+
copyToolArgs = append(copyToolFlags, copyToolArgs...)
112135

113136
var sshOpts []string
114137
if len(instances) == 1 {
@@ -128,14 +151,28 @@ func copyAction(cmd *cobra.Command, args []string) error {
128151
return err
129152
}
130153
}
154+
131155
sshArgs := sshutil.SSHArgsFromOpts(sshOpts)
132156

133-
sshCmd := exec.Command(arg0, append(sshArgs, scpArgs...)...)
157+
sshCmd := exec.Command(arg0, createArgs(sshArgs, copyToolArgs, defaultTool)...)
134158
sshCmd.Stdin = cmd.InOrStdin()
135159
sshCmd.Stdout = cmd.OutOrStdout()
136160
sshCmd.Stderr = cmd.ErrOrStderr()
137-
logrus.Debugf("executing scp (may take a long time): %+v", sshCmd.Args)
161+
logrus.Debugf("executing %s (may take a long time): %+v", arg0, sshCmd.Args)
138162

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

0 commit comments

Comments
 (0)