@@ -117,40 +117,26 @@ export class CodeServer {
117
117
* directories.
118
118
*/
119
119
private async spawn ( ) : Promise < CodeServerProcess > {
120
- // This will be used both as the workspace and data directory to ensure
121
- // instances don't bleed into each other.
122
120
const dir = await this . createWorkspace ( )
123
-
121
+ const args = await this . argsWithDefaults ( [
122
+ "--auth" ,
123
+ "none" ,
124
+ // The workspace to open.
125
+ ...( this . args . includes ( "--ignore-last-opened" ) ? [ ] : [ dir ] ) ,
126
+ ...this . args ,
127
+ // Using port zero will spawn on a random port.
128
+ "--bind-addr" ,
129
+ "127.0.0.1:0" ,
130
+ ] )
124
131
return new Promise ( ( resolve , reject ) => {
125
- const args = [
126
- this . entry ,
127
- "--extensions-dir" ,
128
- path . join ( dir , "extensions" ) ,
129
- "--auth" ,
130
- "none" ,
131
- // The workspace to open.
132
- ...( this . args . includes ( "--ignore-last-opened" ) ? [ ] : [ dir ] ) ,
133
- ...this . args ,
134
- // Using port zero will spawn on a random port.
135
- "--bind-addr" ,
136
- "127.0.0.1:0" ,
137
- // Setting the XDG variables would be easier and more thorough but the
138
- // modules we import ignores those variables for non-Linux operating
139
- // systems so use these flags instead.
140
- "--config" ,
141
- path . join ( dir , "config.yaml" ) ,
142
- "--user-data-dir" ,
143
- dir ,
144
- ]
145
132
this . logger . debug ( "spawning `node " + args . join ( " " ) + "`" )
146
133
const proc = cp . spawn ( "node" , args , {
147
134
cwd : path . join ( __dirname , "../../.." ) ,
148
135
env : {
149
136
...process . env ,
150
137
...this . env ,
151
- // Set to empty string to prevent code-server from
152
- // using the existing instance when running the e2e tests
153
- // from an integrated terminal.
138
+ // Prevent code-server from using the existing instance when running
139
+ // the e2e tests from an integrated terminal.
154
140
VSCODE_IPC_HOOK_CLI : "" ,
155
141
PASSWORD ,
156
142
} ,
@@ -173,11 +159,15 @@ export class CodeServer {
173
159
reject ( error )
174
160
} )
175
161
162
+ // Tracks when the HTTP and session servers are ready.
163
+ let httpAddress : string | undefined
164
+ let sessionAddress : string | undefined
165
+
176
166
let resolved = false
177
167
proc . stdout . setEncoding ( "utf8" )
178
168
onLine ( proc , ( line ) => {
179
169
// As long as we are actively getting input reset the timer. If we stop
180
- // getting input and still have not found the address the timer will
170
+ // getting input and still have not found the addresses the timer will
181
171
// reject.
182
172
timer . reset ( )
183
173
@@ -186,20 +176,69 @@ export class CodeServer {
186
176
if ( resolved ) {
187
177
return
188
178
}
189
- const match = line . trim ( ) . match ( / H T T P S ? s e r v e r l i s t e n i n g o n ( h t t p s ? : \/ \/ [ . : \d ] + ) \/ ? $ / )
179
+
180
+ let match = line . trim ( ) . match ( / H T T P S ? s e r v e r l i s t e n i n g o n ( h t t p s ? : \/ \/ [ . : \d ] + ) \/ ? $ / )
190
181
if ( match ) {
191
- // Cookies don't seem to work on IP address so swap to localhost.
182
+ // Cookies don't seem to work on IP addresses so swap to localhost.
192
183
// TODO: Investigate whether this is a bug with code-server.
193
- const address = match [ 1 ] . replace ( "127.0.0.1" , "localhost" )
194
- this . logger . debug ( `spawned on ${ address } ` )
184
+ httpAddress = match [ 1 ] . replace ( "127.0.0.1" , "localhost" )
185
+ }
186
+
187
+ match = line . trim ( ) . match ( / S e s s i o n s e r v e r l i s t e n i n g o n ( .+ ) $ / )
188
+ if ( match ) {
189
+ sessionAddress = match [ 1 ]
190
+ }
191
+
192
+ if ( typeof httpAddress !== "undefined" && typeof sessionAddress !== "undefined" ) {
195
193
resolved = true
196
194
timer . dispose ( )
197
- resolve ( { process : proc , address } )
195
+ this . logger . debug ( `code-server is ready: ${ httpAddress } ${ sessionAddress } ` )
196
+ resolve ( { process : proc , address : httpAddress } )
198
197
}
199
198
} )
200
199
} )
201
200
}
202
201
202
+ /**
203
+ * Execute a short-lived command.
204
+ */
205
+ async run ( args : string [ ] ) : Promise < void > {
206
+ args = await this . argsWithDefaults ( args )
207
+ this . logger . debug ( "executing `node " + args . join ( " " ) + "`" )
208
+ await util . promisify ( cp . exec ) ( "node " + args . join ( " " ) , {
209
+ cwd : path . join ( __dirname , "../../.." ) ,
210
+ env : {
211
+ ...process . env ,
212
+ ...this . env ,
213
+ // Prevent code-server from using the existing instance when running
214
+ // the e2e tests from an integrated terminal.
215
+ VSCODE_IPC_HOOK_CLI : "" ,
216
+ } ,
217
+ } )
218
+ }
219
+
220
+ /**
221
+ * Combine arguments with defaults.
222
+ */
223
+ private async argsWithDefaults ( args : string [ ] ) : Promise < string [ ] > {
224
+ // This will be used both as the workspace and data directory to ensure
225
+ // instances don't bleed into each other.
226
+ const dir = await this . workspaceDir
227
+ return [
228
+ this . entry ,
229
+ "--extensions-dir" ,
230
+ path . join ( dir , "extensions" ) ,
231
+ ...args ,
232
+ // Setting the XDG variables would be easier and more thorough but the
233
+ // modules we import ignores those variables for non-Linux operating
234
+ // systems so use these flags instead.
235
+ "--config" ,
236
+ path . join ( dir , "config.yaml" ) ,
237
+ "--user-data-dir" ,
238
+ dir ,
239
+ ]
240
+ }
241
+
203
242
/**
204
243
* Close the code-server process.
205
244
*/
@@ -364,6 +403,13 @@ export class CodeServerPage {
364
403
await this . waitForTab ( file )
365
404
}
366
405
406
+ /**
407
+ * Open a file through an external command.
408
+ */
409
+ async openFileExternally ( file : string ) {
410
+ await this . codeServer . run ( [ "--reuse-window" , file ] )
411
+ }
412
+
367
413
/**
368
414
* Wait for a tab to open for the specified file.
369
415
*/
0 commit comments