@@ -47,8 +47,13 @@ import { getPathLabel } from 'vs/base/common/labels';
4747import { IURLService } from 'vs/platform/url/common/url' ;
4848import { URLChannel } from 'vs/platform/url/common/urlIpc' ;
4949import { URLService } from 'vs/platform/url/electron-main/urlService' ;
50+ import { ITelemetryService , NullTelemetryService } from 'vs/platform/telemetry/common/telemetry' ;
51+ import { ITelemetryAppenderChannel , TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc' ;
52+ import { TelemetryService , ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService' ;
53+ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties' ;
54+ import { getDelayedChannel } from 'vs/base/parts/ipc/common/ipc' ;
5055import product from 'vs/platform/product' ;
51-
56+ import pkg from 'vs/platform/package' ;
5257import * as fs from 'original-fs' ;
5358import * as cp from 'child_process' ;
5459import * as path from 'path' ;
@@ -73,6 +78,7 @@ function quit(accessor: ServicesAccessor, arg?: any) {
7378 process . exit ( exitCode ) ; // in main, process.exit === app.exit
7479}
7580
81+ // TODO@Joao wow this is huge, clean up!
7682function main ( accessor : ServicesAccessor , mainIpcServer : Server , userEnv : platform . IProcessEnvironment ) : void {
7783 const instantiationService = accessor . get ( IInstantiationService ) ;
7884 const logService = accessor . get ( ILogService ) ;
@@ -130,10 +136,6 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
130136 const electronIpcServer = new ElectronIPCServer ( ) ;
131137
132138 // Register Electron IPC services
133- const updateService = accessor . get ( IUpdateService ) ;
134- const updateChannel = new UpdateChannel ( updateService ) ;
135- electronIpcServer . registerChannel ( 'update' , updateChannel ) ;
136-
137139 const urlService = accessor . get ( IURLService ) ;
138140 const urlChannel = instantiationService . createInstance ( URLChannel , urlService ) ;
139141 electronIpcServer . registerChannel ( 'url' , urlChannel ) ;
@@ -151,123 +153,150 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
151153
152154 let sharedProcessDisposable ;
153155
154- spawnSharedProcess ( initData , options ) . done ( disposable => {
156+ const sharedProcess = spawnSharedProcess ( initData , options ) . then ( disposable => {
155157 sharedProcessDisposable = disposable ;
156-
157- connect ( environmentService . sharedIPCHandle , 'main' )
158- . done ( client => client . registerChannel ( 'windowEvent' , windowEventChannel ) ) ;
158+ return connect ( environmentService . sharedIPCHandle , 'main' ) ;
159159 } ) ;
160160
161- // Make sure we associate the program with the app user model id
162- // This will help Windows to associate the running program with
163- // any shortcut that is pinned to the taskbar and prevent showing
164- // two icons in the taskbar for the same app.
165- if ( platform . isWindows && product . win32AppUserModelId ) {
166- app . setAppUserModelId ( product . win32AppUserModelId ) ;
161+ // Create a new service collection, because the telemetry service
162+ // requires a connection to shared process, which was only established
163+ // now.
164+ const services = new ServiceCollection ( ) ;
165+ services . set ( IUpdateService , new SyncDescriptor ( UpdateService ) ) ;
166+
167+ if ( environmentService . isBuilt && ! environmentService . extensionDevelopmentPath && ! ! product . enableTelemetry ) {
168+ const channel = getDelayedChannel < ITelemetryAppenderChannel > ( sharedProcess . then ( c => c . getChannel ( 'telemetryAppender' ) ) ) ;
169+ const appender = new TelemetryAppenderClient ( channel ) ;
170+ const commonProperties = resolveCommonProperties ( product . commit , pkg . version ) ;
171+ const piiPaths = [ environmentService . appRoot , environmentService . extensionsPath ] ;
172+ const config : ITelemetryServiceConfig = { appender, commonProperties, piiPaths } ;
173+ services . set ( ITelemetryService , new SyncDescriptor ( TelemetryService , config ) ) ;
174+ } else {
175+ services . set ( ITelemetryService , NullTelemetryService ) ;
167176 }
168177
169- function dispose ( ) {
170- if ( mainIpcServer ) {
171- mainIpcServer . dispose ( ) ;
172- mainIpcServer = null ;
173- }
178+ const instantiationService2 = instantiationService . createChild ( services ) ;
174179
175- if ( sharedProcessDisposable ) {
176- sharedProcessDisposable . dispose ( ) ;
177- }
180+ instantiationService2 . invokeFunction ( accessor => {
181+ // Register more Electron IPC services
182+ const updateService = accessor . get ( IUpdateService ) ;
183+ const updateChannel = new UpdateChannel ( updateService ) ;
184+ electronIpcServer . registerChannel ( 'update' , updateChannel ) ;
178185
179- if ( windowsMutex ) {
180- windowsMutex . release ( ) ;
181- }
186+ // Register windowEvent
187+ sharedProcess . done ( client => client . registerChannel ( 'windowEvent' , windowEventChannel ) ) ;
182188
183- configurationService . dispose ( ) ;
184- }
189+ // Make sure we associate the program with the app user model id
190+ // This will help Windows to associate the running program with
191+ // any shortcut that is pinned to the taskbar and prevent showing
192+ // two icons in the taskbar for the same app.
193+ if ( platform . isWindows && product . win32AppUserModelId ) {
194+ app . setAppUserModelId ( product . win32AppUserModelId ) ;
195+ }
185196
186- // Dispose on app quit
187- app . on ( 'will-quit' , ( ) => {
188- logService . log ( 'App#will-quit: disposing resources' ) ;
197+ function dispose ( ) {
198+ if ( mainIpcServer ) {
199+ mainIpcServer . dispose ( ) ;
200+ mainIpcServer = null ;
201+ }
189202
190- dispose ( ) ;
191- } ) ;
203+ if ( sharedProcessDisposable ) {
204+ sharedProcessDisposable . dispose ( ) ;
205+ }
192206
193- // Dispose on vscode:exit
194- ipc . on ( 'vscode:exit' , ( event , code : number ) => {
195- logService . log ( 'IPC#vscode:exit' , code ) ;
207+ if ( windowsMutex ) {
208+ windowsMutex . release ( ) ;
209+ }
196210
197- dispose ( ) ;
198- process . exit ( code ) ; // in main, process.exit === app.exit
199- } ) ;
211+ configurationService . dispose ( ) ;
212+ }
200213
201- // Lifecycle
202- lifecycleService . ready ( ) ;
214+ // Dispose on app quit
215+ app . on ( 'will-quit' , ( ) => {
216+ logService . log ( 'App#will-quit: disposing resources' ) ;
203217
204- // Propagate to clients
205- windowsMainService . ready ( userEnv ) ;
218+ dispose ( ) ;
219+ } ) ;
206220
207- // Install Menu
208- const menu = instantiationService . createInstance ( VSCodeMenu ) ;
209- menu . ready ( ) ;
221+ // Dispose on vscode:exit
222+ ipc . on ( 'vscode:exit' , ( event , code : number ) => {
223+ logService . log ( 'IPC#vscode:exit' , code ) ;
210224
211- // Install JumpList on Windows
212- if ( platform . isWindows ) {
213- const jumpList : Electron . JumpListCategory [ ] = [ ] ;
214-
215- // Tasks
216- jumpList . push ( {
217- type : 'tasks' ,
218- items : [
219- {
220- type : 'task' ,
221- title : nls . localize ( 'newWindow' , "New Window" ) ,
222- description : nls . localize ( 'newWindowDesc' , "Opens a new window" ) ,
223- program : process . execPath ,
224- args : '-n' , // force new window
225- iconPath : process . execPath ,
226- iconIndex : 0
227- }
228- ]
225+ dispose ( ) ;
226+ process . exit ( code ) ; // in main, process.exit === app.exit
229227 } ) ;
230228
231- // Recent Folders
232- const folders = windowsMainService . getRecentPathsList ( ) . folders ;
233- if ( folders . length > 0 ) {
229+ // Lifecycle
230+ lifecycleService . ready ( ) ;
231+
232+ // Propagate to clients
233+ windowsMainService . ready ( userEnv ) ;
234+
235+ // Install Menu
236+ const menu = instantiationService2 . createInstance ( VSCodeMenu ) ;
237+ menu . ready ( ) ;
238+
239+ // Install JumpList on Windows
240+ if ( platform . isWindows ) {
241+ const jumpList : Electron . JumpListCategory [ ] = [ ] ;
242+
243+ // Tasks
234244 jumpList . push ( {
235- type : 'custom' ,
236- name : 'Recent Folders' ,
237- items : windowsMainService . getRecentPathsList ( ) . folders . slice ( 0 , 7 /* limit number of entries here */ ) . map ( folder => {
238- return < Electron . JumpListItem > {
245+ type : 'tasks' ,
246+ items : [
247+ {
239248 type : 'task' ,
240- title : getPathLabel ( folder ) ,
241- description : nls . localize ( 'folderDesc ' , "{0} {1}" , path . basename ( folder ) , getPathLabel ( path . dirname ( folder ) ) ) ,
249+ title : nls . localize ( 'newWindow' , "New Window" ) ,
250+ description : nls . localize ( 'newWindowDesc ' , "Opens a new window" ) ,
242251 program : process . execPath ,
243- args : folder , // open folder,
244- iconPath : 'explorer.exe' , // simulate folder icon
252+ args : '-n' , // force new window
253+ iconPath : process . execPath ,
245254 iconIndex : 0
246- } ;
247- } )
255+ }
256+ ]
248257 } ) ;
249- }
250258
251- // Recent
252- jumpList . push ( {
253- type : 'recent' // this enables to show files in the "recent" category
254- } ) ;
259+ // Recent Folders
260+ const folders = windowsMainService . getRecentPathsList ( ) . folders ;
261+ if ( folders . length > 0 ) {
262+ jumpList . push ( {
263+ type : 'custom' ,
264+ name : 'Recent Folders' ,
265+ items : windowsMainService . getRecentPathsList ( ) . folders . slice ( 0 , 7 /* limit number of entries here */ ) . map ( folder => {
266+ return < Electron . JumpListItem > {
267+ type : 'task' ,
268+ title : getPathLabel ( folder ) ,
269+ description : nls . localize ( 'folderDesc' , "{0} {1}" , path . basename ( folder ) , getPathLabel ( path . dirname ( folder ) ) ) ,
270+ program : process . execPath ,
271+ args : folder , // open folder,
272+ iconPath : 'explorer.exe' , // simulate folder icon
273+ iconIndex : 0
274+ } ;
275+ } )
276+ } ) ;
277+ }
255278
256- try {
257- app . setJumpList ( jumpList ) ;
258- } catch ( error ) {
259- logService . log ( '#setJumpList' , error ) ; // since setJumpList is relatively new API, make sure to guard for errors
279+ // Recent
280+ jumpList . push ( {
281+ type : 'recent' // this enables to show files in the "recent" category
282+ } ) ;
283+
284+ try {
285+ app . setJumpList ( jumpList ) ;
286+ } catch ( error ) {
287+ logService . log ( '#setJumpList' , error ) ; // since setJumpList is relatively new API, make sure to guard for errors
288+ }
260289 }
261- }
262290
263- // Open our first window
264- if ( environmentService . args [ 'new-window' ] && environmentService . args . _ . length === 0 ) {
265- windowsMainService . open ( { cli : environmentService . args , forceNewWindow : true , forceEmpty : true } ) ; // new window if "-n" was used without paths
266- } else if ( global . macOpenFiles && global . macOpenFiles . length && ( ! environmentService . args . _ || ! environmentService . args . _ . length ) ) {
267- windowsMainService . open ( { cli : environmentService . args , pathsToOpen : global . macOpenFiles } ) ; // mac: open-file event received on startup
268- } else {
269- windowsMainService . open ( { cli : environmentService . args , forceNewWindow : environmentService . args [ 'new-window' ] , diffMode : environmentService . args . diff } ) ; // default: read paths from cli
270- }
291+ // Open our first window
292+ if ( environmentService . args [ 'new-window' ] && environmentService . args . _ . length === 0 ) {
293+ windowsMainService . open ( { cli : environmentService . args , forceNewWindow : true , forceEmpty : true } ) ; // new window if "-n" was used without paths
294+ } else if ( global . macOpenFiles && global . macOpenFiles . length && ( ! environmentService . args . _ || ! environmentService . args . _ . length ) ) {
295+ windowsMainService . open ( { cli : environmentService . args , pathsToOpen : global . macOpenFiles } ) ; // mac: open-file event received on startup
296+ } else {
297+ windowsMainService . open ( { cli : environmentService . args , forceNewWindow : environmentService . args [ 'new-window' ] , diffMode : environmentService . args . diff } ) ; // default: read paths from cli
298+ }
299+ } ) ;
271300}
272301
273302function setupIPC ( accessor : ServicesAccessor ) : TPromise < Server > {
@@ -437,19 +466,7 @@ function createPaths(environmentService: IEnvironmentService): TPromise<any> {
437466 return TPromise . join ( paths . map ( p => mkdirp ( p ) ) ) as TPromise < any > ;
438467}
439468
440- function start ( ) : void {
441- let args : ParsedArgs ;
442-
443- try {
444- args = parseMainProcessArgv ( process . argv ) ;
445- args = validatePaths ( args ) ;
446- } catch ( err ) {
447- console . error ( err . message ) ;
448- process . exit ( 1 ) ;
449- return ;
450- }
451-
452- // TODO: isolate
469+ function createServices ( args ) : IInstantiationService {
453470 const services = new ServiceCollection ( ) ;
454471
455472 services . set ( IEnvironmentService , new SyncDescriptor ( EnvironmentService , args , process . execPath ) ) ;
@@ -460,10 +477,24 @@ function start(): void {
460477 services . set ( IStorageService , new SyncDescriptor ( StorageService ) ) ;
461478 services . set ( IConfigurationService , new SyncDescriptor ( ConfigurationService ) ) ;
462479 services . set ( IRequestService , new SyncDescriptor ( RequestService ) ) ;
463- services . set ( IUpdateService , new SyncDescriptor ( UpdateService ) ) ;
464480 services . set ( IURLService , new SyncDescriptor ( URLService , args [ 'open-url' ] ) ) ;
465481
466- const instantiationService = new InstantiationService ( services ) ;
482+ return new InstantiationService ( services ) ;
483+ }
484+
485+ function start ( ) : void {
486+ let args : ParsedArgs ;
487+
488+ try {
489+ args = parseMainProcessArgv ( process . argv ) ;
490+ args = validatePaths ( args ) ;
491+ } catch ( err ) {
492+ console . error ( err . message ) ;
493+ process . exit ( 1 ) ;
494+ return ;
495+ }
496+
497+ const instantiationService = createServices ( args ) ;
467498
468499 // On some platforms we need to manually read from the global environment variables
469500 // and assign them to the process environment (e.g. when doubleclick app on Mac)
0 commit comments