@@ -12,6 +12,7 @@ import (
12
12
"fmt"
13
13
"io"
14
14
"io/ioutil"
15
+ "net"
15
16
"net/http"
16
17
"net/url"
17
18
"os"
@@ -20,6 +21,7 @@ import (
20
21
"path/filepath"
21
22
"reflect"
22
23
"regexp"
24
+ "strconv"
23
25
"strings"
24
26
"syscall"
25
27
"time"
@@ -91,7 +93,14 @@ func main() {
91
93
}
92
94
}
93
95
94
- err = configureVMOptions (gitpodConfig , alias )
96
+ idePrefix := alias
97
+ if alias == "intellij" {
98
+ idePrefix = "idea"
99
+ }
100
+ // [idea64|goland64|pycharm64|phpstorm64].vmoptions
101
+ vmOptionsPath := fmt .Sprintf ("/ide-desktop/backend/bin/%s64.vmoptions" , idePrefix )
102
+
103
+ err = configureVMOptions (gitpodConfig , alias , vmOptionsPath )
95
104
if err != nil {
96
105
log .WithError (err ).Error ("failed to configure vmoptions" )
97
106
}
@@ -101,22 +110,56 @@ func main() {
101
110
}
102
111
go run (wsInfo , alias )
103
112
104
- http .HandleFunc ("/restart" , func (w http.ResponseWriter , r * http.Request ) {
105
- err := terminateIDE (defaultBackendPort )
113
+ debugAgentPrefix := "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:"
114
+ http .HandleFunc ("/debug" , func (w http.ResponseWriter , r * http.Request ) {
115
+ options , err := readVMOptions (vmOptionsPath )
106
116
if err != nil {
107
- log .WithError (err ).Error ("failed to terminate IDE" )
108
-
109
- w .WriteHeader (http .StatusInternalServerError )
110
- _ , _ = w .Write ([]byte (err .Error ()))
111
-
112
- os .Exit (1 )
117
+ log .WithError (err ).Error ("failed to configure debug agent" )
118
+ http .Error (w , err .Error (), http .StatusInternalServerError )
119
+ return
120
+ }
121
+ debugPort := ""
122
+ i := len (options ) - 1
123
+ for i >= 0 && debugPort == "" {
124
+ option := options [i ]
125
+ if strings .HasPrefix (option , debugAgentPrefix ) {
126
+ debugPort = option [len (debugAgentPrefix ):]
127
+ if debugPort == "0" {
128
+ debugPort = ""
129
+ }
130
+ }
131
+ i --
113
132
}
114
- log .Info ("asked IDE to terminate" )
115
-
116
- w .WriteHeader (http .StatusOK )
117
- _ , _ = w .Write ([]byte ("ok" ))
118
133
119
- os .Exit (0 )
134
+ if debugPort != "" {
135
+ fmt .Fprint (w , debugPort )
136
+ return
137
+ }
138
+ netListener , err := net .Listen ("tcp" , "localhost:0" )
139
+ if err != nil {
140
+ log .WithError (err ).Error ("failed to configure debug agent" )
141
+ http .Error (w , err .Error (), http .StatusInternalServerError )
142
+ return
143
+ }
144
+ debugPort = strconv .Itoa (netListener .(* net.TCPListener ).Addr ().(* net.TCPAddr ).Port )
145
+ _ = netListener .Close ()
146
+
147
+ debugOptions := []string {debugAgentPrefix + debugPort }
148
+ options = deduplicateVMOption (options , debugOptions , func (l , r string ) bool {
149
+ return strings .HasPrefix (l , debugAgentPrefix ) && strings .HasPrefix (r , debugAgentPrefix )
150
+ })
151
+ err = writeVMOptions (vmOptionsPath , options )
152
+ if err != nil {
153
+ log .WithError (err ).Error ("failed to configure debug agent" )
154
+ http .Error (w , err .Error (), http .StatusInternalServerError )
155
+ return
156
+ }
157
+ fmt .Fprint (w , debugPort )
158
+ restart (r )
159
+ })
160
+ http .HandleFunc ("/restart" , func (w http.ResponseWriter , r * http.Request ) {
161
+ fmt .Fprint (w , "terminated" )
162
+ restart (r )
120
163
})
121
164
http .HandleFunc ("/joinLink" , func (w http.ResponseWriter , r * http.Request ) {
122
165
backendPort := r .URL .Query ().Get ("backendPort" )
@@ -170,6 +213,19 @@ func main() {
170
213
}
171
214
}
172
215
216
+ func restart (r * http.Request ) {
217
+ backendPort := r .URL .Query ().Get ("backendPort" )
218
+ if backendPort == "" {
219
+ backendPort = defaultBackendPort
220
+ }
221
+ err := terminateIDE (backendPort )
222
+ if err != nil {
223
+ log .WithError (err ).Error ("failed to terminate IDE gracefully" )
224
+ os .Exit (1 )
225
+ }
226
+ os .Exit (0 )
227
+ }
228
+
173
229
type Projects struct {
174
230
JoinLink string `json:"joinLink"`
175
231
}
@@ -324,19 +380,27 @@ func handleSignal(projectPath string) {
324
380
log .Info ("asked IDE to terminate" )
325
381
}
326
382
327
- func configureVMOptions (config * gitpod.GitpodConfig , alias string ) error {
328
- idePrefix := alias
329
- if alias == "intellij" {
330
- idePrefix = "idea"
331
- }
332
- // [idea64|goland64|pycharm64|phpstorm64].vmoptions
333
- path := fmt .Sprintf ("/ide-desktop/backend/bin/%s64.vmoptions" , idePrefix )
334
- content , err := ioutil .ReadFile (path )
383
+ func configureVMOptions (config * gitpod.GitpodConfig , alias string , vmOptionsPath string ) error {
384
+ options , err := readVMOptions (vmOptionsPath )
335
385
if err != nil {
336
386
return err
337
387
}
338
- newContent := updateVMOptions (config , alias , string (content ))
339
- return ioutil .WriteFile (path , []byte (newContent ), 0 )
388
+ newOptions := updateVMOptions (config , alias , options )
389
+ return writeVMOptions (vmOptionsPath , newOptions )
390
+ }
391
+
392
+ func readVMOptions (vmOptionsPath string ) ([]string , error ) {
393
+ content , err := ioutil .ReadFile (vmOptionsPath )
394
+ if err != nil {
395
+ return nil , err
396
+ }
397
+ return strings .Fields (string (content )), nil
398
+ }
399
+
400
+ func writeVMOptions (vmOptionsPath string , vmoptions []string ) error {
401
+ // vmoptions file should end with a newline
402
+ content := strings .Join (vmoptions , "\n " ) + "\n "
403
+ return ioutil .WriteFile (vmOptionsPath , []byte (content ), 0 )
340
404
}
341
405
342
406
// deduplicateVMOption append new VMOptions onto old VMOptions and remove any duplicated leftmost options
@@ -357,7 +421,11 @@ func deduplicateVMOption(oldLines []string, newLines []string, predicate func(l,
357
421
return result
358
422
}
359
423
360
- func updateVMOptions (config * gitpod.GitpodConfig , alias string , content string ) string {
424
+ func updateVMOptions (
425
+ config * gitpod.GitpodConfig ,
426
+ alias string ,
427
+ // original vmoptions (inherited from $JETBRAINS_IDE_HOME/bin/idea64.vmoptions)
428
+ ideaVMOptionsLines []string ) []string {
361
429
// inspired by how intellij platform merge the VMOptions
362
430
// https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/openapi/application/ConfigImportHelper.java#L1115
363
431
filterFunc := func (l , r string ) bool {
@@ -369,8 +437,6 @@ func updateVMOptions(config *gitpod.GitpodConfig, alias string, content string)
369
437
strings .Split (l , "=" )[0 ] == strings .Split (r , "=" )[0 ]
370
438
return isEqual || isXmx || isXms || isXss || isXXOptions
371
439
}
372
- // original vmoptions (inherited from $JETBRAINS_IDE_HOME/bin/idea64.vmoptions)
373
- ideaVMOptionsLines := strings .Fields (content )
374
440
// Gitpod's default customization
375
441
gitpodVMOptions := []string {"-Dgtw.disable.exit.dialog=true" }
376
442
vmoptions := deduplicateVMOption (ideaVMOptionsLines , gitpodVMOptions , filterFunc )
@@ -393,8 +459,7 @@ func updateVMOptions(config *gitpod.GitpodConfig, alias string, content string)
393
459
}
394
460
}
395
461
396
- // vmoptions file should end with a newline
397
- return strings .Join (vmoptions , "\n " ) + "\n "
462
+ return vmoptions
398
463
}
399
464
400
465
/*
0 commit comments