@@ -11,12 +11,21 @@ import { ProxyHttpProvider } from "./app/proxy"
11
11
import { StaticHttpProvider } from "./app/static"
12
12
import { UpdateHttpProvider } from "./app/update"
13
13
import { VscodeHttpProvider } from "./app/vscode"
14
- import { Args , bindAddrFromAllSources , optionDescriptions , parse , readConfigFile , setDefaults } from "./cli"
15
14
import { coderCloudBind } from "./coder-cloud"
15
+ import {
16
+ Args ,
17
+ bindAddrFromAllSources ,
18
+ optionDescriptions ,
19
+ parse ,
20
+ readConfigFile ,
21
+ setDefaults ,
22
+ shouldOpenInExistingInstance ,
23
+ shouldRunVsCodeCli ,
24
+ } from "./cli"
16
25
import { AuthType , HttpServer , HttpServerOptions } from "./http"
17
26
import { loadPlugins } from "./plugin"
18
27
import { generateCertificate , hash , humanPath , open } from "./util"
19
- import { ipcMain , wrap } from "./wrapper"
28
+ import { ipcMain , WrapperProcess } from "./wrapper"
20
29
21
30
let pkg : { version ?: string ; commit ?: string } = { }
22
31
try {
28
37
const version = pkg . version || "development"
29
38
const commit = pkg . commit || "development"
30
39
40
+ export const runVsCodeCli = ( args : Args ) : void => {
41
+ logger . debug ( "forking vs code cli..." )
42
+ const vscode = cp . fork ( path . resolve ( __dirname , "../../lib/vscode/out/vs/server/fork" ) , [ ] , {
43
+ env : {
44
+ ...process . env ,
45
+ CODE_SERVER_PARENT_PID : process . pid . toString ( ) ,
46
+ } ,
47
+ } )
48
+ vscode . once ( "message" , ( message : any ) => {
49
+ logger . debug ( "got message from VS Code" , field ( "message" , message ) )
50
+ if ( message . type !== "ready" ) {
51
+ logger . error ( "Unexpected response waiting for ready response" , field ( "type" , message . type ) )
52
+ process . exit ( 1 )
53
+ }
54
+ const send : CliMessage = { type : "cli" , args }
55
+ vscode . send ( send )
56
+ } )
57
+ vscode . once ( "error" , ( error ) => {
58
+ logger . error ( "Got error from VS Code" , field ( "error" , error ) )
59
+ process . exit ( 1 )
60
+ } )
61
+ vscode . on ( "exit" , ( code ) => process . exit ( code || 0 ) )
62
+ }
63
+
64
+ export const openInExistingInstance = async ( args : Args , socketPath : string ) : Promise < void > => {
65
+ const pipeArgs : OpenCommandPipeArgs & { fileURIs : string [ ] } = {
66
+ type : "open" ,
67
+ folderURIs : [ ] ,
68
+ fileURIs : [ ] ,
69
+ forceReuseWindow : args [ "reuse-window" ] ,
70
+ forceNewWindow : args [ "new-window" ] ,
71
+ }
72
+
73
+ const isDir = async ( path : string ) : Promise < boolean > => {
74
+ try {
75
+ const st = await fs . stat ( path )
76
+ return st . isDirectory ( )
77
+ } catch ( error ) {
78
+ return false
79
+ }
80
+ }
81
+
82
+ for ( let i = 0 ; i < args . _ . length ; i ++ ) {
83
+ const fp = path . resolve ( args . _ [ i ] )
84
+ if ( await isDir ( fp ) ) {
85
+ pipeArgs . folderURIs . push ( fp )
86
+ } else {
87
+ pipeArgs . fileURIs . push ( fp )
88
+ }
89
+ }
90
+
91
+ if ( pipeArgs . forceNewWindow && pipeArgs . fileURIs . length > 0 ) {
92
+ logger . error ( "--new-window can only be used with folder paths" )
93
+ process . exit ( 1 )
94
+ }
95
+
96
+ if ( pipeArgs . folderURIs . length === 0 && pipeArgs . fileURIs . length === 0 ) {
97
+ logger . error ( "Please specify at least one file or folder" )
98
+ process . exit ( 1 )
99
+ }
100
+
101
+ const vscode = http . request (
102
+ {
103
+ path : "/" ,
104
+ method : "POST" ,
105
+ socketPath,
106
+ } ,
107
+ ( response ) => {
108
+ response . on ( "data" , ( message ) => {
109
+ logger . debug ( "got message from VS Code" , field ( "message" , message . toString ( ) ) )
110
+ } )
111
+ } ,
112
+ )
113
+ vscode . on ( "error" , ( error : unknown ) => {
114
+ logger . error ( "got error from VS Code" , field ( "error" , error ) )
115
+ } )
116
+ vscode . write ( JSON . stringify ( pipeArgs ) )
117
+ vscode . end ( )
118
+ }
119
+
31
120
const main = async ( args : Args , configArgs : Args ) : Promise < void > => {
32
121
if ( args . link ) {
33
122
// If we're being exposed to the cloud, we listen on a random address and disable auth.
@@ -92,7 +181,7 @@ const main = async (args: Args, configArgs: Args): Promise<void> => {
92
181
93
182
await loadPlugins ( httpServer , args )
94
183
95
- ipcMain ( ) . onDispose ( ( ) => {
184
+ ipcMain . onDispose ( ( ) => {
96
185
httpServer . dispose ( ) . then ( ( errors ) => {
97
186
errors . forEach ( ( error ) => logger . error ( error . message ) )
98
187
} )
@@ -132,7 +221,9 @@ const main = async (args: Args, configArgs: Args): Promise<void> => {
132
221
if ( serverAddress && ! options . socket && args . open ) {
133
222
// The web socket doesn't seem to work if browsing with 0.0.0.0.
134
223
const openAddress = serverAddress . replace ( / : \/ \/ 0 .0 .0 .0 / , "://localhost" )
135
- await open ( openAddress ) . catch ( console . error )
224
+ await open ( openAddress ) . catch ( ( error : Error ) => {
225
+ logger . error ( "Failed to open" , field ( "address" , openAddress ) , field ( "error" , error ) )
226
+ } )
136
227
logger . info ( `Opened ${ openAddress } ` )
137
228
}
138
229
@@ -141,27 +232,32 @@ const main = async (args: Args, configArgs: Args): Promise<void> => {
141
232
await coderCloudBind ( serverAddress ! , args . link . value )
142
233
} catch ( err ) {
143
234
logger . error ( err . message )
144
- ipcMain ( ) . exit ( 1 )
235
+ ipcMain . exit ( 1 )
145
236
}
146
237
}
147
238
}
148
239
149
240
async function entry ( ) : Promise < void > {
150
- const tryParse = async ( ) : Promise < [ Args , Args ] > => {
151
- try {
152
- const cliArgs = parse ( process . argv . slice ( 2 ) )
153
- const configArgs = await readConfigFile ( cliArgs . config )
154
- // This prioritizes the flags set in args over the ones in the config file.
155
- let args = Object . assign ( configArgs , cliArgs )
156
- args = await setDefaults ( args )
157
- return [ args , configArgs ]
158
- } catch ( error ) {
159
- console . error ( error . message )
160
- process . exit ( 1 )
161
- }
241
+ const tryParse = async ( ) : Promise < [ Args , Args , Args ] > => {
242
+ const cliArgs = parse ( process . argv . slice ( 2 ) )
243
+ const configArgs = await readConfigFile ( cliArgs . config )
244
+ // This prioritizes the flags set in args over the ones in the config file.
245
+ let args = Object . assign ( configArgs , cliArgs )
246
+ args = await setDefaults ( args )
247
+ return [ args , cliArgs , configArgs ]
248
+ }
249
+
250
+ const [ args , cliArgs , configArgs ] = await tryParse ( )
251
+
252
+ // There's no need to check flags like --help or to spawn in an existing
253
+ // instance for the child process because these would have already happened in
254
+ // the parent and the child wouldn't have been spawned.
255
+ if ( ipcMain . isChild ) {
256
+ await ipcMain . handshake ( )
257
+ ipcMain . preventExit ( )
258
+ return main ( args , configArgs )
162
259
}
163
260
164
- const [ args , configArgs ] = await tryParse ( )
165
261
if ( args . help ) {
166
262
console . log ( "code-server" , version , commit )
167
263
console . log ( "" )
@@ -171,7 +267,10 @@ async function entry(): Promise<void> {
171
267
optionDescriptions ( ) . forEach ( ( description ) => {
172
268
console . log ( "" , description )
173
269
} )
174
- } else if ( args . version ) {
270
+ return
271
+ }
272
+
273
+ if ( args . version ) {
175
274
if ( args . json ) {
176
275
console . log ( {
177
276
codeServer : version ,
@@ -181,83 +280,23 @@ async function entry(): Promise<void> {
181
280
} else {
182
281
console . log ( version , commit )
183
282
}
184
- process . exit ( 0 )
185
- } else if ( args [ "list-extensions" ] || args [ "install-extension" ] || args [ "uninstall-extension" ] ) {
186
- logger . debug ( "forking vs code cli..." )
187
- const vscode = cp . fork ( path . resolve ( __dirname , "../../lib/vscode/out/vs/server/fork" ) , [ ] , {
188
- env : {
189
- ...process . env ,
190
- CODE_SERVER_PARENT_PID : process . pid . toString ( ) ,
191
- } ,
192
- } )
193
- vscode . once ( "message" , ( message : any ) => {
194
- logger . debug ( "Got message from VS Code" , field ( "message" , message ) )
195
- if ( message . type !== "ready" ) {
196
- logger . error ( "Unexpected response waiting for ready response" )
197
- process . exit ( 1 )
198
- }
199
- const send : CliMessage = { type : "cli" , args }
200
- vscode . send ( send )
201
- } )
202
- vscode . once ( "error" , ( error ) => {
203
- logger . error ( error . message )
204
- process . exit ( 1 )
205
- } )
206
- vscode . on ( "exit" , ( code ) => process . exit ( code || 0 ) )
207
- } else if ( process . env . VSCODE_IPC_HOOK_CLI ) {
208
- const pipeArgs : OpenCommandPipeArgs = {
209
- type : "open" ,
210
- folderURIs : [ ] ,
211
- forceReuseWindow : args [ "reuse-window" ] ,
212
- forceNewWindow : args [ "new-window" ] ,
213
- }
214
- const isDir = async ( path : string ) : Promise < boolean > => {
215
- try {
216
- const st = await fs . stat ( path )
217
- return st . isDirectory ( )
218
- } catch ( error ) {
219
- return false
220
- }
221
- }
222
- for ( let i = 0 ; i < args . _ . length ; i ++ ) {
223
- const fp = path . resolve ( args . _ [ i ] )
224
- if ( await isDir ( fp ) ) {
225
- pipeArgs . folderURIs . push ( fp )
226
- } else {
227
- if ( ! pipeArgs . fileURIs ) {
228
- pipeArgs . fileURIs = [ ]
229
- }
230
- pipeArgs . fileURIs . push ( fp )
231
- }
232
- }
233
- if ( pipeArgs . forceNewWindow && pipeArgs . fileURIs && pipeArgs . fileURIs . length > 0 ) {
234
- logger . error ( "new-window can only be used with folder paths" )
235
- process . exit ( 1 )
236
- }
237
- if ( pipeArgs . folderURIs . length === 0 && ( ! pipeArgs . fileURIs || pipeArgs . fileURIs . length === 0 ) ) {
238
- logger . error ( "Please specify at least one file or folder argument" )
239
- process . exit ( 1 )
240
- }
241
- const vscode = http . request (
242
- {
243
- path : "/" ,
244
- method : "POST" ,
245
- socketPath : process . env [ "VSCODE_IPC_HOOK_CLI" ] ,
246
- } ,
247
- ( res ) => {
248
- res . on ( "data" , ( message ) => {
249
- logger . debug ( "Got message from VS Code" , field ( "message" , message . toString ( ) ) )
250
- } )
251
- } ,
252
- )
253
- vscode . on ( "error" , ( err ) => {
254
- logger . debug ( "Got error from VS Code" , field ( "error" , err ) )
255
- } )
256
- vscode . write ( JSON . stringify ( pipeArgs ) )
257
- vscode . end ( )
258
- } else {
259
- wrap ( ( ) => main ( args , configArgs ) )
283
+ return
284
+ }
285
+
286
+ if ( shouldRunVsCodeCli ( args ) ) {
287
+ return runVsCodeCli ( args )
260
288
}
289
+
290
+ const socketPath = await shouldOpenInExistingInstance ( cliArgs )
291
+ if ( socketPath ) {
292
+ return openInExistingInstance ( args , socketPath )
293
+ }
294
+
295
+ const wrapper = new WrapperProcess ( require ( "../../package.json" ) . version )
296
+ return wrapper . start ( )
261
297
}
262
298
263
- entry ( )
299
+ entry ( ) . catch ( ( error ) => {
300
+ logger . error ( error . message )
301
+ ipcMain . exit ( error )
302
+ } )
0 commit comments