@@ -29,13 +29,14 @@ const (
2929)
3030
3131type options struct {
32- skipSync bool
33- syncBack bool
34- noOpen bool
35- reuseConnection bool
36- bindAddr string
37- remotePort string
38- sshFlags string
32+ skipSync bool
33+ syncBack bool
34+ noOpen bool
35+ reuseConnection bool
36+ bindAddr string
37+ remotePort string
38+ sshFlags string
39+ uploadCodeServer string
3940}
4041
4142func sshCode (host , dir string , o options ) error {
@@ -76,23 +77,49 @@ func sshCode(host, dir string, o options) error {
7677 }
7778 }
7879
79- flog .Info ("ensuring code-server is updated..." )
80- dlScript := downloadScript (codeServerPath )
80+ // Upload local code-server or download code-server from CI server.
81+ if o .uploadCodeServer != "" {
82+ flog .Info ("uploading local code-server binary..." )
83+ err = copyCodeServerBinary (o .sshFlags , host , o .uploadCodeServer , codeServerPath )
84+ if err != nil {
85+ return xerrors .Errorf ("failed to upload local code-server binary to remote server: %w" , err )
86+ }
8187
82- // Downloads the latest code-server and allows it to be executed.
83- sshCmdStr := fmt .Sprintf ("ssh %v %v '/usr/bin/env bash -l'" , o .sshFlags , host )
88+ sshCmdStr :=
89+ fmt .Sprintf ("ssh %v %v 'chmod +x %v'" ,
90+ o .sshFlags , host , codeServerPath ,
91+ )
8492
85- sshCmd := exec .Command ("sh" , "-l" , "-c" , sshCmdStr )
86- sshCmd .Stdout = os .Stdout
87- sshCmd .Stderr = os .Stderr
88- sshCmd .Stdin = strings .NewReader (dlScript )
89- err = sshCmd .Run ()
90- if err != nil {
91- return xerrors .Errorf ("failed to update code-server: \n ---ssh cmd---\n %s\n ---download script---\n %s: %w" ,
92- sshCmdStr ,
93- dlScript ,
94- err ,
95- )
93+ sshCmd := exec .Command ("sh" , "-l" , "-c" , sshCmdStr )
94+ sshCmd .Stdout = os .Stdout
95+ sshCmd .Stderr = os .Stderr
96+ err = sshCmd .Run ()
97+ if err != nil {
98+ return xerrors .Errorf ("failed to make code-server binary executable:\n ---ssh cmd---\n %s: %w" ,
99+ sshCmdStr ,
100+ err ,
101+ )
102+ }
103+ } else {
104+ flog .Info ("ensuring code-server is updated..." )
105+ dlScript := downloadScript (codeServerPath )
106+
107+ // Downloads the latest code-server and allows it to be executed.
108+ sshCmdStr := fmt .Sprintf ("ssh %v %v '/usr/bin/env bash -l'" , o .sshFlags , host )
109+
110+ sshCmd := exec .Command ("sh" , "-l" , "-c" , sshCmdStr )
111+ sshCmd .Stdout = os .Stdout
112+ sshCmd .Stderr = os .Stderr
113+ sshCmd .Stdin = strings .NewReader (dlScript )
114+ err = sshCmd .Run ()
115+ if err != nil {
116+ return xerrors .Errorf ("failed to update code-server:\n ---ssh cmd---\n %s" +
117+ "\n ---download script---\n %s: %w" ,
118+ sshCmdStr ,
119+ dlScript ,
120+ err ,
121+ )
122+ }
96123 }
97124
98125 if ! o .skipSync {
@@ -117,13 +144,13 @@ func sshCode(host, dir string, o options) error {
117144
118145 flog .Info ("Tunneling remote port %v to %v" , o .remotePort , o .bindAddr )
119146
120- sshCmdStr =
147+ sshCmdStr : =
121148 fmt .Sprintf ("ssh -tt -q -L %v:localhost:%v %v %v 'cd %v; %v --host 127.0.0.1 --allow-http --no-auth --port=%v'" ,
122149 o .bindAddr , o .remotePort , o .sshFlags , host , dir , codeServerPath , o .remotePort ,
123150 )
124151
125152 // Starts code-server and forwards the remote port.
126- sshCmd = exec .Command ("sh" , "-l" , "-c" , sshCmdStr )
153+ sshCmd : = exec .Command ("sh" , "-l" , "-c" , sshCmdStr )
127154 sshCmd .Stdin = os .Stdin
128155 sshCmd .Stdout = os .Stdout
129156 sshCmd .Stderr = os .Stderr
@@ -399,6 +426,20 @@ func checkSSHMaster(sshMasterCmd *exec.Cmd, sshFlags string, host string) error
399426 return xerrors .Errorf ("max number of tries exceeded: %d" , maxTries )
400427}
401428
429+ // copyCodeServerBinary copies a code-server binary from local to remote.
430+ func copyCodeServerBinary (sshFlags string , host string , localPath string , remotePath string ) error {
431+ if err := validateIsFile (localPath ); err != nil {
432+ return err
433+ }
434+
435+ var (
436+ src = localPath
437+ dest = host + ":" + remotePath
438+ )
439+
440+ return rsync (src , dest , sshFlags )
441+ }
442+
402443func syncUserSettings (sshFlags string , host string , back bool ) error {
403444 localConfDir , err := configDir ()
404445 if err != nil {
@@ -517,6 +558,18 @@ func ensureDir(path string) error {
517558 return nil
518559}
519560
561+ // validateIsFile tries to stat the specified path and ensure it's a file.
562+ func validateIsFile (path string ) error {
563+ info , err := os .Stat (path )
564+ if err != nil {
565+ return err
566+ }
567+ if info .IsDir () {
568+ return xerrors .New ("path is a directory" )
569+ }
570+ return nil
571+ }
572+
520573// parseHost parses the host argument. If 'gcp:' is prefixed to the
521574// host then a lookup is done using gcloud to determine the external IP and any
522575// additional SSH arguments that should be used for ssh commands. Otherwise, host
0 commit comments