diff --git a/src/vs/workbench/api/browser/mainThreadExtensionService.ts b/src/vs/workbench/api/browser/mainThreadExtensionService.ts index 1b9316170ad..41309ab2bd9 100644 --- a/src/vs/workbench/api/browser/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/browser/mainThreadExtensionService.ts @@ -26,6 +26,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { URI, UriComponents } from 'vs/base/common/uri'; import { FileAccess } from 'vs/base/common/network'; +import { IExtensionDescriptionDelta } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; @extHostNamedCustomer(MainContext.MainThreadExtensionService) export class MainThreadExtensionService implements MainThreadExtensionServiceShape { @@ -204,8 +205,8 @@ class ExtensionHostProxy implements IExtensionHostProxy { const uriComponents = await this._actual.$getCanonicalURI(remoteAuthority, uri); return (uriComponents ? URI.revive(uriComponents) : uriComponents); } - startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise { - return this._actual.$startExtensionHost(enabledExtensionIds); + startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise { + return this._actual.$startExtensionHost(extensionsDelta); } extensionTestsExecute(): Promise { return this._actual.$extensionTestsExecute(); @@ -225,8 +226,8 @@ class ExtensionHostProxy implements IExtensionHostProxy { updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise { return this._actual.$updateRemoteConnectionData(connectionData); } - deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise { - return this._actual.$deltaExtensions(toAdd, toRemove); + deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise { + return this._actual.$deltaExtensions(extensionsDelta); } test_latency(n: number): Promise { return this._actual.$test_latency(n); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8ccdce38e97..4787ccb401b 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -62,7 +62,7 @@ import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescrip import { TypeHierarchyItem } from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy'; import { AuthenticationProviderInformation, AuthenticationSession, AuthenticationSessionsChangeEvent } from 'vs/workbench/services/authentication/common/authentication'; import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn'; -import { IStaticWorkspaceData } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { IExtensionDescriptionDelta, IStaticWorkspaceData } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy'; import { ActivationKind, ExtensionActivationReason, MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions'; import { createProxyIdentifier, Dto, IRPCProtocol, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier'; @@ -1434,7 +1434,7 @@ export interface ExtHostExtensionServiceShape { * Returns `null` if no resolver for `remoteAuthority` is found. */ $getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise; - $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; + $startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise; $extensionTestsExecute(): Promise; $extensionTestsExit(code: number): Promise; $activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise; @@ -1442,7 +1442,7 @@ export interface ExtHostExtensionServiceShape { $setRemoteEnvironment(env: { [key: string]: string | null }): Promise; $updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise; - $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise; + $deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise; $test_latency(n: number): Promise; $test_up(b: VSBuffer): Promise; diff --git a/src/vs/workbench/api/common/extHostExtensionService.ts b/src/vs/workbench/api/common/extHostExtensionService.ts index a60f54b98be..71ab9fb23aa 100644 --- a/src/vs/workbench/api/common/extHostExtensionService.ts +++ b/src/vs/workbench/api/common/extHostExtensionService.ts @@ -13,12 +13,12 @@ import { TernarySearchTree } from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostExtensionServiceShape, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape } from 'vs/workbench/api/common/extHost.protocol'; -import { IExtensionHostInitData } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { IExtensionDescriptionDelta, IExtensionHostInitData } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration'; import { ActivatedExtension, EmptyExtension, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator'; import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { MissingExtensionDependency, ActivationKind, checkProposedApiEnabled, isProposedApiEnabled, ExtensionActivationReason } from 'vs/workbench/services/extensions/common/extensions'; +import { MissingExtensionDependency, ActivationKind, checkProposedApiEnabled, isProposedApiEnabled, ExtensionActivationReason, extensionIdentifiersArrayToSet } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import * as errors from 'vs/base/common/errors'; import type * as vscode from 'vscode'; @@ -100,7 +100,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme private readonly _readyToRunExtensions: Barrier; private readonly _eagerExtensionsActivated: Barrier; - protected readonly _registry: ExtensionDescriptionRegistry; + protected readonly _myRegistry: ExtensionDescriptionRegistry; + protected readonly _globalRegistry: ExtensionDescriptionRegistry; private readonly _storage: ExtHostStorage; private readonly _secretState: ExtHostSecretState; private readonly _storagePath: IExtensionStoragePaths; @@ -144,7 +145,11 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme this._readyToStartExtensionHost = new Barrier(); this._readyToRunExtensions = new Barrier(); this._eagerExtensionsActivated = new Barrier(); - this._registry = new ExtensionDescriptionRegistry(this._initData.extensions); + this._globalRegistry = new ExtensionDescriptionRegistry(this._initData.allExtensions); + const myExtensionsSet = extensionIdentifiersArrayToSet(this._initData.myExtensions); + this._myRegistry = new ExtensionDescriptionRegistry( + filterExtensions(this._globalRegistry, myExtensionsSet) + ); this._storage = new ExtHostStorage(this._extHostContext); this._secretState = new ExtHostSecretState(this._extHostContext); this._storagePath = storagePath; @@ -154,24 +159,33 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme [IExtHostSecretState, this._secretState] )); - const hostExtensions = new Set(); - this._initData.hostExtensions.forEach((extensionId) => hostExtensions.add(ExtensionIdentifier.toKey(extensionId))); + let resolvedExtensions: ExtensionIdentifier[] = []; + let hostExtensions: ExtensionIdentifier[] = []; + if (this._initData.remote.isRemote) { + resolvedExtensions = this._initData.allExtensions.filter(extension => !extension.main && !extension.browser).map(extension => extension.identifier); + hostExtensions = ( + this._initData.allExtensions + .filter(extension => !myExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier.value))) + .filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier) + ); + } + const hostExtensionsSet = extensionIdentifiersArrayToSet(hostExtensions); this._activator = this._register(new ExtensionsActivator( - this._registry, - this._initData.resolvedExtensions, - this._initData.hostExtensions, + this._myRegistry, + resolvedExtensions, + hostExtensions, { onExtensionActivationError: (extensionId: ExtensionIdentifier, error: Error, missingExtensionDependency: MissingExtensionDependency | null): void => { this._mainThreadExtensionsProxy.$onExtensionActivationError(extensionId, errors.transformErrorForSerialization(error), missingExtensionDependency); }, actualActivateExtension: async (extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise => { - if (hostExtensions.has(ExtensionIdentifier.toKey(extensionId))) { + if (hostExtensionsSet.has(ExtensionIdentifier.toKey(extensionId))) { await this._mainThreadExtensionsProxy.$activateExtension(extensionId, reason); return new HostExtension(); } - const extensionDescription = this._registry.getExtensionDescription(extensionId)!; + const extensionDescription = this._myRegistry.getExtensionDescription(extensionId)!; return this._activateExtension(extensionDescription, reason); } }, @@ -210,7 +224,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme let allPromises: Promise[] = []; try { - const allExtensions = this._registry.getAllExtensionDescriptions(); + const allExtensions = this._myRegistry.getAllExtensionDescriptions(); const allExtensionsIds = allExtensions.map(ext => ext.identifier); const activatedExtensions = allExtensionsIds.filter(id => this.isActivated(id)); @@ -293,7 +307,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme } public getExtensionRegistry(): Promise { - return this._readyToRunExtensions.wait().then(_ => this._registry); + return this._readyToRunExtensions.wait().then(_ => this._myRegistry); } public getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined { @@ -326,7 +340,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme return extUriBiasedIgnorePathCase.ignorePathCasing(key); }); // const tst = TernarySearchTree.forUris(key => true); - for (const ext of this._registry.getAllExtensionDescriptions()) { + for (const ext of this._myRegistry.getAllExtensionDescriptions()) { if (this._getEntryPoint(ext)) { const uri = await this._realPathExtensionUri(ext.extensionLocation); tst.set(uri, ext); @@ -572,7 +586,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme // startup is considered finished this._mainThreadExtensionsProxy.$setPerformanceMarks(performance.getMarks()); - for (const desc of this._registry.getAllExtensionDescriptions()) { + for (const desc of this._myRegistry.getAllExtensionDescriptions()) { if (desc.activationEvents) { for (const activationEvent of desc.activationEvents) { if (activationEvent === 'onStartupFinished') { @@ -607,7 +621,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme } return Promise.all( - this._registry.getAllExtensionDescriptions().map((desc) => { + this._myRegistry.getAllExtensionDescriptions().map((desc) => { return this._handleWorkspaceContainsEagerExtension(folders, desc); }) ).then(() => { }); @@ -816,8 +830,19 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme return result; } - public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise { - this._registry.keepOnly(enabledExtensionIds); + public $startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise { + extensionsDelta.toAdd.forEach((extension) => (extension).extensionLocation = URI.revive(extension.extensionLocation)); + this._globalRegistry.deltaExtensions(extensionsDelta.toAdd, extensionsDelta.toRemove); + + const myExtensions = extensionIdentifiersArrayToSet(this._myRegistry.getAllExtensionDescriptions().map(extension => extension.identifier)); + for (const extensionId of extensionsDelta.myToRemove) { + myExtensions.delete(ExtensionIdentifier.toKey(extensionId)); + } + for (const extensionId of extensionsDelta.myToAdd) { + myExtensions.add(ExtensionIdentifier.toKey(extensionId)); + } + this._myRegistry.set(filterExtensions(this._globalRegistry, myExtensions)); + return this._startExtensionHost(); } @@ -834,7 +859,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme public async $activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise { await this._readyToRunExtensions.wait(); - if (!this._registry.getExtensionDescription(extensionId)) { + if (!this._myRegistry.getExtensionDescription(extensionId)) { // unknown extension => ignore return false; } @@ -842,24 +867,36 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme return true; } - public async $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise { - toAdd.forEach((extension) => (extension).extensionLocation = URI.revive(extension.extensionLocation)); + public async $deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise { + extensionsDelta.toAdd.forEach((extension) => (extension).extensionLocation = URI.revive(extension.extensionLocation)); - const trie = await this.getExtensionPathIndex(); + this._globalRegistry.deltaExtensions(extensionsDelta.toAdd, extensionsDelta.toRemove); - await Promise.all(toRemove.map(async (extensionId) => { - const extensionDescription = this._registry.getExtensionDescription(extensionId); - if (extensionDescription) { - trie.delete(await this._realPathExtensionUri(extensionDescription.extensionLocation)); - } - })); + const myExtensions = extensionIdentifiersArrayToSet(this._myRegistry.getAllExtensionDescriptions().map(extension => extension.identifier)); + for (const extensionId of extensionsDelta.myToRemove) { + myExtensions.delete(ExtensionIdentifier.toKey(extensionId)); + } + for (const extensionId of extensionsDelta.myToAdd) { + myExtensions.add(ExtensionIdentifier.toKey(extensionId)); + } + this._myRegistry.set(filterExtensions(this._globalRegistry, myExtensions)); - await Promise.all(toAdd.map(async (extensionDescription) => { - const realpathUri = await this._realPathExtensionUri(extensionDescription.extensionLocation); - trie.set(realpathUri, extensionDescription); - })); + console.log(`TODO: update the extension path trie!`); + + // const trie = await this.getExtensionPathIndex(); + + // await Promise.all(toRemove.map(async (extensionId) => { + // const extensionDescription = this._myRegistry.getExtensionDescription(extensionId); + // if (extensionDescription) { + // trie.delete(await this._realPathExtensionUri(extensionDescription.extensionLocation)); + // } + // })); + + // await Promise.all(toAdd.map(async (extensionDescription) => { + // const realpathUri = await this._realPathExtensionUri(extensionDescription.extensionLocation); + // trie.set(realpathUri, extensionDescription); + // })); - this._registry.deltaExtensions(toAdd, toRemove); return Promise.resolve(undefined); } @@ -976,6 +1013,12 @@ export class Extension implements vscode.Ex } } +function filterExtensions(globalRegistry: ExtensionDescriptionRegistry, desiredExtensions: Set): IExtensionDescription[] { + return globalRegistry.getAllExtensionDescriptions().filter( + extension => desiredExtensions.has(ExtensionIdentifier.toKey(extension.identifier)) + ); +} + function getRemoteAuthorityPrefix(remoteAuthority: string): string { const plusIndex = remoteAuthority.indexOf('+'); if (plusIndex === -1) { diff --git a/src/vs/workbench/api/common/extensionHostMain.ts b/src/vs/workbench/api/common/extensionHostMain.ts index 99c7c7b08fd..0eabc9e29cc 100644 --- a/src/vs/workbench/api/common/extensionHostMain.ts +++ b/src/vs/workbench/api/common/extensionHostMain.ts @@ -120,7 +120,7 @@ export class ExtensionHostMain { } private static _transform(initData: IExtensionHostInitData, rpcProtocol: RPCProtocol): IExtensionHostInitData { - initData.extensions.forEach((ext) => (ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation))); + initData.allExtensions.forEach((ext) => (ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation))); initData.environment.appRoot = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appRoot)); const extDevLocs = initData.environment.extensionDevelopmentLocationURI; if (extDevLocs) { diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 481409b79d5..8521f23ca0a 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -72,7 +72,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { } // Module loading tricks - const interceptor = this._instaService.createInstance(NodeModuleRequireInterceptor, extensionApiFactory, this._registry); + const interceptor = this._instaService.createInstance(NodeModuleRequireInterceptor, extensionApiFactory, this._myRegistry); await interceptor.install(); performance.mark('code/extHost/didInitAPI'); diff --git a/src/vs/workbench/api/worker/extHostExtensionService.ts b/src/vs/workbench/api/worker/extHostExtensionService.ts index 68c7c834910..cc072dcdacd 100644 --- a/src/vs/workbench/api/worker/extHostExtensionService.ts +++ b/src/vs/workbench/api/worker/extHostExtensionService.ts @@ -44,7 +44,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService { // initialize API and register actors const apiFactory = this._instaService.invokeFunction(createApiFactoryAndRegisterActors); - this._fakeModules = this._instaService.createInstance(WorkerRequireInterceptor, apiFactory, this._registry); + this._fakeModules = this._instaService.createInstance(WorkerRequireInterceptor, apiFactory, this._myRegistry); await this._fakeModules.install(); performance.mark('code/extHost/didInitAPI'); diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index 42a05f2344a..8ebc2b75496 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -112,8 +112,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten const allExtensions = await this.getExtensions(); const localWebWorkerExtensions = this._filterByRunningLocation(allExtensions, desiredRunningLocation); return { - autoStart: true, - extensions: localWebWorkerExtensions + allExtensions: allExtensions, + myExtensions: localWebWorkerExtensions.map(extension => extension.identifier) }; } }; @@ -232,8 +232,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten extensionHostLogsPath: remoteEnv.extensionHostLogsPath, globalStorageHome: remoteEnv.globalStorageHome, workspaceStorageHome: remoteEnv.workspaceStorageHome, - extensions: remoteExtensions, - allExtensions: this._registry.getAllExtensionDescriptions() + allExtensions: this._registry.getAllExtensionDescriptions(), + myExtensions: remoteExtensions.map(extension => extension.identifier), }; } diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts index 85bff25d857..e67094778e7 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts @@ -12,11 +12,11 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as platform from 'vs/base/common/platform'; import * as dom from 'vs/base/browser/dom'; import { URI } from 'vs/base/common/uri'; -import { IExtensionHost, ExtensionHostLogFileName, LocalWebWorkerRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionHost, ExtensionHostLogFileName, LocalWebWorkerRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; import { IProductService } from 'vs/platform/product/common/productService'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { joinPath } from 'vs/base/common/resources'; @@ -30,11 +30,10 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { FileAccess } from 'vs/base/common/network'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { parentOriginHash } from 'vs/workbench/browser/webview'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; export interface IWebWorkerExtensionHostInitData { - readonly autoStart: boolean; - readonly extensions: IExtensionDescription[]; + readonly allExtensions: IExtensionDescription[]; + readonly myExtensions: ExtensionIdentifier[]; } export interface IWebWorkerExtensionHostDataProvider { @@ -45,7 +44,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost public readonly remoteAuthority = null; public readonly lazyStart: boolean; - public readonly extensions = new ExtensionDescriptionRegistry([]); + public readonly extensions = new ExtensionHostExtensions(); private readonly _onDidExit = this._register(new Emitter<[number, string | null]>()); public readonly onExit: Event<[number, string | null]> = this._onDidExit.event; @@ -267,7 +266,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost private async _createExtHostInitData(): Promise { const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); const workspace = this._contextService.getWorkspace(); - this.extensions.deltaExtensions(initData.extensions, []); + const deltaExtensions = this.extensions.set(initData.allExtensions, initData.myExtensions); return { commit: this._productService.commit, version: this._productService.version, @@ -289,14 +288,13 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost name: this._labelService.getWorkspaceLabel(workspace), transient: workspace.transient }, - resolvedExtensions: [], - hostExtensions: [], - extensions: this.extensions.getAllExtensionDescriptions(), + allExtensions: deltaExtensions.toAdd, + myExtensions: deltaExtensions.myToAdd, telemetryInfo, logLevel: this._logService.getLevel(), logsLocation: this._extensionHostLogsLocation, logFile: this._extensionHostLogFile, - autoStart: initData.autoStart, + autoStart: true, remote: { authority: this._environmentService.remoteAuthority, connectionData: null, diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 0334f7f0b99..fc7e02bdcfc 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -628,12 +628,10 @@ export abstract class AbstractExtensionService extends Disposable implements IEx await Promise.all(promises); } - private async _updateExtensionsOnExtHost(extensionHostManager: IExtensionHostManager, _toAdd: IExtensionDescription[], _toRemove: ExtensionIdentifier[], removedRunningLocation: Map): Promise { - const toAdd = filterByExtensionHostManager(_toAdd, this._runningLocation, extensionHostManager); - const toRemove = _filterByExtensionHostManager(_toRemove, extId => extId, removedRunningLocation, extensionHostManager); - if (toRemove.length > 0 || toAdd.length > 0) { - await extensionHostManager.deltaExtensions(toAdd, toRemove); - } + private async _updateExtensionsOnExtHost(extensionHostManager: IExtensionHostManager, toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[], removedRunningLocation: Map): Promise { + const myToAdd = filterByExtensionHostManager(toAdd, this._runningLocation, extensionHostManager); + const myToRemove = _filterByExtensionHostManager(toRemove, extId => extId, removedRunningLocation, extensionHostManager); + await extensionHostManager.deltaExtensions({ toRemove, toAdd, myToRemove, myToAdd: myToAdd.map(extension => extension.identifier) }); } public canAddExtension(extension: IExtensionDescription): boolean { diff --git a/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts b/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts index b3cb9b17813..274bc9c396e 100644 --- a/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts +++ b/src/vs/workbench/services/extensions/common/extensionDescriptionRegistry.ts @@ -61,10 +61,8 @@ export class ExtensionDescriptionRegistry { } } - public keepOnly(extensionIds: ExtensionIdentifier[]): void { - const toKeep = new Set(); - extensionIds.forEach(extensionId => toKeep.add(ExtensionIdentifier.toKey(extensionId))); - this._extensionDescriptions = this._extensionDescriptions.filter(extension => toKeep.has(ExtensionIdentifier.toKey(extension.identifier))); + public set(extensionDescriptions: IExtensionDescription[]) { + this._extensionDescriptions = extensionDescriptions; this._initialize(); this._onDidChange.fire(undefined); } diff --git a/src/vs/workbench/services/extensions/common/extensionHostManager.ts b/src/vs/workbench/services/extensions/common/extensionHostManager.ts index e0aff464773..eb4c4437b6a 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostManager.ts @@ -19,13 +19,14 @@ import { registerAction2, Action2 } from 'vs/platform/actions/common/actions'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StopWatch } from 'vs/base/common/stopwatch'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IExtensionHost, ExtensionHostKind, ActivationKind, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionHost, ExtensionHostKind, ActivationKind, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService, ExtensionRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; import { CATEGORIES } from 'vs/workbench/common/actions'; import { Barrier, timeout } from 'vs/base/common/async'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionHostProxy, IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy'; +import { IExtensionDescriptionDelta } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; // Enable to see detailed message communication between window and extension host const LOG_EXTENSION_HOST_COMMUNICATION = false; @@ -39,7 +40,7 @@ export interface IExtensionHostManager { dispose(): void; ready(): Promise; representsRunningLocation(runningLocation: ExtensionRunningLocation): boolean; - deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise; + deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise; containsExtension(extensionId: ExtensionIdentifier): boolean; activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise; activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise; @@ -50,7 +51,7 @@ export interface IExtensionHostManager { * Returns `null` if no resolver for `remoteAuthority` is found. */ getCanonicalURI(remoteAuthority: string, uri: URI): Promise; - start(enabledExtensionIds: ExtensionIdentifier[]): Promise; + start(allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): Promise; extensionTestsExecute(): Promise; extensionTestsSendExit(exitCode: number): Promise; setRemoteEnvironment(env: { [key: string]: string | null }): Promise; @@ -398,13 +399,13 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { return proxy.getCanonicalURI(remoteAuthority, uri); } - public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise { + public async start(allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): Promise { const proxy = await this._proxy; if (!proxy) { return; } - this._extensionHost.extensions.keepOnly(enabledExtensionIds); - return proxy.startExtensionHost(enabledExtensionIds); + const deltaExtensions = this._extensionHost.extensions.set(allExtensions, myExtensions); + return proxy.startExtensionHost(deltaExtensions); } public async extensionTestsExecute(): Promise { @@ -433,13 +434,13 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager { return this._extensionHost.runningLocation.equals(runningLocation); } - public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise { + public async deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise { const proxy = await this._proxy; if (!proxy) { return; } - this._extensionHost.extensions.deltaExtensions(toAdd, toRemove); - return proxy.deltaExtensions(toAdd, toRemove); + this._extensionHost.extensions.delta(extensionsDelta); + return proxy.deltaExtensions(extensionsDelta); } public containsExtension(extensionId: ExtensionIdentifier): boolean { @@ -468,6 +469,7 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost private readonly _extensionHost: IExtensionHost; private _startCalled: Barrier; private _actual: ExtensionHostManager | null; + private _lazyStartExtensions: ExtensionHostExtensions | null; public get kind(): ExtensionHostKind { return this._extensionHost.runningLocation.kind; @@ -485,6 +487,7 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost this.onDidExit = extensionHost.onExit; this._startCalled = new Barrier(); this._actual = null; + this._lazyStartExtensions = null; } private _createActual(reason: string): ExtensionHostManager { @@ -500,7 +503,7 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost return this._actual; } const actual = this._createActual(reason); - await actual.start([]); + await actual.start([], []); return actual; } @@ -513,13 +516,17 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost public representsRunningLocation(runningLocation: ExtensionRunningLocation): boolean { return this._extensionHost.runningLocation.equals(runningLocation); } - public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise { + public async deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise { await this._startCalled.wait(); - const extensionHostAlreadyStarted = Boolean(this._actual); - const shouldStartExtensionHost = (toAdd.length > 0); - if (extensionHostAlreadyStarted || shouldStartExtensionHost) { - const actual = await this._getOrCreateActualAndStart(`contains ${toAdd.length} new extension(s) (installed or enabled): ${toAdd.map(ext => ext.identifier.value)}`); - return actual.deltaExtensions(toAdd, toRemove); + if (this._actual) { + return this._actual.deltaExtensions(extensionsDelta); + } + this._lazyStartExtensions!.delta(extensionsDelta); + if (extensionsDelta.myToAdd.length > 0) { + const actual = this._createActual(`contains ${extensionsDelta.myToAdd.length} new extension(s) (installed or enabled): ${extensionsDelta.myToAdd.map(extId => extId.value)}`); + const { toAdd, myToAdd } = this._lazyStartExtensions!.toDelta(); + actual.start(toAdd, myToAdd); + return; } } public containsExtension(extensionId: ExtensionIdentifier): boolean { @@ -582,15 +589,17 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost } throw new Error(`Cannot resolve canonical URI`); } - public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise { - if (enabledExtensionIds.length > 0) { + public async start(allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): Promise { + if (myExtensions.length > 0) { // there are actual extensions, so let's launch the extension host - const actual = this._createActual(`contains ${enabledExtensionIds.length} extension(s): ${enabledExtensionIds.map(extId => extId.value)}.`); - const result = actual.start(enabledExtensionIds); + const actual = this._createActual(`contains ${myExtensions.length} extension(s): ${myExtensions.map(extId => extId.value)}.`); + const result = actual.start(allExtensions, myExtensions); this._startCalled.open(); return result; } - // there are no actual extensions + // there are no actual extensions running, store extensions in `this._lazyStartExtensions` + this._lazyStartExtensions = new ExtensionHostExtensions(); + this._lazyStartExtensions.set(allExtensions, myExtensions); this._startCalled.open(); } public async extensionTestsExecute(): Promise { diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index a090dced1df..ca72df6f92f 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -10,15 +10,21 @@ import { LogLevel } from 'vs/platform/log/common/log'; import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; +export interface IExtensionDescriptionDelta { + readonly toRemove: ExtensionIdentifier[]; + readonly toAdd: IExtensionDescription[]; + readonly myToRemove: ExtensionIdentifier[]; + readonly myToAdd: ExtensionIdentifier[]; +} + export interface IExtensionHostInitData { version: string; commit?: string; parentPid: number; environment: IEnvironment; workspace?: IStaticWorkspaceData | null; - resolvedExtensions: ExtensionIdentifier[]; - hostExtensions: ExtensionIdentifier[]; - extensions: IExtensionDescription[]; + allExtensions: IExtensionDescription[]; + myExtensions: ExtensionIdentifier[]; telemetryInfo: ITelemetryInfo; logLevel: LogLevel; logsLocation: URI; diff --git a/src/vs/workbench/services/extensions/common/extensionHostProxy.ts b/src/vs/workbench/services/extensions/common/extensionHostProxy.ts index d021dda0f0d..b528989a727 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProxy.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProxy.ts @@ -5,8 +5,9 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { URI } from 'vs/base/common/uri'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { IExtensionDescriptionDelta } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ActivationKind, ExtensionActivationReason } from 'vs/workbench/services/extensions/common/extensions'; export interface IResolveAuthorityErrorResult { @@ -31,14 +32,14 @@ export interface IExtensionHostProxy { * Returns `null` if no resolver for `remoteAuthority` is found. */ getCanonicalURI(remoteAuthority: string, uri: URI): Promise; - startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise; + startExtensionHost(extensionsDelta: IExtensionDescriptionDelta): Promise; extensionTestsExecute(): Promise; extensionTestsExit(code: number): Promise; activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise; activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise; setRemoteEnvironment(env: { [key: string]: string | null }): Promise; updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise; - deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise; + deltaExtensions(extensionsDelta: IExtensionDescriptionDelta): Promise; test_latency(n: number): Promise; test_up(b: VSBuffer): Promise; test_down(size: number): Promise; diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index db9df68c5f6..1a564e9a491 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -13,7 +13,7 @@ import { getExtensionId, getGalleryExtensionId } from 'vs/platform/extensionMana import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { ApiProposalName } from 'vs/workbench/services/extensions/common/extensionsApiProposals'; import { IV8Profile } from 'vs/platform/profiling/common/profiling'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; +import { IExtensionDescriptionDelta } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; export const nullExtensionDescription = Object.freeze({ identifier: new ExtensionIdentifier('nullExtensionDescription'), @@ -150,10 +150,11 @@ export interface IExtensionHost { readonly remoteAuthority: string | null; readonly lazyStart: boolean; /** - * A collection of extensions that will execute or are executing on this extension host. + * A collection of extensions which includes information about which + * extension will execute or is executing on this extension host. * **NOTE**: this will reflect extensions correctly only after `start()` resolves. */ - readonly extensions: ExtensionDescriptionRegistry; + readonly extensions: ExtensionHostExtensions; readonly onExit: Event<[number, string | null]>; start(): Promise | null; @@ -162,6 +163,142 @@ export interface IExtensionHost { dispose(): void; } +export class ExtensionHostExtensions { + + private _allExtensions: IExtensionDescription[]; + private _myExtensions: ExtensionIdentifier[]; + + constructor() { + this._allExtensions = []; + this._myExtensions = []; + } + + public toDelta(): IExtensionDescriptionDelta { + return { + toRemove: [], + toAdd: this._allExtensions, + myToRemove: [], + myToAdd: this._myExtensions + }; + } + + public set(allExtensions: IExtensionDescription[], myExtensions: ExtensionIdentifier[]): IExtensionDescriptionDelta { + const toRemove: ExtensionIdentifier[] = []; + const toAdd: IExtensionDescription[] = []; + const myToRemove: ExtensionIdentifier[] = []; + const myToAdd: ExtensionIdentifier[] = []; + + const oldExtensionsMap = extensionDescriptionArrayToMap(this._allExtensions); + const newExtensionsMap = extensionDescriptionArrayToMap(allExtensions); + const extensionsAreTheSame = (a: IExtensionDescription, b: IExtensionDescription) => { + return ( + (a.extensionLocation.toString() === b.extensionLocation.toString()) + || (a.isBuiltin === b.isBuiltin) + || (a.isUserBuiltin === b.isUserBuiltin) + || (a.isUnderDevelopment === b.isUnderDevelopment) + ); + }; + + for (const oldExtension of this._allExtensions) { + const newExtension = newExtensionsMap.get(ExtensionIdentifier.toKey(oldExtension.identifier)); + if (!newExtension) { + toRemove.push(oldExtension.identifier); + oldExtensionsMap.delete(ExtensionIdentifier.toKey(oldExtension.identifier)); + continue; + } + if (!extensionsAreTheSame(oldExtension, newExtension)) { + // The new extension is different than the old one + // (e.g. maybe it executes in a different location) + toRemove.push(oldExtension.identifier); + oldExtensionsMap.delete(ExtensionIdentifier.toKey(oldExtension.identifier)); + continue; + } + } + for (const newExtension of allExtensions) { + const oldExtension = oldExtensionsMap.get(ExtensionIdentifier.toKey(newExtension.identifier)); + if (!oldExtension) { + toAdd.push(newExtension); + continue; + } + if (!extensionsAreTheSame(oldExtension, newExtension)) { + // The new extension is different than the old one + // (e.g. maybe it executes in a different location) + toRemove.push(oldExtension.identifier); + oldExtensionsMap.delete(ExtensionIdentifier.toKey(oldExtension.identifier)); + continue; + } + } + + const myOldExtensionsSet = extensionIdentifiersArrayToSet(this._myExtensions); + const myNewExtensionsSet = extensionIdentifiersArrayToSet(myExtensions); + for (const oldExtensionId of this._myExtensions) { + if (!myNewExtensionsSet.has(ExtensionIdentifier.toKey(oldExtensionId))) { + myToRemove.push(oldExtensionId); + } + } + for (const newExtensionId of myExtensions) { + if (!myOldExtensionsSet.has(ExtensionIdentifier.toKey(newExtensionId))) { + myToAdd.push(newExtensionId); + } + } + + const delta = { toRemove, toAdd, myToRemove, myToAdd }; + this.delta(delta); + return delta; + } + + public delta(extensionsDelta: IExtensionDescriptionDelta): void { + const { toRemove, toAdd, myToRemove, myToAdd } = extensionsDelta; + // First handle removals + const toRemoveSet = extensionIdentifiersArrayToSet(toRemove); + const myToRemoveSet = extensionIdentifiersArrayToSet(myToRemove); + for (let i = 0; i < this._allExtensions.length; i++) { + if (toRemoveSet.has(ExtensionIdentifier.toKey(this._allExtensions[i].identifier))) { + this._allExtensions.splice(i, 1); + i--; + } + } + for (let i = 0; i < this._myExtensions.length; i++) { + if (myToRemoveSet.has(ExtensionIdentifier.toKey(this._myExtensions[i]))) { + this._myExtensions.splice(i, 1); + i--; + } + } + // Then handle additions + for (const extension of toAdd) { + this._allExtensions.push(extension); + } + for (const extensionId of myToAdd) { + this._myExtensions.push(extensionId); + } + } + + public containsExtension(extensionId: ExtensionIdentifier): boolean { + for (const myExtensionId of this._myExtensions) { + if (ExtensionIdentifier.equals(myExtensionId, extensionId)) { + return true; + } + } + return false; + } +} + +export function extensionIdentifiersArrayToSet(extensionIds: ExtensionIdentifier[]): Set { + const result = new Set(); + for (const extensionId of extensionIds) { + result.add(ExtensionIdentifier.toKey(extensionId)); + } + return result; +} + +function extensionDescriptionArrayToMap(extensions: IExtensionDescription[]): Map { + const result = new Map(); + for (const extension of extensions) { + result.set(ExtensionIdentifier.toKey(extension.identifier), extension); + } + return result; +} + export function isProposedApiEnabled(extension: IExtensionDescription, proposal: ApiProposalName): boolean { if (!extension.enabledApiProposals) { return false; diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts index bd382d7f168..b6eb37647f8 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHost.ts @@ -25,10 +25,9 @@ import { ISignService } from 'vs/platform/sign/common/sign'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; import { createMessageOfType, isMessageOfType, MessageType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; -import { ExtensionHostLogFileName, IExtensionHost, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionHostExtensions, ExtensionHostLogFileName, IExtensionHost, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle'; import { Extensions, IOutputChannelRegistry } from 'vs/workbench/services/output/common/output'; @@ -39,8 +38,8 @@ export interface IRemoteExtensionHostInitData { readonly extensionHostLogsPath: URI; readonly globalStorageHome: URI; readonly workspaceStorageHome: URI; - readonly extensions: IExtensionDescription[]; readonly allExtensions: IExtensionDescription[]; + readonly myExtensions: ExtensionIdentifier[]; } export interface IRemoteExtensionHostDataProvider { @@ -52,7 +51,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { public readonly remoteAuthority: string; public readonly lazyStart = false; - public readonly extensions = new ExtensionDescriptionRegistry([]); + public readonly extensions = new ExtensionHostExtensions(); private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>()); public readonly onExit: Event<[number, string | null]> = this._onExit.event; @@ -213,19 +212,8 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { private async _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise { const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); - - // Collect all identifiers for extension ids which can be considered "resolved" - const remoteExtensions = new Set(); - remoteInitData.extensions.forEach((extension) => remoteExtensions.add(ExtensionIdentifier.toKey(extension.identifier.value))); - - const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main && !extension.browser).map(extension => extension.identifier); - const hostExtensions = ( - remoteInitData.allExtensions - .filter(extension => !remoteExtensions.has(ExtensionIdentifier.toKey(extension.identifier.value))) - .filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier) - ); const workspace = this._contextService.getWorkspace(); - this.extensions.deltaExtensions(remoteInitData.extensions, []); + const deltaExtensions = this.extensions.set(remoteInitData.allExtensions, remoteInitData.myExtensions); return { commit: this._productService.commit, version: this._productService.version, @@ -253,9 +241,8 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost { authority: this._initDataProvider.remoteAuthority, connectionData: remoteInitData.connectionData }, - resolvedExtensions: resolvedExtensions, - hostExtensions: hostExtensions, - extensions: this.extensions.getAllExtensionDescriptions(), + allExtensions: deltaExtensions.toAdd, + myExtensions: deltaExtensions.myToAdd, telemetryInfo, logLevel: this._logService.getLevel(), logsLocation: remoteInitData.extensionHostLogsPath, diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 606ee940774..14be28cc18a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -162,18 +162,20 @@ export class ExtensionService extends AbstractExtensionService implements IExten // Here we load even extensions that would be disabled by workspace trust const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions(), /* ignore workspace trust */true); const runningLocation = this._determineRunningLocation(localExtensions); - const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation); + const myExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation); return { autoStart: false, - extensions: localProcessExtensions + allExtensions: localExtensions, + myExtensions: myExtensions.map(extension => extension.identifier) }; } else { // restart case const allExtensions = await this.getExtensions(); - const localProcessExtensions = this._filterByRunningLocation(allExtensions, desiredRunningLocation); + const myExtensions = this._filterByRunningLocation(allExtensions, desiredRunningLocation); return { autoStart: true, - extensions: localProcessExtensions + allExtensions: allExtensions, + myExtensions: myExtensions.map(extension => extension.identifier) }; } } @@ -561,8 +563,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten extensionHostLogsPath: remoteEnv.extensionHostLogsPath, globalStorageHome: remoteEnv.globalStorageHome, workspaceStorageHome: remoteEnv.workspaceStorageHome, - extensions: remoteExtensions, allExtensions: this._registry.getAllExtensionDescriptions(), + myExtensions: remoteExtensions.map(extension => extension.identifier), }); } @@ -583,7 +585,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten private _startExtensionHost(extensionHostManager: IExtensionHostManager, _extensions: IExtensionDescription[]): void { const extensions = this._filterByExtensionHostManager(_extensions, extensionHostManager); - extensionHostManager.start(extensions.map(extension => extension.identifier)); + extensionHostManager.start(this._registry.getAllExtensionDescriptions(), extensions.map(extension => extension.identifier)); } public _onExtensionHostExit(code: number): void { diff --git a/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts index 46a45aa5cf5..0f7f60bbc7d 100644 --- a/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/localProcessExtensionHost.ts @@ -29,11 +29,11 @@ import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { isUntitledWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { MessageType, createMessageOfType, isMessageOfType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { parseExtensionDevOptions } from '../common/extensionDevOptions'; import { VSBuffer } from 'vs/base/common/buffer'; import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; -import { IExtensionHost, ExtensionHostLogFileName, LocalProcessRunningLocation } from 'vs/workbench/services/extensions/common/extensions'; +import { IExtensionHost, ExtensionHostLogFileName, LocalProcessRunningLocation, ExtensionHostExtensions } from 'vs/workbench/services/extensions/common/extensions'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { joinPath } from 'vs/base/common/resources'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -43,12 +43,12 @@ import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform import { SerializedError } from 'vs/base/common/errors'; import { removeDangerousEnvVariables } from 'vs/base/common/processes'; import { StopWatch } from 'vs/base/common/stopwatch'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { process } from 'vs/base/parts/sandbox/electron-sandbox/globals'; export interface ILocalProcessExtensionHostInitData { readonly autoStart: boolean; - readonly extensions: IExtensionDescription[]; + readonly allExtensions: IExtensionDescription[]; + readonly myExtensions: ExtensionIdentifier[]; } export interface ILocalProcessExtensionHostDataProvider { @@ -108,7 +108,7 @@ export class LocalProcessExtensionHost implements IExtensionHost { public readonly remoteAuthority = null; public readonly lazyStart = false; - public readonly extensions = new ExtensionDescriptionRegistry([]); + public readonly extensions = new ExtensionHostExtensions(); private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>(); public readonly onExit: Event<[number, string]> = this._onExit.event; @@ -498,7 +498,7 @@ export class LocalProcessExtensionHost implements IExtensionHost { private async _createExtHostInitData(): Promise { const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]); const workspace = this._contextService.getWorkspace(); - this.extensions.deltaExtensions(initData.extensions, []); + const deltaExtensions = this.extensions.set(initData.allExtensions, initData.myExtensions); return { commit: this._productService.commit, version: this._productService.version, @@ -527,9 +527,8 @@ export class LocalProcessExtensionHost implements IExtensionHost { connectionData: null, isRemote: false }, - resolvedExtensions: [], - hostExtensions: [], - extensions: this.extensions.getAllExtensionDescriptions(), + allExtensions: deltaExtensions.toAdd, + myExtensions: deltaExtensions.myToAdd, telemetryInfo, logLevel: this._logService.getLevel(), logsLocation: this._environmentService.extHostLogsPath,