@@ -34,6 +34,7 @@ func newCopyCommand() *cobra.Command {
34
34
35
35
copyCommand .Flags ().BoolP ("recursive" , "r" , false , "copy directories recursively" )
36
36
copyCommand .Flags ().BoolP ("verbose" , "v" , false , "enable verbose output" )
37
+ copyCommand .Flags ().BoolP ("rsync" , "" , false , "use rsync for copying instead of scp" )
37
38
38
39
return copyCommand
39
40
}
@@ -49,10 +50,24 @@ func copyAction(cmd *cobra.Command, args []string) error {
49
50
return err
50
51
}
51
52
52
- arg0 , err := exec . LookPath ( "scp " )
53
+ useRsync , err := cmd . Flags (). GetBool ( "rsync " )
53
54
if err != nil {
54
55
return err
55
56
}
57
+
58
+ var arg0 string
59
+ if useRsync {
60
+ arg0 , err = exec .LookPath ("rsync" )
61
+ if err != nil {
62
+ return err
63
+ }
64
+ } else {
65
+ arg0 , err = exec .LookPath ("scp" )
66
+ if err != nil {
67
+ return err
68
+ }
69
+ }
70
+
56
71
instances := make (map [string ]* store.Instance )
57
72
scpFlags := []string {}
58
73
scpArgs := []string {}
@@ -67,6 +82,9 @@ func copyAction(cmd *cobra.Command, args []string) error {
67
82
68
83
if verbose {
69
84
scpFlags = append (scpFlags , "-v" )
85
+ if useRsync {
86
+ scpFlags = append (scpFlags , "--progress" )
87
+ }
70
88
} else {
71
89
scpFlags = append (scpFlags , "-q" )
72
90
}
@@ -93,11 +111,15 @@ func copyAction(cmd *cobra.Command, args []string) error {
93
111
if inst .Status == store .StatusStopped {
94
112
return fmt .Errorf ("instance %q is stopped, run `limactl start %s` to start the instance" , instName , instName )
95
113
}
96
- if legacySSH {
97
- scpFlags = append (scpFlags , "-P" , fmt .Sprintf ("%d" , inst .SSHLocalPort ))
114
+ if useRsync {
98
115
scpArgs = append (scpArgs , fmt .Sprintf ("%s@127.0.0.1:%s" , * inst .Config .User .Name , path [1 ]))
99
116
} else {
100
- scpArgs = append (scpArgs , fmt .Sprintf ("scp://%s@127.0.0.1:%d/%s" , * inst .Config .User .Name , inst .SSHLocalPort , path [1 ]))
117
+ if legacySSH {
118
+ scpFlags = append (scpFlags , "-P" , fmt .Sprintf ("%d" , inst .SSHLocalPort ))
119
+ scpArgs = append (scpArgs , fmt .Sprintf ("%s@127.0.0.1:%s" , * inst .Config .User .Name , path [1 ]))
120
+ } else {
121
+ scpArgs = append (scpArgs , fmt .Sprintf ("scp://%s@127.0.0.1:%d/%s" , * inst .Config .User .Name , inst .SSHLocalPort , path [1 ]))
122
+ }
101
123
}
102
124
instances [instName ] = inst
103
125
default :
@@ -107,7 +129,9 @@ func copyAction(cmd *cobra.Command, args []string) error {
107
129
if legacySSH && len (instances ) > 1 {
108
130
return errors .New ("more than one (instance) host is involved in this command, this is only supported for openSSH v8.0 or higher" )
109
131
}
110
- scpFlags = append (scpFlags , "-3" , "--" )
132
+ if ! useRsync {
133
+ scpFlags = append (scpFlags , "-3" , "--" )
134
+ }
111
135
scpArgs = append (scpFlags , scpArgs ... )
112
136
113
137
var sshOpts []string
@@ -128,13 +152,23 @@ func copyAction(cmd *cobra.Command, args []string) error {
128
152
return err
129
153
}
130
154
}
155
+
156
+ var cmdArgs []string
131
157
sshArgs := sshutil .SSHArgsFromOpts (sshOpts )
158
+ if useRsync {
159
+ // for rsync, add the -e flag with SSH options
160
+ scpFlags = append (scpFlags , "-e" , fmt .Sprintf ("ssh %s" , strings .Join (sshArgs , " " )))
161
+ cmdArgs = append (cmdArgs , append (scpFlags , scpArgs ... )... )
162
+ } else {
163
+ // for scp, append SSH options and scpArgs
164
+ cmdArgs = append (cmdArgs , append (sshArgs , scpArgs ... )... )
165
+ }
132
166
133
- sshCmd := exec .Command (arg0 , append ( sshArgs , scpArgs ... ) ... )
167
+ sshCmd := exec .Command (arg0 , cmdArgs ... )
134
168
sshCmd .Stdin = cmd .InOrStdin ()
135
169
sshCmd .Stdout = cmd .OutOrStdout ()
136
170
sshCmd .Stderr = cmd .ErrOrStderr ()
137
- logrus .Debugf ("executing scp (may take a long time): %+v" , sshCmd .Args )
171
+ logrus .Debugf ("executing %s (may take a long time): %+v" , arg0 , sshCmd .Args )
138
172
139
173
// TODO: use syscall.Exec directly (results in losing tty?)
140
174
return sshCmd .Run ()
0 commit comments