diff --git a/src/vs/platform/extensions/common/abstractExtensionService.ts b/src/vs/platform/extensions/common/abstractExtensionService.ts index bb27a525222..b6b9f4fca70 100644 --- a/src/vs/platform/extensions/common/abstractExtensionService.ts +++ b/src/vs/platform/extensions/common/abstractExtensionService.ts @@ -78,6 +78,12 @@ export abstract class AbstractExtensionService imp }); } + public readExtensions(): TPromise { + return this.onReady().then(() => { + return this._registry.getAllExtensionDescriptions(); + }); + } + public getExtensionsStatus(): { [id: string]: IExtensionsStatus } { return null; } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index b3bbfb536be..79be650c93a 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -43,7 +43,7 @@ import * as vscode from 'vscode'; import * as paths from 'vs/base/common/paths'; import { realpathSync } from 'fs'; import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { MainContext, ExtHostContext, InstanceCollection } from './extHost.protocol'; +import { MainContext, ExtHostContext, InstanceCollection, IInitConfiguration } from './extHost.protocol'; export interface IExtensionApiFactory { @@ -53,7 +53,7 @@ export interface IExtensionApiFactory { /** * This method instantiates and returns the extension API surface */ -export function createApiFactory(threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService, telemetryService: ITelemetryService): IExtensionApiFactory { +export function createApiFactory(initDataConfiguration: IInitConfiguration, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService, telemetryService: ITelemetryService): IExtensionApiFactory { @@ -64,7 +64,7 @@ export function createApiFactory(threadService: IThreadService, extensionService const extHostDocumentSaveParticipant = col.define(ExtHostContext.ExtHostDocumentSaveParticipant).set(new ExtHostDocumentSaveParticipant(extHostDocuments, threadService.get(MainContext.MainThreadWorkspace))); const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set(new ExtHostEditors(threadService, extHostDocuments)); const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set(new ExtHostCommands(threadService, extHostEditors, extHostHeapService)); - const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration))); + const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initDataConfiguration)); const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set(new ExtHostDiagnostics(threadService)); const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics)); const extHostFileSystemEvent = col.define(ExtHostContext.ExtHostFileSystemEventService).set(new ExtHostFileSystemEventService()); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index bc7bf0c2e0a..a7d6157e15b 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -43,6 +43,10 @@ export interface IEnvironment { extensionTestsPath: string; } +export interface IInitConfiguration { + _initConfigurationBrand: void; +} + export interface IInitData { parentPid: number; environment: IEnvironment; @@ -50,6 +54,7 @@ export interface IInitData { workspace: IWorkspace; }; extensions: IExtensionDescription[]; + configuration: IInitConfiguration; } export interface InstanceSetter { @@ -213,7 +218,6 @@ export abstract class MainThreadWorkspaceShape { } export abstract class MainProcessExtensionServiceShape { - $onExtensionHostReady(extensionDescriptions: IExtensionDescription[]): TPromise { throw ni(); } $localShowMessage(severity: Severity, msg: string): void { throw ni(); } $onExtensionActivated(extensionId: string): void { throw ni(); } $onExtensionActivationFailed(extensionId: string): void { throw ni(); } diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index e2426909469..662c14b0a04 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -5,7 +5,6 @@ 'use strict'; import { mixin } from 'vs/base/common/objects'; -import { illegalState } from 'vs/base/common/errors'; import Event, { Emitter } from 'vs/base/common/event'; import { WorkspaceConfiguration } from 'vscode'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; @@ -14,13 +13,13 @@ import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/ export class ExtHostConfiguration extends ExtHostConfigurationShape { private _proxy: MainThreadConfigurationShape; - private _hasConfig: boolean; private _config: any; private _onDidChangeConfiguration = new Emitter(); - constructor(proxy: MainThreadConfigurationShape) { + constructor(proxy: MainThreadConfigurationShape, configuration: any) { super(); this._proxy = proxy; + this._config = configuration; } get onDidChangeConfiguration(): Event { @@ -29,14 +28,10 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { public $acceptConfigurationChanged(config: any) { this._config = config; - this._hasConfig = true; this._onDidChangeConfiguration.fire(undefined); } public getConfiguration(section?: string): WorkspaceConfiguration { - if (!this._hasConfig) { - throw illegalState('missing config'); - } const config = section ? ExtHostConfiguration._lookUp(section, this._config) diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 8a0f2016c00..5e2c54c7a1f 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -119,7 +119,7 @@ export class ExtHostExtensionService extends AbstractExtensionService { - // Wait for the main process to acknowledge its receival of the extensions descriptions - // before allowing extensions to be activated - this._triggerOnReady(); - }); - } - // -- overwriting AbstractExtensionService protected _showMessage(severity: Severity, msg: string): void { diff --git a/src/vs/workbench/api/node/mainThreadConfiguration.ts b/src/vs/workbench/api/node/mainThreadConfiguration.ts index b707f4e6a47..39a5c31f124 100644 --- a/src/vs/workbench/api/node/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/node/mainThreadConfiguration.ts @@ -25,7 +25,6 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape { this._configurationEditingService = configurationEditingService; const proxy = threadService.get(ExtHostContext.ExtHostConfiguration); this._toDispose = configurationService.onDidUpdateConfiguration(event => proxy.$acceptConfigurationChanged(event.config)); - proxy.$acceptConfigurationChanged(configurationService.getConfiguration()); } public dispose(): void { diff --git a/src/vs/workbench/api/node/mainThreadExtensionService.ts b/src/vs/workbench/api/node/mainThreadExtensionService.ts index eb2f6954a0c..436d492117e 100644 --- a/src/vs/workbench/api/node/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/node/mainThreadExtensionService.ts @@ -7,7 +7,7 @@ import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService'; -import { IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions'; +import { IExtensionsRuntimeService, IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; import { IMessageService } from 'vs/platform/message/common/message'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; @@ -53,7 +53,8 @@ export class MainProcessExtensionService extends AbstractExtensionService this._onExtensionDescriptions(extensionDescriptions)); } private _handleMessage(msg: IMessage) { @@ -124,7 +127,7 @@ export class MainProcessExtensionService extends AbstractExtensionService { + private _onExtensionDescriptions(extensionDescriptions: IExtensionDescription[]): void { this._registry.registerExtensions(extensionDescriptions); let availableExtensions = this._registry.getAllExtensionDescriptions(); @@ -135,7 +138,6 @@ export class MainProcessExtensionService extends AbstractExtensionService(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[]): void { diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 258ffbab5d3..429b4b21bc3 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -296,12 +296,13 @@ export class WorkbenchShell { serviceCollection.set(IExtensionsRuntimeService, extensionsRuntimeService); disposables.add(extensionsRuntimeService); - const extensionHostProcessWorker = this.startExtensionHost(instantiationService); + const extensionHostProcessWorker = instantiationService.createInstance(ExtensionHostProcessWorker); this.threadService = instantiationService.createInstance(MainThreadService, extensionHostProcessWorker.messagingProtocol); serviceCollection.set(IThreadService, this.threadService); const extensionService = instantiationService.createInstance(MainProcessExtensionService); serviceCollection.set(IExtensionService, extensionService); + extensionHostProcessWorker.start(extensionService); serviceCollection.set(ICommandService, new CommandService(instantiationService, extensionService)); @@ -454,12 +455,6 @@ export class WorkbenchShell { this.workbench.layout(); } - private startExtensionHost(instantiationService: InstantiationService): ExtensionHostProcessWorker { - const extensionHostProcessWorker: ExtensionHostProcessWorker = instantiationService.createInstance(ExtensionHostProcessWorker); - extensionHostProcessWorker.start(); - return extensionHostProcessWorker; - } - public joinCreation(): TPromise { return this.workbench.joinCreation(); } diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index 29216aec2f9..1cf968a7acc 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -55,7 +55,7 @@ export class ExtensionHostMain { this._extensionService = new ExtHostExtensionService(initData.extensions, threadService, telemetryService, { _serviceBrand: 'optionalArgs', workspaceStoragePath }); // Create the ext host API - const factory = createApiFactory(threadService, this._extensionService, this._contextService, telemetryService); + const factory = createApiFactory(initData.configuration, threadService, this._extensionService, this._contextService, telemetryService); defineAPI(factory, this._extensionService); } @@ -107,7 +107,7 @@ export class ExtensionHostMain { } public start(): TPromise { - return this.registerExtensions(); + return this.handleEagerExtensions().then(() => this.handleExtensionTests()); } public terminate(): void { @@ -142,11 +142,6 @@ export class ExtensionHostMain { }, 1000); } - private registerExtensions(): TPromise { - this._extensionService.registrationDone(); - return this.handleEagerExtensions().then(() => this.handleExtensionTests()); - } - // Handle "eager" activation extensions private handleEagerExtensions(): TPromise { this._extensionService.activateByEvent('*').then(null, (err) => { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 3feb264e282..f2f1b0671d9 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -22,11 +22,12 @@ import { ipcRenderer as ipc } from 'electron'; 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 { IExtensionsRuntimeService } from 'vs/platform/extensions/common/extensions'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import Event, { Emitter } from 'vs/base/common/event'; import { createQueuedSender, IQueuedSender } from 'vs/base/node/processes'; -import { IInitData } from 'vs/workbench/api/node/extHost.protocol'; +import { IInitData, IInitConfiguration } from 'vs/workbench/api/node/extHost.protocol'; +import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService'; +import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; @@ -58,6 +59,8 @@ export class ExtensionHostProcessWorker { return this._onMessage.event; } + private extensionService: MainProcessExtensionService; + constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService, @@ -65,7 +68,7 @@ export class ExtensionHostProcessWorker { @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService private instantiationService: IInstantiationService, @IEnvironmentService private environmentService: IEnvironmentService, - @IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { // handle extension host lifecycle a bit special when we know we are developing an extension that runs inside this.isExtensionDevelopmentHost = !!environmentService.extensionDevelopmentPath; @@ -78,7 +81,8 @@ export class ExtensionHostProcessWorker { lifecycleService.onShutdown(() => this.terminate()); } - public start(): void { + public start(extensionService: MainProcessExtensionService): void { + this.extensionService = extensionService; let opts: any = { env: objects.mixin(objects.clone(process.env), { AMD_ENTRYPOINT: 'vs/workbench/node/extensionHostProcess', @@ -200,7 +204,7 @@ export class ExtensionHostProcessWorker { if (this.initializeTimer) { window.clearTimeout(this.initializeTimer); } - this.extensionsRuntimeService.getExtensions().then(extensionDescriptors => { + this.extensionService.readExtensions().then((extensionDescriptions) => { let initData: IInitData = { parentPid: process.pid, environment: { @@ -213,7 +217,8 @@ export class ExtensionHostProcessWorker { contextService: { workspace: this.contextService.getWorkspace() }, - extensions: extensionDescriptors + extensions: extensionDescriptions, + configuration: this.configurationService.getConfiguration() }; this.extensionHostProcessQueuedSender.send(stringify(initData)); }); diff --git a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts index 4eb053a2380..50839cabd00 100644 --- a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts @@ -25,15 +25,9 @@ suite('ExtHostConfiguration', function () { if (!shape) { shape = new class extends MainThreadConfigurationShape { }; } - const result = new ExtHostConfiguration(shape); - result.$acceptConfigurationChanged(data); - return result; + return new ExtHostConfiguration(shape, data); } - test('check illegal state', function () { - assert.throws(() => new ExtHostConfiguration(new class extends MainThreadConfigurationShape { }).getConfiguration('foo')); - }); - test('udate / section to key', function () { const shape = new RecordingShape();