Skip to content
This repository has been archived by the owner on Jan 17, 2021. It is now read-only.

Commit

Permalink
Add flag to sync extensions back to local
Browse files Browse the repository at this point in the history
Resolves #20
  • Loading branch information
ammario committed Apr 20, 2019
1 parent 3f4919f commit 5fad595
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 19 deletions.
3 changes: 3 additions & 0 deletions .sail/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
FROM codercom/ubuntu-dev-go

# Go module tooling is completely broken.
ENV GO111MODULE=off

LABEL project_root "~/go/src/go.coder.com"
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ This operation may take a while on a slow connections, but will be fast
on follow-up connections to the same server.

To disable this feature entirely, pass the `--skipsync` flag.

### Sync-back

By default, VS Code changes on the remote server won't be synced back
when the connection closes. To synchronize back to local when the connection ends,
pass the `-b` flag.
99 changes: 80 additions & 19 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"strconv"
Expand All @@ -24,8 +25,12 @@ func init() {
}

func main() {
skipSyncFlag := flag.Bool("skipsync", false, "skip syncing local settings and extensions to remote host")
sshFlags := flag.String("ssh-flags", "", "custom SSH flags")
var (
skipSyncFlag = flag.Bool("skipsync", false, "skip syncing local settings and extensions to remote host")
sshFlags = flag.String("ssh-flags", "", "custom SSH flags")
syncBack = flag.Bool("b", false, "sync extensions back on termination")
)

flag.Usage = func() {
fmt.Printf(`Usage: [-skipsync] %v HOST [DIR] [SSH ARGS...]
Expand Down Expand Up @@ -58,6 +63,9 @@ More info: https://github.com/codercom/sshcode
"-tt",
host,
`/bin/bash -c 'set -euxo pipefail || exit 1
# Make sure any currently running code-server is gone so we can overwrite
# the binary.
pkill -9 `+filepath.Base(codeServerPath)+` || true
wget -q https://codesrv-ci.cdr.sh/latest-linux -O `+codeServerPath+`
mkdir -p ~/.local/share/code-server
cd `+filepath.Dir(codeServerPath)+`
Expand All @@ -74,17 +82,17 @@ chmod +x `+codeServerPath+`
flog.Fatal("failed to update code-server: %v", err)
}

if !(*skipSyncFlag) {
if !*skipSyncFlag {
start := time.Now()
flog.Info("syncing settings")
err = syncUserSettings(host)
err = syncUserSettings(host, false)
if err != nil {
flog.Fatal("failed to sync settings: %v", err)
}
flog.Info("synced settings in %s", time.Since(start))

flog.Info("syncing extensions")
err = syncExtensions(host)
err = syncExtensions(host, false)
if err != nil {
flog.Fatal("failed to sync extensions: %v", err)
}
Expand Down Expand Up @@ -131,8 +139,38 @@ chmod +x `+codeServerPath+`
break
}

ctx, cancel = context.WithCancel(context.Background())
openBrowser(url)
sshCmd.Wait()

go func() {
defer cancel()
sshCmd.Wait()
}()

c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)

select {
case <-ctx.Done():
case <-c:
}

if !*syncBack {
flog.Info("shutting down")
return
}

flog.Info("synchronizing VS Code back to local")

err = syncExtensions(host, true)
if err != nil {
flog.Fatal("failed to sync extensions back: %v", err)
}

err = syncUserSettings(host, true)
if err != nil {
flog.Fatal("failed to user settigns extensions back: %v", err)
}
}

func openBrowser(url string) {
Expand Down Expand Up @@ -197,40 +235,63 @@ func randomPort() (string, error) {
return "", xerrors.Errorf("max number of tries exceeded: %d", maxTries)
}

func syncUserSettings(host string) error {
func syncUserSettings(host string, back bool) error {
localConfDir, err := configDir()
if err != nil {
return err
}
const remoteSettingsDir = ".local/share/code-server/User"
const remoteSettingsDir = ".local/share/code-server/User/"

var (
src = localConfDir + "/"
dest = host + ":" + remoteSettingsDir
)

if back {
dest, src = src, dest
}

// Append "/" to have rsync copy the contents of the dir.
return rsync(localConfDir+"/", remoteSettingsDir, host, "workspaceStorage", "logs", "CachedData")
return rsync(src, dest, "workspaceStorage", "logs", "CachedData")
}

func syncExtensions(host string) error {
func syncExtensions(host string, back bool) error {
localExtensionsDir, err := extensionsDir()
if err != nil {
return err
}
const remoteExtensionsDir = ".local/share/code-server/extensions"
const remoteExtensionsDir = ".local/share/code-server/extensions/"

var (
src = localExtensionsDir + "/"
dest = host + ":" + remoteExtensionsDir
)
if back {
dest, src = src, dest
}

return rsync(localExtensionsDir+"/", remoteExtensionsDir, host)
return rsync(src, dest)
}

func rsync(src string, dest string, host string, excludePaths ...string) error {
remoteDest := fmt.Sprintf("%s:%s", host, dest)
func rsync(src string, dest string, excludePaths ...string) error {
excludeFlags := make([]string, len(excludePaths))
for i, path := range excludePaths {
excludeFlags[i] = "--exclude=" + path
}

cmd := exec.Command("rsync", append(excludeFlags, "-azv", "--copy-unsafe-links", src, remoteDest)...)
cmd := exec.Command("rsync", append(excludeFlags, "-azvr",
// Only update newer directories, and sync times
// to keep things simple.
"-u", "--times",
"--copy-unsafe-links",
src, dest,
)...,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return xerrors.Errorf("failed to rsync '%s' to '%s': %w", src, remoteDest, err)
return xerrors.Errorf("failed to rsync '%s' to '%s': %w", src, dest, err)
}

return nil
Expand All @@ -240,9 +301,9 @@ func configDir() (string, error) {
var path string
switch runtime.GOOS {
case "linux":
path = os.ExpandEnv("$HOME/.config/Code/User")
path = os.ExpandEnv("$HOME/.config/Code/User/")
case "darwin":
path = os.ExpandEnv("$HOME/Library/Application Support/Code/User")
path = os.ExpandEnv("$HOME/Library/Application Support/Code/User/")
default:
return "", xerrors.Errorf("unsupported platform: %s", runtime.GOOS)
}
Expand All @@ -253,7 +314,7 @@ func extensionsDir() (string, error) {
var path string
switch runtime.GOOS {
case "linux", "darwin":
path = os.ExpandEnv("$HOME/.vscode/extensions")
path = os.ExpandEnv("$HOME/.vscode/extensions/")
default:
return "", xerrors.Errorf("unsupported platform: %s", runtime.GOOS)
}
Expand Down

0 comments on commit 5fad595

Please sign in to comment.