未验证 提交 87dd7d6a 编写于 作者: A Alex Dima

Move `deltaExtensions` related methods up to `AbstractExtensionService`

上级 607ee4ae
......@@ -506,7 +506,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
const host: IExtensionActivationHost = {
folders: folders.map(folder => folder.uri),
forceUsingSearch: localWithRemote,
exists: (path) => this._hostUtils.exists(path),
exists: (uri) => this._hostUtils.exists(uri.fsPath),
checkExists: (folders, includes, token) => this._mainThreadWorkspaceProxy.$checkExists(folders, includes, token)
};
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'vs/base/common/path';
import * as resources from 'vs/base/common/resources';
import { URI, UriComponents } from 'vs/base/common/uri';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
......@@ -19,7 +19,7 @@ export interface IExtensionActivationHost {
readonly folders: readonly UriComponents[];
readonly forceUsingSearch: boolean;
exists(path: string): Promise<boolean>;
exists(uri: URI): Promise<boolean>;
checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise<boolean>;
}
......@@ -69,7 +69,7 @@ export function checkActivateWorkspaceContainsExtension(host: IExtensionActivati
async function _activateIfFileName(host: IExtensionActivationHost, fileName: string, activate: (activationEvent: string) => void): Promise<void> {
// find exact path
for (const uri of host.folders) {
if (await host.exists(path.join(URI.revive(uri).fsPath, fileName))) {
if (await host.exists(resources.joinPath(URI.revive(uri), fileName))) {
// the file was found
activate(`workspaceContains:${fileName}`);
return;
......
......@@ -19,13 +19,15 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionIdentifier, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription, ExtensionKind, IExtension } from 'vs/platform/extensions/common/extensions';
import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browser/webWorkerFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
......@@ -41,6 +43,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
@IFileService fileService: IFileService,
@IProductService productService: IProductService,
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IConfigurationService private readonly _configService: IConfigurationService,
......@@ -56,6 +60,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
extensionEnablementService,
fileService,
productService,
extensionManagementService,
contextService,
);
this._runningLocation = new Map<string, ExtensionRunningLocation>();
......@@ -74,6 +80,13 @@ export class ExtensionService extends AbstractExtensionService implements IExten
super.dispose();
}
protected async _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
return null;
}
protected async _updateExtensionsOnExtHosts(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
}
private _initFetchFileSystem(): void {
const provider = new FetchFileSystemProvider();
this._disposables.add(this._fileService.registerProvider(Schemas.http, provider));
......
......@@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { Barrier } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
......@@ -20,11 +21,14 @@ import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensi
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { IProductService } from 'vs/platform/product/common/productService';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
const hasOwnProperty = Object.hasOwnProperty;
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
......@@ -39,6 +43,13 @@ export function parseScannedExtension(extension: ITranslatedScannedExtension): I
};
}
class DeltaExtensionsQueueItem {
constructor(
public readonly toAdd: IExtension[],
public readonly toRemove: string[]
) { }
}
export abstract class AbstractExtensionService extends Disposable implements IExtensionService {
public _serviceBrand: undefined;
......@@ -66,6 +77,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
private readonly _proposedApiController: ProposedApiController;
private readonly _isExtensionDevHost: boolean;
protected readonly _isExtensionDevTestFromCli: boolean;
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
private _inHandleDeltaExtensions: boolean;
// --- Members used per extension host process
protected _extensionHostManagers: ExtensionHostManager[];
......@@ -80,7 +93,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
@ITelemetryService protected readonly _telemetryService: ITelemetryService,
@IWorkbenchExtensionEnablementService protected readonly _extensionEnablementService: IWorkbenchExtensionEnablementService,
@IFileService protected readonly _fileService: IFileService,
@IProductService protected readonly _productService: IProductService
@IProductService protected readonly _productService: IProductService,
@IExtensionManagementService protected readonly _extensionManagementService: IExtensionManagementService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
) {
super();
......@@ -103,8 +118,225 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
const devOpts = parseExtensionDevOptions(this._environmentService);
this._isExtensionDevHost = devOpts.isExtensionDevHost;
this._isExtensionDevTestFromCli = devOpts.isExtensionDevTestFromCli;
this._deltaExtensionsQueue = [];
this._inHandleDeltaExtensions = false;
this._register(this._extensionEnablementService.onEnablementChanged((extensions) => {
let toAdd: IExtension[] = [];
let toRemove: string[] = [];
for (const extension of extensions) {
if (this._extensionEnablementService.isEnabled(extension)) {
// an extension has been enabled
toAdd.push(extension);
} else {
// an extension has been disabled
toRemove.push(extension.identifier.id);
}
}
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
}));
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
if (event.local) {
if (this._extensionEnablementService.isEnabled(event.local)) {
// an extension has been installed
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
}
}
}));
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
if (!event.error) {
// an extension has been uninstalled
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id]));
}
}));
}
//#region deltaExtensions
private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise<void> {
this._deltaExtensionsQueue.push(item);
if (this._inHandleDeltaExtensions) {
// Let the current item finish, the new one will be picked up
return;
}
while (this._deltaExtensionsQueue.length > 0) {
const item = this._deltaExtensionsQueue.shift()!;
try {
this._inHandleDeltaExtensions = true;
await this._deltaExtensions(item.toAdd, item.toRemove);
} finally {
this._inHandleDeltaExtensions = false;
}
}
}
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
if (this._environmentService.configuration.remoteAuthority) {
return;
}
let toAdd: IExtensionDescription[] = [];
for (let i = 0, len = _toAdd.length; i < len; i++) {
const extension = _toAdd[i];
if (!this._canAddExtension(extension)) {
continue;
}
const extensionDescription = await this._scanSingleExtension(extension);
if (!extensionDescription) {
// could not scan extension...
continue;
}
toAdd.push(extensionDescription);
}
let toRemove: IExtensionDescription[] = [];
for (let i = 0, len = _toRemove.length; i < len; i++) {
const extensionId = _toRemove[i];
const extensionDescription = this._registry.getExtensionDescription(extensionId);
if (!extensionDescription) {
// ignore disabling/uninstalling an extension which is not running
continue;
}
if (!this.canRemoveExtension(extensionDescription)) {
// uses non-dynamic extension point or is activated
continue;
}
toRemove.push(extensionDescription);
}
if (toAdd.length === 0 && toRemove.length === 0) {
return;
}
// Update the local registry
const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
this._onDidChangeExtensions.fire(undefined);
toRemove = toRemove.concat(result.removedDueToLooping);
if (result.removedDueToLooping.length > 0) {
this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', ')));
}
// enable or disable proposed API per extension
this._checkEnableProposedApi(toAdd);
// Update extension points
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
// Update the extension host
this._updateExtensionsOnExtHosts(toAdd, toRemove.map(e => e.identifier));
for (let i = 0; i < toAdd.length; i++) {
this._activateAddedExtensionIfNeeded(toAdd[i]);
}
}
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
return this._canAddExtension(toExtension(extensionDescription));
}
protected _canAddExtension(extension: IExtension): boolean {
const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id);
if (extensionDescription) {
// this extension is already running (most likely at a different version)
return false;
}
// Check if extension is renamed
if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) {
return false;
}
return true;
}
public canRemoveExtension(extension: IExtensionDescription): boolean {
const extensionDescription = this._registry.getExtensionDescription(extension.identifier);
if (!extensionDescription) {
// ignore removing an extension which is not running
return false;
}
if (this._extensionHostActiveExtensions.has(ExtensionIdentifier.toKey(extensionDescription.identifier))) {
// Extension is running, cannot remove it safely
return false;
}
return true;
}
private async _activateAddedExtensionIfNeeded(extensionDescription: IExtensionDescription): Promise<void> {
let shouldActivate = false;
let shouldActivateReason: string | null = null;
let hasWorkspaceContains = false;
if (Array.isArray(extensionDescription.activationEvents)) {
for (let activationEvent of extensionDescription.activationEvents) {
// TODO@joao: there's no easy way to contribute this
if (activationEvent === 'onUri') {
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
}
if (this._allRequestedActivateEvents.has(activationEvent)) {
// This activation event was fired before the extension was added
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
if (activationEvent === '*') {
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
if (/^workspaceContains/.test(activationEvent)) {
hasWorkspaceContains = true;
}
if (activationEvent === 'onStartupFinished') {
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
}
}
if (shouldActivate) {
await Promise.all(
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
).then(() => { });
} else if (hasWorkspaceContains) {
const workspace = await this._contextService.getCompleteWorkspace();
const forceUsingSearch = !!this._environmentService.configuration.remoteAuthority;
const host: IWorkspaceContainsActivationHost = {
folders: workspace.folders.map(folder => folder.uri),
forceUsingSearch: forceUsingSearch,
exists: (uri) => this._fileService.exists(uri),
checkExists: (folders, includes, token) => this._instantiationService.invokeFunction((accessor) => checkGlobFileExists(accessor, folders, includes, token))
};
const result = await checkActivateWorkspaceContainsExtension(host, extensionDescription);
if (!result) {
return;
}
await Promise.all(
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: result.activationEvent }))
).then(() => { });
}
}
//#endregion
protected async _initialize(): Promise<void> {
perf.mark('willLoadExtensions');
this._startExtensionHosts(true, []);
......@@ -169,14 +401,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
//#region IExtensionService
public canAddExtension(extension: IExtensionDescription): boolean {
return false;
}
public canRemoveExtension(extension: IExtensionDescription): boolean {
return false;
}
public restartExtensionHost(): void {
this._stopExtensionHosts();
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
......@@ -463,6 +687,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
protected abstract _scanAndHandleExtensions(): Promise<void>;
protected abstract _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null>;
protected abstract _updateExtensionsOnExtHosts(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
public abstract _onExtensionHostExit(code: number): void;
}
......
......@@ -25,7 +25,6 @@ import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
import { Schemas } from 'vs/base/common/network';
import { IFileService } from 'vs/platform/files/common/files';
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
import { IProductService } from 'vs/platform/product/common/productService';
......@@ -37,18 +36,10 @@ import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { exists } from 'vs/base/node/pfs';
import { ILogService } from 'vs/platform/log/common/log';
import { CATEGORIES } from 'vs/workbench/common/actions';
class DeltaExtensionsQueueItem {
constructor(
public readonly toAdd: IExtension[],
public readonly toRemove: string[]
) { }
}
import { Schemas } from 'vs/base/common/network';
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
......@@ -56,7 +47,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
private _runningLocation: Map<string, ExtensionRunningLocation>;
private readonly _extensionScanner: CachedExtensionScanner;
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
constructor(
@IInstantiationService instantiationService: IInstantiationService,
......@@ -66,7 +56,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
@IFileService fileService: IFileService,
@IProductService productService: IProductService,
@IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService,
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
......@@ -76,7 +67,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
@IHostService private readonly _hostService: IHostService,
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
@IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
@ILogService private readonly _logService: ILogService,
) {
super(
......@@ -86,7 +76,9 @@ export class ExtensionService extends AbstractExtensionService implements IExten
telemetryService,
extensionEnablementService,
fileService,
productService
productService,
extensionManagementService,
contextService,
);
this._enableLocalWebWorker = this._configurationService.getValue<boolean>(webWorkerExtHostConfig);
......@@ -95,38 +87,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
this._runningLocation = new Map<string, ExtensionRunningLocation>();
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
this._deltaExtensionsQueue = [];
this._register(this._extensionEnablementService.onEnablementChanged((extensions) => {
let toAdd: IExtension[] = [];
let toRemove: string[] = [];
for (const extension of extensions) {
if (this._extensionEnablementService.isEnabled(extension)) {
// an extension has been enabled
toAdd.push(extension);
} else {
// an extension has been disabled
toRemove.push(extension.identifier.id);
}
}
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
}));
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
if (event.local) {
if (this._extensionEnablementService.isEnabled(event.local)) {
// an extension has been installed
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
}
}
}));
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
if (!event.error) {
// an extension has been uninstalled
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id]));
}
}));
// delay extension host creation and extension scanning
// until the workbench is running. we cannot defer the
......@@ -163,101 +123,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return null;
}
//#region deltaExtensions
private _inHandleDeltaExtensions = false;
private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise<void> {
this._deltaExtensionsQueue.push(item);
if (this._inHandleDeltaExtensions) {
// Let the current item finish, the new one will be picked up
return;
}
while (this._deltaExtensionsQueue.length > 0) {
const item = this._deltaExtensionsQueue.shift()!;
try {
this._inHandleDeltaExtensions = true;
await this._deltaExtensions(item.toAdd, item.toRemove);
} finally {
this._inHandleDeltaExtensions = false;
}
}
}
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
if (this._environmentService.configuration.remoteAuthority) {
return;
}
let toAdd: IExtensionDescription[] = [];
for (let i = 0, len = _toAdd.length; i < len; i++) {
const extension = _toAdd[i];
if (!this._canAddExtension(extension)) {
continue;
}
const extensionDescription = await this._extensionScanner.scanSingleExtension(extension.location.fsPath, extension.type === ExtensionType.System, this.createLogger());
if (!extensionDescription) {
// could not scan extension...
continue;
}
toAdd.push(extensionDescription);
}
let toRemove: IExtensionDescription[] = [];
for (let i = 0, len = _toRemove.length; i < len; i++) {
const extensionId = _toRemove[i];
const extensionDescription = this._registry.getExtensionDescription(extensionId);
if (!extensionDescription) {
// ignore disabling/uninstalling an extension which is not running
continue;
}
if (!this._canRemoveExtension(extensionDescription)) {
// uses non-dynamic extension point or is activated
continue;
}
toRemove.push(extensionDescription);
}
if (toAdd.length === 0 && toRemove.length === 0) {
return;
}
// Update the local registry
const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
this._onDidChangeExtensions.fire(undefined);
toRemove = toRemove.concat(result.removedDueToLooping);
if (result.removedDueToLooping.length > 0) {
this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', ')));
}
// enable or disable proposed API per extension
this._checkEnableProposedApi(toAdd);
// Update extension points
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
// Update the extension host
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
if (localProcessExtensionHost) {
await localProcessExtensionHost.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
}
for (let i = 0; i < toAdd.length; i++) {
this._activateAddedExtensionIfNeeded(toAdd[i]);
}
}
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
return this._canAddExtension(toExtension(extensionDescription));
}
private _canAddExtension(extension: IExtension): boolean {
protected _canAddExtension(extension: IExtension): boolean {
if (this._environmentService.configuration.remoteAuthority) {
return false;
}
......@@ -266,18 +132,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return false;
}
const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id);
if (extensionDescription) {
// this extension is already running (most likely at a different version)
return false;
}
// Check if extension is renamed
if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) {
return false;
}
return true;
return super._canAddExtension(extension);
}
public canRemoveExtension(extension: IExtensionDescription): boolean {
......@@ -289,88 +144,21 @@ export class ExtensionService extends AbstractExtensionService implements IExten
return false;
}
const extensionDescription = this._registry.getExtensionDescription(extension.identifier);
if (!extensionDescription) {
// ignore removing an extension which is not running
return false;
}
return this._canRemoveExtension(extensionDescription);
return super.canRemoveExtension(extension);
}
private _canRemoveExtension(extension: IExtensionDescription): boolean {
if (this._extensionHostActiveExtensions.has(ExtensionIdentifier.toKey(extension.identifier))) {
// Extension is running, cannot remove it safely
return false;
}
return true;
protected _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
return this._extensionScanner.scanSingleExtension(extension.location.fsPath, extension.type === ExtensionType.System, this.createLogger());
}
private async _activateAddedExtensionIfNeeded(extensionDescription: IExtensionDescription): Promise<void> {
let shouldActivate = false;
let shouldActivateReason: string | null = null;
let hasWorkspaceContains = false;
if (Array.isArray(extensionDescription.activationEvents)) {
for (let activationEvent of extensionDescription.activationEvents) {
// TODO@joao: there's no easy way to contribute this
if (activationEvent === 'onUri') {
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
}
if (this._allRequestedActivateEvents.has(activationEvent)) {
// This activation event was fired before the extension was added
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
if (activationEvent === '*') {
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
if (/^workspaceContains/.test(activationEvent)) {
hasWorkspaceContains = true;
}
if (activationEvent === 'onStartupFinished') {
shouldActivate = true;
shouldActivateReason = activationEvent;
break;
}
}
}
if (shouldActivate) {
await Promise.all(
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
).then(() => { });
} else if (hasWorkspaceContains) {
const workspace = await this._contextService.getCompleteWorkspace();
const forceUsingSearch = !!this._environmentService.configuration.remoteAuthority;
const host: IWorkspaceContainsActivationHost = {
folders: workspace.folders.map(folder => folder.uri),
forceUsingSearch: forceUsingSearch,
exists: (path) => exists(path),
checkExists: (folders, includes, token) => this._instantiationService.invokeFunction((accessor) => checkGlobFileExists(accessor, folders, includes, token))
};
const result = await checkActivateWorkspaceContainsExtension(host, extensionDescription);
if (!result) {
return;
}
await Promise.all(
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: result.activationEvent }))
).then(() => { });
protected async _updateExtensionsOnExtHosts(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
if (localProcessExtensionHost) {
await localProcessExtensionHost.deltaExtensions(toAdd, toRemove);
}
}
//#endregion
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
return flatten(await Promise.all([
this._extensionScanner.scannedExtensions,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册