From aa2fd63b49bea3b5c4b5668b1079dcb235822484 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Mon, 10 Oct 2016 15:29:36 +0200 Subject: [PATCH] #13357 Move extensions scanning to renderer --- src/vs/workbench/node/extensionHostMain.ts | 73 ++----------- .../thread/electron-browser/threadService.ts | 101 +++++++++++++++--- 2 files changed, 95 insertions(+), 79 deletions(-) diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index d7384ef57aa..d84cdf3d357 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -10,10 +10,8 @@ import * as crypto from 'crypto'; import nls = require('vs/nls'); import pfs = require('vs/base/node/pfs'); -import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; import paths = require('vs/base/common/paths'); -import pkg from 'vs/platform/package'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ExtHostAPIImplementation, defineAPI } from 'vs/workbench/api/node/extHost.api.impl'; @@ -21,14 +19,9 @@ import { IMainProcessExtHostIPC } from 'vs/platform/extensions/common/ipcRemoteC import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostThreadService } from 'vs/workbench/services/thread/common/extHostThreadService'; import { RemoteTelemetryService } from 'vs/workbench/api/node/extHostTelemetry'; -import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints'; import { IWorkspaceContextService, WorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import * as errors from 'vs/base/common/errors'; -const DIRNAME = URI.parse(require.toUrl('./')).fsPath; -const BASE_PATH = paths.normalize(paths.join(DIRNAME, '../../../..')); -const BUILTIN_EXTENSIONS_PATH = paths.join(BASE_PATH, 'extensions'); - export interface IEnvironment { appSettingsHome: string; disableExtensions: boolean; @@ -44,6 +37,7 @@ export interface IInitData { workspace: any; options: any; }; + extensions: IExtensionDescription[]; } const nativeExit = process.exit.bind(process); @@ -65,11 +59,13 @@ export class ExtensionHostMain { private _contextService: IWorkspaceContextService; private _environment: IEnvironment; private _extensionService: ExtHostExtensionService; + private _extensions: IExtensionDescription[]; constructor(remoteCom: IMainProcessExtHostIPC, initData: IInitData) { this._isTerminating = false; this._environment = initData.environment; + this._extensions = initData.extensions; this._contextService = new WorkspaceContextService(initData.contextService.workspace); const workspaceStoragePath = this._getOrCreateWorkspaceStoragePath(); @@ -80,16 +76,6 @@ export class ExtensionHostMain { this._extensionService = new ExtHostExtensionService(threadService, telemetryService, { _serviceBrand: 'optionalArgs', workspaceStoragePath }); - // Connect to shared process services - /* - const channel = sharedProcessClient.getChannel('extensions'); - const extensionsService = new ExtensionManagementChannelClient(channel); - if (false && false) { - // TODO: what to do with the ExtensionManagementChannelClient? - console.log(extensionsService); - } - */ - // Create the ext host API defineAPI(new ExtHostAPIImplementation(threadService, this._extensionService, this._contextService, telemetryService)); } @@ -142,7 +128,7 @@ export class ExtensionHostMain { } public start(): TPromise { - return this.readExtensions(); + return this.registerExtensions(); } public terminate(): void { @@ -177,53 +163,10 @@ export class ExtensionHostMain { }, 1000); } - private readExtensions(): TPromise { - let collector = new MessagesCollector(); - - return ExtensionHostMain.scanExtensions(collector, BUILTIN_EXTENSIONS_PATH, !this._environment.disableExtensions ? this._environment.userExtensionsHome : void 0, !this._environment.disableExtensions ? this._environment.extensionDevelopmentPath : void 0, pkg.version) - .then(null, err => { - collector.error('', err); - return []; - }) - .then(extensions => { - // Register & Signal done - ExtensionsRegistry.registerExtensions(extensions); - this._extensionService.registrationDone(collector.getMessages()); - }) - .then(() => this.handleEagerExtensions()) - .then(() => this.handleExtensionTests()); - } - - private static scanExtensions(collector: MessagesCollector, builtinExtensionsPath: string, userInstallPath: string, extensionDevelopmentPath: string, version: string): TPromise { - const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, builtinExtensionsPath, true); - const userExtensions = !userInstallPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, userInstallPath, false); - const developedExtensions = !extensionDevelopmentPath ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, extensionDevelopmentPath, false); - - return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((_: IExtensionDescription[][]) => { - let builtinExtensions = _[0]; - let userExtensions = _[1]; - let developedExtensions = _[2]; - - let result: { [extensionId: string]: IExtensionDescription; } = {}; - builtinExtensions.forEach((builtinExtension) => { - result[builtinExtension.id] = builtinExtension; - }); - userExtensions.forEach((userExtension) => { - if (result.hasOwnProperty(userExtension.id)) { - collector.warn(userExtension.extensionFolderPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); - } - result[userExtension.id] = userExtension; - }); - developedExtensions.forEach(developedExtension => { - collector.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); - if (result.hasOwnProperty(developedExtension.id)) { - collector.warn(developedExtension.extensionFolderPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); - } - result[developedExtension.id] = developedExtension; - }); - - return Object.keys(result).map(name => result[name]); - }); + private registerExtensions(): TPromise { + ExtensionsRegistry.registerExtensions(this._extensions); + this._extensionService.registrationDone([]); + return this.handleEagerExtensions().then(() => this.handleExtensionTests()); } // Handle "eager" activation extensions diff --git a/src/vs/workbench/services/thread/electron-browser/threadService.ts b/src/vs/workbench/services/thread/electron-browser/threadService.ts index 03537d6d797..f6f2dfd34fb 100644 --- a/src/vs/workbench/services/thread/electron-browser/threadService.ts +++ b/src/vs/workbench/services/thread/electron-browser/threadService.ts @@ -6,6 +6,8 @@ 'use strict'; import * as nls from 'vs/nls'; +import pkg from 'vs/platform/package'; +import paths = require('vs/base/common/paths'); import { toErrorMessage } from 'vs/base/common/errorMessage'; import { stringify } from 'vs/base/common/marshalling'; import * as objects from 'vs/base/common/objects'; @@ -26,11 +28,17 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions'; +import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints'; export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; export const EXTENSION_TERMINATE_BROADCAST_CHANNEL = 'vscode:extensionTerminate'; +const DIRNAME = URI.parse(require.toUrl('./')).fsPath; +const BASE_PATH = paths.normalize(paths.join(DIRNAME, '../../../../../..')); +const BUILTIN_EXTENSIONS_PATH = paths.join(BASE_PATH, 'extensions'); + // Enable to see detailed message communication between window and extension host const logExtensionHostCommunication = false; @@ -243,22 +251,64 @@ class ExtensionHostProcessManager { if (this.initializeTimer) { window.clearTimeout(this.initializeTimer); } - - let initPayload = stringify({ - parentPid: process.pid, - environment: { - appSettingsHome: this.environmentService.appSettingsHome, - disableExtensions: this.environmentService.disableExtensions, - userExtensionsHome: this.environmentService.extensionsPath, - extensionDevelopmentPath: this.environmentService.extensionDevelopmentPath, - extensionTestsPath: this.environmentService.extensionTestsPath - }, - contextService: { - workspace: this.contextService.getWorkspace() - } + this.scanExtensions().then(extensionDescriptors => { + let initPayload = stringify({ + parentPid: process.pid, + environment: { + appSettingsHome: this.environmentService.appSettingsHome, + disableExtensions: this.environmentService.disableExtensions, + userExtensionsHome: this.environmentService.extensionsPath, + extensionDevelopmentPath: this.environmentService.extensionDevelopmentPath, + extensionTestsPath: this.environmentService.extensionTestsPath + }, + contextService: { + workspace: this.contextService.getWorkspace() + }, + extensions: extensionDescriptors + }); + this.extensionHostProcessHandle.send(initPayload); }); + } + + private scanExtensions(): TPromise { + const collector = new MessagesCollector(); + const version = pkg.version; + const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, BUILTIN_EXTENSIONS_PATH, true); + const userExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, this.environmentService.extensionsPath, false); + const developedExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionDevelopmentPath ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, this.environmentService.extensionDevelopmentPath, false); + const isDev = !this.environmentService.isBuilt || !!this.environmentService.extensionDevelopmentPath; + + return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => { + let builtinExtensions = extensionDescriptions[0]; + let userExtensions = extensionDescriptions[1]; + let developedExtensions = extensionDescriptions[2]; + + let result: { [extensionId: string]: IExtensionDescription; } = {}; + builtinExtensions.forEach((builtinExtension) => { + result[builtinExtension.id] = builtinExtension; + }); + userExtensions.forEach((userExtension) => { + if (result.hasOwnProperty(userExtension.id)) { + collector.warn(userExtension.extensionFolderPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); + } + result[userExtension.id] = userExtension; + }); + developedExtensions.forEach(developedExtension => { + collector.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); + if (result.hasOwnProperty(developedExtension.id)) { + collector.warn(developedExtension.extensionFolderPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); + } + result[developedExtension.id] = developedExtension; + }); - this.extensionHostProcessHandle.send(initPayload); + return Object.keys(result).map(name => result[name]); + }).then(null, err => { + collector.error('', err); + return []; + }).then(extensions => { + collector.getMessages().forEach(entry => this._handleMessage(entry, isDev)); + return extensions; + }); } private logExtensionHostMessage(logEntry: ILogEntry) { @@ -369,4 +419,27 @@ class ExtensionHostProcessManager { event.veto(TPromise.timeout(100 /* wait a bit for IPC to get delivered */).then(() => false)); } } + + private _handleMessage(message: IMessage, isDev: boolean): void { + let messageShown = false; + if (message.type === Severity.Error || message.type === Severity.Warning) { + if (isDev) { + // Only show nasty intrusive messages if doing extension development. + this.messageService.show(message.type, (message.source ? '[' + message.source + ']: ' : '') + message.message); + messageShown = true; + } + } + if (!messageShown) { + switch (message.type) { + case Severity.Error: + console.error(message); + break; + case Severity.Warning: + console.warn(message); + break; + default: + console.log(message); + } + } + } } \ No newline at end of file -- GitLab