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