@@ -117,40 +117,26 @@ export class CodeServer {
117117 * directories.
118118 */
119119 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.
122120 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+ ] )
124131 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- ]
145132 this . logger . debug ( "spawning `node " + args . join ( " " ) + "`" )
146133 const proc = cp . spawn ( "node" , args , {
147134 cwd : path . join ( __dirname , "../../.." ) ,
148135 env : {
149136 ...process . env ,
150137 ...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.
154140 VSCODE_IPC_HOOK_CLI : "" ,
155141 PASSWORD ,
156142 } ,
@@ -173,11 +159,15 @@ export class CodeServer {
173159 reject ( error )
174160 } )
175161
162+ // Tracks when the HTTP and session servers are ready.
163+ let httpAddress : string | undefined
164+ let sessionAddress : string | undefined
165+
176166 let resolved = false
177167 proc . stdout . setEncoding ( "utf8" )
178168 onLine ( proc , ( line ) => {
179169 // 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
181171 // reject.
182172 timer . reset ( )
183173
@@ -186,20 +176,69 @@ export class CodeServer {
186176 if ( resolved ) {
187177 return
188178 }
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 ] + ) \/ ? $ / )
190181 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.
192183 // 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" ) {
195193 resolved = true
196194 timer . dispose ( )
197- resolve ( { process : proc , address } )
195+ this . logger . debug ( `code-server is ready: ${ httpAddress } ${ sessionAddress } ` )
196+ resolve ( { process : proc , address : httpAddress } )
198197 }
199198 } )
200199 } )
201200 }
202201
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+
203242 /**
204243 * Close the code-server process.
205244 */
@@ -364,6 +403,13 @@ export class CodeServerPage {
364403 await this . waitForTab ( file )
365404 }
366405
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+
367413 /**
368414 * Wait for a tab to open for the specified file.
369415 */
0 commit comments