9
9
"net/http"
10
10
"os"
11
11
"os/exec"
12
+ "os/signal"
12
13
"path/filepath"
13
14
"runtime"
14
15
"strconv"
@@ -24,8 +25,12 @@ func init() {
24
25
}
25
26
26
27
func main () {
27
- skipSyncFlag := flag .Bool ("skipsync" , false , "skip syncing local settings and extensions to remote host" )
28
- sshFlags := flag .String ("ssh-flags" , "" , "custom SSH flags" )
28
+ var (
29
+ skipSyncFlag = flag .Bool ("skipsync" , false , "skip syncing local settings and extensions to remote host" )
30
+ sshFlags = flag .String ("ssh-flags" , "" , "custom SSH flags" )
31
+ syncBack = flag .Bool ("b" , false , "sync extensions back on termination" )
32
+ )
33
+
29
34
flag .Usage = func () {
30
35
fmt .Printf (`Usage: [-skipsync] %v HOST [DIR] [SSH ARGS...]
31
36
@@ -58,6 +63,9 @@ More info: https://github.com/codercom/sshcode
58
63
"-tt" ,
59
64
host ,
60
65
`/bin/bash -c 'set -euxo pipefail || exit 1
66
+ # Make sure any currently running code-server is gone so we can overwrite
67
+ # the binary.
68
+ pkill -9 ` + filepath .Base (codeServerPath )+ ` || true
61
69
wget -q https://codesrv-ci.cdr.sh/latest-linux -O ` + codeServerPath + `
62
70
mkdir -p ~/.local/share/code-server
63
71
cd ` + filepath .Dir (codeServerPath )+ `
@@ -74,17 +82,17 @@ chmod +x `+codeServerPath+`
74
82
flog .Fatal ("failed to update code-server: %v" , err )
75
83
}
76
84
77
- if ! ( * skipSyncFlag ) {
85
+ if ! * skipSyncFlag {
78
86
start := time .Now ()
79
87
flog .Info ("syncing settings" )
80
- err = syncUserSettings (host )
88
+ err = syncUserSettings (host , false )
81
89
if err != nil {
82
90
flog .Fatal ("failed to sync settings: %v" , err )
83
91
}
84
92
flog .Info ("synced settings in %s" , time .Since (start ))
85
93
86
94
flog .Info ("syncing extensions" )
87
- err = syncExtensions (host )
95
+ err = syncExtensions (host , false )
88
96
if err != nil {
89
97
flog .Fatal ("failed to sync extensions: %v" , err )
90
98
}
@@ -131,8 +139,38 @@ chmod +x `+codeServerPath+`
131
139
break
132
140
}
133
141
142
+ ctx , cancel = context .WithCancel (context .Background ())
134
143
openBrowser (url )
135
- sshCmd .Wait ()
144
+
145
+ go func () {
146
+ defer cancel ()
147
+ sshCmd .Wait ()
148
+ }()
149
+
150
+ c := make (chan os.Signal )
151
+ signal .Notify (c , os .Interrupt )
152
+
153
+ select {
154
+ case <- ctx .Done ():
155
+ case <- c :
156
+ }
157
+
158
+ if ! * syncBack {
159
+ flog .Info ("shutting down" )
160
+ return
161
+ }
162
+
163
+ flog .Info ("synchronizing VS Code back to local" )
164
+
165
+ err = syncExtensions (host , true )
166
+ if err != nil {
167
+ flog .Fatal ("failed to sync extensions back: %v" , err )
168
+ }
169
+
170
+ err = syncUserSettings (host , true )
171
+ if err != nil {
172
+ flog .Fatal ("failed to user settigns extensions back: %v" , err )
173
+ }
136
174
}
137
175
138
176
func openBrowser (url string ) {
@@ -197,40 +235,63 @@ func randomPort() (string, error) {
197
235
return "" , xerrors .Errorf ("max number of tries exceeded: %d" , maxTries )
198
236
}
199
237
200
- func syncUserSettings (host string ) error {
238
+ func syncUserSettings (host string , back bool ) error {
201
239
localConfDir , err := configDir ()
202
240
if err != nil {
203
241
return err
204
242
}
205
- const remoteSettingsDir = ".local/share/code-server/User"
243
+ const remoteSettingsDir = ".local/share/code-server/User/"
244
+
245
+ var (
246
+ src = localConfDir + "/"
247
+ dest = host + ":" + remoteSettingsDir
248
+ )
249
+
250
+ if back {
251
+ dest , src = src , dest
252
+ }
206
253
207
254
// Append "/" to have rsync copy the contents of the dir.
208
- return rsync (localConfDir + "/" , remoteSettingsDir , host , "workspaceStorage" , "logs" , "CachedData" )
255
+ return rsync (src , dest , "workspaceStorage" , "logs" , "CachedData" )
209
256
}
210
257
211
- func syncExtensions (host string ) error {
258
+ func syncExtensions (host string , back bool ) error {
212
259
localExtensionsDir , err := extensionsDir ()
213
260
if err != nil {
214
261
return err
215
262
}
216
- const remoteExtensionsDir = ".local/share/code-server/extensions"
263
+ const remoteExtensionsDir = ".local/share/code-server/extensions/"
264
+
265
+ var (
266
+ src = localExtensionsDir + "/"
267
+ dest = host + ":" + remoteExtensionsDir
268
+ )
269
+ if back {
270
+ dest , src = src , dest
271
+ }
217
272
218
- return rsync (localExtensionsDir + "/" , remoteExtensionsDir , host )
273
+ return rsync (src , dest )
219
274
}
220
275
221
- func rsync (src string , dest string , host string , excludePaths ... string ) error {
222
- remoteDest := fmt .Sprintf ("%s:%s" , host , dest )
276
+ func rsync (src string , dest string , excludePaths ... string ) error {
223
277
excludeFlags := make ([]string , len (excludePaths ))
224
278
for i , path := range excludePaths {
225
279
excludeFlags [i ] = "--exclude=" + path
226
280
}
227
281
228
- cmd := exec .Command ("rsync" , append (excludeFlags , "-azv" , "--copy-unsafe-links" , src , remoteDest )... )
282
+ cmd := exec .Command ("rsync" , append (excludeFlags , "-azvr" ,
283
+ // Only update newer directories, and sync times
284
+ // to keep things simple.
285
+ "-u" , "--times" ,
286
+ "--copy-unsafe-links" ,
287
+ src , dest ,
288
+ )... ,
289
+ )
229
290
cmd .Stdout = os .Stdout
230
291
cmd .Stderr = os .Stderr
231
292
err := cmd .Run ()
232
293
if err != nil {
233
- return xerrors .Errorf ("failed to rsync '%s' to '%s': %w" , src , remoteDest , err )
294
+ return xerrors .Errorf ("failed to rsync '%s' to '%s': %w" , src , dest , err )
234
295
}
235
296
236
297
return nil
@@ -240,9 +301,9 @@ func configDir() (string, error) {
240
301
var path string
241
302
switch runtime .GOOS {
242
303
case "linux" :
243
- path = os .ExpandEnv ("$HOME/.config/Code/User" )
304
+ path = os .ExpandEnv ("$HOME/.config/Code/User/ " )
244
305
case "darwin" :
245
- path = os .ExpandEnv ("$HOME/Library/Application Support/Code/User" )
306
+ path = os .ExpandEnv ("$HOME/Library/Application Support/Code/User/ " )
246
307
default :
247
308
return "" , xerrors .Errorf ("unsupported platform: %s" , runtime .GOOS )
248
309
}
@@ -253,7 +314,7 @@ func extensionsDir() (string, error) {
253
314
var path string
254
315
switch runtime .GOOS {
255
316
case "linux" , "darwin" :
256
- path = os .ExpandEnv ("$HOME/.vscode/extensions" )
317
+ path = os .ExpandEnv ("$HOME/.vscode/extensions/ " )
257
318
default :
258
319
return "" , xerrors .Errorf ("unsupported platform: %s" , runtime .GOOS )
259
320
}
0 commit comments