| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -41,6 +41,7 @@ type rootCmd struct { | |||
| 41 | 41 | noReuseConnection bool | |
| 42 | 42 | bindAddr string | |
| 43 | 43 | sshFlags string | |
| 44 | + uploadCodeServer string | ||
| 44 | 45 | } | |
| 45 | 46 | ||
| 46 | 47 | func (c *rootCmd) Spec() cli.CommandSpec { | |
@@ -58,6 +59,7 @@ func (c *rootCmd) RegisterFlags(fl *pflag.FlagSet) { | |||
| 58 | 59 | fl.BoolVar(&c.noReuseConnection, "no-reuse-connection", false, "do not reuse SSH connection via control socket") | |
| 59 | 60 | fl.StringVar(&c.bindAddr, "bind", "", "local bind address for SSH tunnel, in [HOST][:PORT] syntax (default: 127.0.0.1)") | |
| 60 | 61 | fl.StringVar(&c.sshFlags, "ssh-flags", "", "custom SSH flags") | |
| 62 | + fl.StringVar(&c.uploadCodeServer, "upload-code-server", "", "custom code-server binary to upload to the remote host") | ||
| 61 | 63 | } | |
| 62 | 64 | ||
| 63 | 65 | func (c *rootCmd) Run(fl *pflag.FlagSet) { | |
@@ -79,11 +81,12 @@ func (c *rootCmd) Run(fl *pflag.FlagSet) { | |||
| 79 | 81 | } | |
| 80 | 82 | ||
| 81 | 83 | err := sshCode(host, dir, options{ | |
| 82 | - skipSync: c.skipSync, | ||
| 83 | - sshFlags: c.sshFlags, | ||
| 84 | - bindAddr: c.bindAddr, | ||
| 85 | - syncBack: c.syncBack, | ||
| 86 | - reuseConnection: !c.noReuseConnection, | ||
| 84 | + skipSync: c.skipSync, | ||
| 85 | + sshFlags: c.sshFlags, | ||
| 86 | + bindAddr: c.bindAddr, | ||
| 87 | + syncBack: c.syncBack, | ||
| 88 | + reuseConnection: !c.noReuseConnection, | ||
| 89 | + uploadCodeServer: c.uploadCodeServer, | ||
| 87 | 90 | }) | |
| 88 | 91 | ||
| 89 | 92 | if err != nil { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,13 +29,14 @@ const ( | |||
| 29 | 29 | ) | |
| 30 | 30 | ||
| 31 | 31 | type 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 | ||
| 39 | 40 | } | |
| 40 | 41 | ||
| 41 | 42 | func sshCode(host, dir string, o options) error { | |
@@ -76,23 +77,49 @@ func sshCode(host, dir string, o options) error { | |||
| 76 | 77 | } | |
| 77 | 78 | } | |
| 78 | 79 | ||
| 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 | + } | ||
| 81 | 87 | ||
| 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 | + ) | ||
| 84 | 92 | ||
| 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 | + } | ||
| 96 | 123 | } | |
| 97 | 124 | ||
| 98 | 125 | if !o.skipSync { | |
@@ -117,13 +144,13 @@ func sshCode(host, dir string, o options) error { | |||
| 117 | 144 | ||
| 118 | 145 | flog.Info("Tunneling remote port %v to %v", o.remotePort, o.bindAddr) | |
| 119 | 146 | ||
| 120 | - sshCmdStr = | ||
| 147 | + sshCmdStr := | ||
| 121 | 148 | 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'", | |
| 122 | 149 | o.bindAddr, o.remotePort, o.sshFlags, host, dir, codeServerPath, o.remotePort, | |
| 123 | 150 | ) | |
| 124 | 151 | ||
| 125 | 152 | // Starts code-server and forwards the remote port. | |
| 126 | - sshCmd = exec.Command("sh", "-l", "-c", sshCmdStr) | ||
| 153 | + sshCmd := exec.Command("sh", "-l", "-c", sshCmdStr) | ||
| 127 | 154 | sshCmd.Stdin = os.Stdin | |
| 128 | 155 | sshCmd.Stdout = os.Stdout | |
| 129 | 156 | sshCmd.Stderr = os.Stderr | |
@@ -399,6 +426,20 @@ func checkSSHMaster(sshMasterCmd *exec.Cmd, sshFlags string, host string) error | |||
| 399 | 426 | return xerrors.Errorf("max number of tries exceeded: %d", maxTries) | |
| 400 | 427 | } | |
| 401 | 428 | ||
| 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 | + | ||
| 402 | 443 | func syncUserSettings(sshFlags string, host string, back bool) error { | |
| 403 | 444 | localConfDir, err := configDir() | |
| 404 | 445 | if err != nil { | |
@@ -517,6 +558,18 @@ func ensureDir(path string) error { | |||
| 517 | 558 | return nil | |
| 518 | 559 | } | |
| 519 | 560 | ||
| 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 | + | ||
| 520 | 573 | // parseHost parses the host argument. If 'gcp:' is prefixed to the | |
| 521 | 574 | // host then a lookup is done using gcloud to determine the external IP and any | |
| 522 | 575 | // additional SSH arguments that should be used for ssh commands. Otherwise, host | |
| Back | FazBrowse Home | New Git URL |
0 commit comments