@@ -34,6 +34,7 @@ func newCopyCommand() *cobra.Command {
3434
3535 copyCommand .Flags ().BoolP ("recursive" , "r" , false , "copy directories recursively" )
3636 copyCommand .Flags ().BoolP ("verbose" , "v" , false , "enable verbose output" )
37+ copyCommand .Flags ().BoolP ("rsync" , "" , false , "use rsync for copying instead of scp" )
3738
3839 return copyCommand
3940}
@@ -49,10 +50,24 @@ func copyAction(cmd *cobra.Command, args []string) error {
4950 return err
5051 }
5152
52- arg0 , err := exec . LookPath ( "scp " )
53+ useRsync , err := cmd . Flags (). GetBool ( "rsync " )
5354 if err != nil {
5455 return err
5556 }
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+
5671 instances := make (map [string ]* store.Instance )
5772 scpFlags := []string {}
5873 scpArgs := []string {}
@@ -67,6 +82,9 @@ func copyAction(cmd *cobra.Command, args []string) error {
6782
6883 if verbose {
6984 scpFlags = append (scpFlags , "-v" )
85+ if useRsync {
86+ scpFlags = append (scpFlags , "--progress" )
87+ }
7088 } else {
7189 scpFlags = append (scpFlags , "-q" )
7290 }
@@ -93,11 +111,15 @@ func copyAction(cmd *cobra.Command, args []string) error {
93111 if inst .Status == store .StatusStopped {
94112 return fmt .Errorf ("instance %q is stopped, run `limactl start %s` to start the instance" , instName , instName )
95113 }
96- if legacySSH {
97- scpFlags = append (scpFlags , "-P" , fmt .Sprintf ("%d" , inst .SSHLocalPort ))
114+ if useRsync {
98115 scpArgs = append (
scpArgs ,
fmt .
Sprintf (
"%[email protected] :%s" ,
* inst .
Config .
User .
Name ,
path [
1 ]))
99116 } else {
100- scpArgs = append (
scpArgs ,
fmt .
Sprintf (
"scp://%[email protected] :%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 (
"%[email protected] :%s" ,
* inst .
Config .
User .
Name ,
path [
1 ]))
120+ } else {
121+ scpArgs = append (
scpArgs ,
fmt .
Sprintf (
"scp://%[email protected] :%d/%s" ,
* inst .
Config .
User .
Name ,
inst .
SSHLocalPort ,
path [
1 ]))
122+ }
101123 }
102124 instances [instName ] = inst
103125 default :
@@ -107,7 +129,9 @@ func copyAction(cmd *cobra.Command, args []string) error {
107129 if legacySSH && len (instances ) > 1 {
108130 return errors .New ("more than one (instance) host is involved in this command, this is only supported for openSSH v8.0 or higher" )
109131 }
110- scpFlags = append (scpFlags , "-3" , "--" )
132+ if ! useRsync {
133+ scpFlags = append (scpFlags , "-3" , "--" )
134+ }
111135 scpArgs = append (scpFlags , scpArgs ... )
112136
113137 var sshOpts []string
@@ -128,13 +152,23 @@ func copyAction(cmd *cobra.Command, args []string) error {
128152 return err
129153 }
130154 }
155+
156+ var cmdArgs []string
131157 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+ }
132166
133- sshCmd := exec .Command (arg0 , append ( sshArgs , scpArgs ... ) ... )
167+ sshCmd := exec .Command (arg0 , cmdArgs ... )
134168 sshCmd .Stdin = cmd .InOrStdin ()
135169 sshCmd .Stdout = cmd .OutOrStdout ()
136170 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 )
138172
139173 // TODO: use syscall.Exec directly (results in losing tty?)
140174 return sshCmd .Run ()
0 commit comments