mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Merge from vscode 2cd495805cf99b31b6926f08ff4348124b2cf73d
This commit is contained in:
committed by
AzureDataStudio
parent
a8a7559229
commit
1388493cc1
@@ -5,35 +5,31 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
|
||||
import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { AbstractExtensionService, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { RemoteExtensionHost, IRemoteExtensionHostDataProvider, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { WebWorkerExtensionHostStarter } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { canExecuteOnWeb } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExtensionIdentifier } 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 { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
|
||||
import { DeltaExtensionsResult } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
private _disposables = new DisposableStore();
|
||||
private _remoteExtensionsEnvironmentData: IRemoteAgentEnvironment | null = null;
|
||||
private _remoteInitData: IRemoteExtensionHostInitData | null = null;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -46,7 +42,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IConfigurationService private readonly _configService: IConfigurationService,
|
||||
@IStaticExtensionsService private readonly _staticExtensions: IStaticExtensionsService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
) {
|
||||
super(
|
||||
instantiationService,
|
||||
@@ -73,32 +69,39 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._disposables.add(this._fileService.registerProvider(Schemas.https, provider));
|
||||
}
|
||||
|
||||
private _createProvider(remoteAuthority: string): IInitDataProvider {
|
||||
private _createLocalExtensionHostDataProvider() {
|
||||
return {
|
||||
remoteAuthority: remoteAuthority,
|
||||
getInitData: async () => {
|
||||
await this.whenInstalledExtensionsRegistered();
|
||||
const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority);
|
||||
const remoteEnvironment = this._remoteExtensionsEnvironmentData!;
|
||||
return { connectionData, remoteEnvironment };
|
||||
const allExtensions = await this.getExtensions();
|
||||
const webExtensions = allExtensions.filter(ext => canExecuteOnWeb(ext, this._productService, this._configService));
|
||||
return {
|
||||
autoStart: true,
|
||||
extensions: webExtensions
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(_isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] {
|
||||
const result: ExtensionHostProcessManager[] = [];
|
||||
private _createRemoteExtensionHostDataProvider(remoteAuthority: string): IRemoteExtensionHostDataProvider {
|
||||
return {
|
||||
remoteAuthority: remoteAuthority,
|
||||
getInitData: async () => {
|
||||
await this.whenInstalledExtensionsRegistered();
|
||||
return this._remoteInitData!;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => canExecuteOnWeb(ext, this._productService, this._configService)));
|
||||
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, webExtensions, URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme }));
|
||||
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, null, initialActivationEvents);
|
||||
result.push(webHostProcessManager);
|
||||
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider());
|
||||
result.push(webWorkerExtHost);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
const remoteExtensions = this.getExtensions().then(extensions => extensions.filter(ext => !canExecuteOnWeb(ext, this._productService, this._configService)));
|
||||
const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, remoteExtensions, this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
|
||||
result.push(remoteExtHostProcessManager);
|
||||
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
result.push(remoteExtHost);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -108,16 +111,18 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
// fetch the remote environment
|
||||
let [remoteEnv, localExtensions] = await Promise.all([
|
||||
this._remoteAgentService.getEnvironment(),
|
||||
this._staticExtensions.getExtensions()
|
||||
this._webExtensionsScannerService.scanExtensions().then(extensions => extensions.map(parseScannedExtension))
|
||||
]);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
|
||||
let result: DeltaExtensionsResult;
|
||||
|
||||
// local: only enabled and web'ish extension
|
||||
localExtensions = localExtensions!.filter(ext => this._isEnabled(ext) && canExecuteOnWeb(ext, this._productService, this._configService));
|
||||
this._checkEnableProposedApi(localExtensions);
|
||||
|
||||
if (!remoteEnv) {
|
||||
if (!remoteEnv || !remoteAgentConnection) {
|
||||
result = this._registry.deltaExtensions(localExtensions, []);
|
||||
|
||||
} else {
|
||||
@@ -131,7 +136,17 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
localExtensions = localExtensions.filter(extension => !isRemoteExtension.has(ExtensionIdentifier.toKey(extension.identifier)));
|
||||
|
||||
// save for remote extension's init data
|
||||
this._remoteExtensionsEnvironmentData = remoteEnv;
|
||||
this._remoteInitData = {
|
||||
connectionData: this._remoteAuthorityResolverService.getConnectionData(remoteAgentConnection.remoteAuthority),
|
||||
pid: remoteEnv.pid,
|
||||
appRoot: remoteEnv.appRoot,
|
||||
appSettingsHome: remoteEnv.appSettingsHome,
|
||||
extensionHostLogsPath: remoteEnv.extensionHostLogsPath,
|
||||
globalStorageHome: remoteEnv.globalStorageHome,
|
||||
userHome: remoteEnv.userHome,
|
||||
extensions: remoteEnv.extensions,
|
||||
allExtensions: remoteEnv.extensions.concat(localExtensions)
|
||||
};
|
||||
|
||||
result = this._registry.deltaExtensions(remoteEnv.extensions.concat(localExtensions), []);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtensionHostStarter, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
@@ -25,7 +25,19 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
|
||||
export interface IWebWorkerExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
readonly extensions: IExtensionDescription[];
|
||||
}
|
||||
|
||||
export interface IWebWorkerExtensionHostDataProvider {
|
||||
getInitData(): Promise<IWebWorkerExtensionHostInitData>;
|
||||
}
|
||||
|
||||
export class WebWorkerExtensionHost implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalWebWorker;
|
||||
public readonly remoteAuthority = null;
|
||||
|
||||
private _toDispose = new DisposableStore();
|
||||
private _isTerminating: boolean = false;
|
||||
@@ -34,12 +46,11 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
|
||||
private readonly _onDidExit = new Emitter<[number, string | null]>();
|
||||
readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
|
||||
|
||||
private readonly _extensionHostLogsLocation: URI;
|
||||
private readonly _extensionHostLogFile: URI;
|
||||
|
||||
constructor(
|
||||
private readonly _autoStart: boolean,
|
||||
private readonly _extensions: Promise<IExtensionDescription[]>,
|
||||
private readonly _extensionHostLogsLocation: URI,
|
||||
private readonly _initDataProvider: IWebWorkerExtensionHostDataProvider,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@@ -47,6 +58,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
) {
|
||||
this._extensionHostLogsLocation = URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme });
|
||||
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
|
||||
}
|
||||
|
||||
@@ -127,7 +139,7 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
|
||||
}
|
||||
|
||||
private async _createExtHostInitData(): Promise<IInitData> {
|
||||
const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]);
|
||||
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
@@ -153,12 +165,12 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter {
|
||||
},
|
||||
resolvedExtensions: [],
|
||||
hostExtensions: [],
|
||||
extensions: extensionDescriptions,
|
||||
extensions: initData.extensions,
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: this._extensionHostLogsLocation,
|
||||
logFile: this._extensionHostLogFile,
|
||||
autoStart: this._autoStart,
|
||||
autoStart: initData.autoStart,
|
||||
remote: {
|
||||
authority: this._environmentService.configuration.remoteAuthority,
|
||||
connectionData: null,
|
||||
@@ -15,12 +15,12 @@ import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionM
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtensionDescription, IScannedExtension, ExtensionType } 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';
|
||||
@@ -29,6 +29,16 @@ import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtens
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export function parseScannedExtension(extension: IScannedExtension): IExtensionDescription {
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUnderDevelopment: false,
|
||||
extensionLocation: extension.location,
|
||||
...extension.packageJSON,
|
||||
};
|
||||
}
|
||||
|
||||
export abstract class AbstractExtensionService extends Disposable implements IExtensionService {
|
||||
|
||||
public _serviceBrand: undefined;
|
||||
@@ -58,9 +68,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
protected readonly _isExtensionDevTestFromCli: boolean;
|
||||
|
||||
// --- Members used per extension host process
|
||||
protected _extensionHostProcessManagers: ExtensionHostProcessManager[];
|
||||
protected _extensionHostManagers: ExtensionHostManager[];
|
||||
protected _extensionHostActiveExtensions: Map<string, ExtensionIdentifier>;
|
||||
private _extensionHostProcessActivationTimes: Map<string, ActivationTimes>;
|
||||
private _extensionHostActivationTimes: Map<string, ActivationTimes>;
|
||||
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
|
||||
|
||||
constructor(
|
||||
@@ -85,9 +95,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._extensionsMessages = new Map<string, IMessage[]>();
|
||||
this._proposedApiController = new ProposedApiController(this._environmentService, this._productService);
|
||||
|
||||
this._extensionHostProcessManagers = [];
|
||||
this._extensionHostManagers = [];
|
||||
this._extensionHostActiveExtensions = new Map<string, ExtensionIdentifier>();
|
||||
this._extensionHostProcessActivationTimes = new Map<string, ActivationTimes>();
|
||||
this._extensionHostActivationTimes = new Map<string, ActivationTimes>();
|
||||
this._extensionHostExtensionRuntimeErrors = new Map<string, Error[]>();
|
||||
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
@@ -97,7 +107,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
protected async _initialize(): Promise<void> {
|
||||
perf.mark('willLoadExtensions');
|
||||
this._startExtensionHostProcess(true, []);
|
||||
this._startExtensionHosts(true, []);
|
||||
this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions'));
|
||||
await this._scanAndHandleExtensions();
|
||||
this._releaseBarrier();
|
||||
@@ -110,18 +120,18 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier));
|
||||
}
|
||||
|
||||
private _stopExtensionHostProcess(): void {
|
||||
private _stopExtensionHosts(): void {
|
||||
let previouslyActivatedExtensionIds: ExtensionIdentifier[] = [];
|
||||
this._extensionHostActiveExtensions.forEach((value) => {
|
||||
previouslyActivatedExtensionIds.push(value);
|
||||
});
|
||||
|
||||
for (const manager of this._extensionHostProcessManagers) {
|
||||
for (const manager of this._extensionHostManagers) {
|
||||
manager.dispose();
|
||||
}
|
||||
this._extensionHostProcessManagers = [];
|
||||
this._extensionHostManagers = [];
|
||||
this._extensionHostActiveExtensions = new Map<string, ExtensionIdentifier>();
|
||||
this._extensionHostProcessActivationTimes = new Map<string, ActivationTimes>();
|
||||
this._extensionHostActivationTimes = new Map<string, ActivationTimes>();
|
||||
this._extensionHostExtensionRuntimeErrors = new Map<string, Error[]>();
|
||||
|
||||
if (previouslyActivatedExtensionIds.length > 0) {
|
||||
@@ -129,18 +139,19 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
}
|
||||
|
||||
private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
this._stopExtensionHostProcess();
|
||||
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
this._stopExtensionHosts();
|
||||
|
||||
const processManagers = this._createExtensionHosts(isInitialStart, initialActivationEvents);
|
||||
processManagers.forEach((processManager) => {
|
||||
const extensionHosts = this._createExtensionHosts(isInitialStart);
|
||||
extensionHosts.forEach((extensionHost) => {
|
||||
const processManager = this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
|
||||
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
|
||||
processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
|
||||
this._extensionHostProcessManagers.push(processManager);
|
||||
this._extensionHostManagers.push(processManager);
|
||||
});
|
||||
}
|
||||
|
||||
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
|
||||
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
|
||||
// Unexpected termination
|
||||
if (!this._isExtensionDevHost) {
|
||||
@@ -151,9 +162,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onExtensionHostExit(code);
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal);
|
||||
this._stopExtensionHostProcess();
|
||||
this._stopExtensionHosts();
|
||||
}
|
||||
|
||||
//#region IExtensionService
|
||||
@@ -167,12 +178,12 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
|
||||
public restartExtensionHost(): void {
|
||||
this._stopExtensionHostProcess();
|
||||
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
this._stopExtensionHosts();
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
}
|
||||
|
||||
protected startExtensionHost(): void {
|
||||
this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
}
|
||||
|
||||
public activateByEvent(activationEvent: string): Promise<void> {
|
||||
@@ -200,7 +211,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
private _activateByEvent(activationEvent: string): Promise<void> {
|
||||
const result = Promise.all(
|
||||
this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent))
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent))
|
||||
).then(() => { });
|
||||
this._onWillActivateByEvent.fire({
|
||||
event: activationEvent,
|
||||
@@ -248,7 +259,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
const extensionKey = ExtensionIdentifier.toKey(extension.identifier);
|
||||
result[extension.identifier.value] = {
|
||||
messages: this._extensionsMessages.get(extensionKey) || [],
|
||||
activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey),
|
||||
activationTimes: this._extensionHostActivationTimes.get(extensionKey),
|
||||
runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [],
|
||||
};
|
||||
}
|
||||
@@ -261,7 +272,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
|
||||
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||
await this._extensionHostProcessManagers
|
||||
await this._extensionHostManagers
|
||||
.map(manager => manager.setRemoteEnvironment(env));
|
||||
}
|
||||
|
||||
@@ -275,6 +286,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
}
|
||||
|
||||
protected _checkEnabledAndProposedAPI(extensions: IExtensionDescription[]): IExtensionDescription[] {
|
||||
// enable or disable proposed API per extension
|
||||
this._checkEnableProposedApi(extensions);
|
||||
|
||||
// keep only enabled extensions
|
||||
return extensions.filter(extension => this._isEnabled(extension));
|
||||
}
|
||||
|
||||
private _isExtensionUnderDevelopment(extension: IExtensionDescription): boolean {
|
||||
if (this._environmentService.isExtensionDevelopment) {
|
||||
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
|
||||
@@ -291,21 +310,17 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
|
||||
protected _isEnabled(extension: IExtensionDescription): boolean {
|
||||
return !this._isDisabled(extension);
|
||||
}
|
||||
|
||||
protected _isDisabled(extension: IExtensionDescription): boolean {
|
||||
if (this._isExtensionUnderDevelopment(extension)) {
|
||||
// Never disable extensions under development
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) {
|
||||
// Check if this is the better merge extension which was migrated to a built-in extension
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !this._extensionEnablementService.isEnabled(toExtension(extension));
|
||||
return this._extensionEnablementService.isEnabled(toExtension(extension));
|
||||
}
|
||||
|
||||
protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void {
|
||||
@@ -413,7 +428,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
public async _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
|
||||
const results = await Promise.all(
|
||||
this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, reason))
|
||||
this._extensionHostManagers.map(manager => manager.activate(extensionId, reason))
|
||||
);
|
||||
const activated = results.some(e => e);
|
||||
if (!activated) {
|
||||
@@ -426,7 +441,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
|
||||
public _onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void {
|
||||
this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(codeLoadingTime, activateCallTime, activateResolvedTime, activationReason));
|
||||
this._extensionHostActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(codeLoadingTime, activateCallTime, activateResolvedTime, activationReason));
|
||||
this._onDidChangeExtensionsStatus.fire([extensionId]);
|
||||
}
|
||||
|
||||
@@ -441,7 +456,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
//#endregion
|
||||
|
||||
protected abstract _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[];
|
||||
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
|
||||
protected abstract _scanAndHandleExtensions(): Promise<void>;
|
||||
public abstract _onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
@@ -21,17 +21,17 @@ 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 { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
const LOG_USE_COLORS = true;
|
||||
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export class ExtensionHostProcessManager extends Disposable {
|
||||
export class ExtensionHostManager extends Disposable {
|
||||
|
||||
public readonly kind: ExtensionHostKind;
|
||||
public readonly onDidExit: Event<[number, string | null]>;
|
||||
|
||||
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
|
||||
@@ -40,32 +40,31 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
/**
|
||||
* A map of already activated events to speed things up if the same activation event is triggered multiple times.
|
||||
*/
|
||||
private readonly _extensionHostProcessFinishedActivateEvents: { [activationEvent: string]: boolean; };
|
||||
private _extensionHostProcessRPCProtocol: RPCProtocol | null;
|
||||
private readonly _extensionHostProcessCustomers: IDisposable[];
|
||||
private readonly _extensionHostProcessWorker: IExtensionHostStarter;
|
||||
private readonly _finishedActivateEvents: { [activationEvent: string]: boolean; };
|
||||
private _rpcProtocol: RPCProtocol | null;
|
||||
private readonly _customers: IDisposable[];
|
||||
private readonly _extensionHost: IExtensionHost;
|
||||
/**
|
||||
* winjs believes a proxy is a promise because it has a `then` method, so wrap the result in an object.
|
||||
*/
|
||||
private _extensionHostProcessProxy: Promise<{ value: ExtHostExtensionServiceShape; } | null> | null;
|
||||
private _proxy: Promise<{ value: ExtHostExtensionServiceShape; } | null> | null;
|
||||
private _resolveAuthorityAttempt: number;
|
||||
|
||||
constructor(
|
||||
public readonly isLocal: boolean,
|
||||
extensionHostProcessWorker: IExtensionHostStarter,
|
||||
private readonly _remoteAuthority: string | null,
|
||||
extensionHost: IExtensionHost,
|
||||
initialActivationEvents: string[],
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
) {
|
||||
super();
|
||||
this._extensionHostProcessFinishedActivateEvents = Object.create(null);
|
||||
this._extensionHostProcessRPCProtocol = null;
|
||||
this._extensionHostProcessCustomers = [];
|
||||
this._finishedActivateEvents = Object.create(null);
|
||||
this._rpcProtocol = null;
|
||||
this._customers = [];
|
||||
|
||||
this._extensionHostProcessWorker = extensionHostProcessWorker;
|
||||
this.onDidExit = this._extensionHostProcessWorker.onExit;
|
||||
this._extensionHostProcessProxy = this._extensionHostProcessWorker.start()!.then(
|
||||
this._extensionHost = extensionHost;
|
||||
this.kind = this._extensionHost.kind;
|
||||
this.onDidExit = this._extensionHost.onExit;
|
||||
this._proxy = this._extensionHost.start()!.then(
|
||||
(protocol) => {
|
||||
return { value: this._createExtensionHostCustomers(protocol) };
|
||||
},
|
||||
@@ -75,7 +74,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
return null;
|
||||
}
|
||||
);
|
||||
this._extensionHostProcessProxy.then(() => {
|
||||
this._proxy.then(() => {
|
||||
initialActivationEvents.forEach((activationEvent) => this.activateByEvent(activationEvent));
|
||||
this._register(registerLatencyTestProvider({
|
||||
measure: () => this.measure()
|
||||
@@ -85,27 +84,27 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._extensionHostProcessWorker) {
|
||||
this._extensionHostProcessWorker.dispose();
|
||||
if (this._extensionHost) {
|
||||
this._extensionHost.dispose();
|
||||
}
|
||||
if (this._extensionHostProcessRPCProtocol) {
|
||||
this._extensionHostProcessRPCProtocol.dispose();
|
||||
if (this._rpcProtocol) {
|
||||
this._rpcProtocol.dispose();
|
||||
}
|
||||
for (let i = 0, len = this._extensionHostProcessCustomers.length; i < len; i++) {
|
||||
const customer = this._extensionHostProcessCustomers[i];
|
||||
for (let i = 0, len = this._customers.length; i < len; i++) {
|
||||
const customer = this._customers[i];
|
||||
try {
|
||||
customer.dispose();
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
}
|
||||
}
|
||||
this._extensionHostProcessProxy = null;
|
||||
this._proxy = null;
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private async measure(): Promise<ExtHostLatencyResult | null> {
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return null;
|
||||
}
|
||||
@@ -113,18 +112,18 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
const down = await this._measureDown(proxy);
|
||||
const up = await this._measureUp(proxy);
|
||||
return {
|
||||
remoteAuthority: this._remoteAuthority,
|
||||
remoteAuthority: this._extensionHost.remoteAuthority,
|
||||
latency,
|
||||
down,
|
||||
up
|
||||
};
|
||||
}
|
||||
|
||||
private async _getExtensionHostProcessProxy(): Promise<ExtHostExtensionServiceShape | null> {
|
||||
if (!this._extensionHostProcessProxy) {
|
||||
private async _getProxy(): Promise<ExtHostExtensionServiceShape | null> {
|
||||
if (!this._proxy) {
|
||||
return null;
|
||||
}
|
||||
const p = await this._extensionHostProcessProxy;
|
||||
const p = await this._proxy;
|
||||
if (!p) {
|
||||
return null;
|
||||
}
|
||||
@@ -159,7 +158,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
const sw = StopWatch.create(true);
|
||||
await proxy.$test_up(buff);
|
||||
sw.stop();
|
||||
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
|
||||
return ExtensionHostManager._convert(SIZE, sw.elapsed());
|
||||
}
|
||||
|
||||
private async _measureDown(proxy: ExtHostExtensionServiceShape): Promise<number> {
|
||||
@@ -168,7 +167,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
const sw = StopWatch.create(true);
|
||||
await proxy.$test_down(SIZE);
|
||||
sw.stop();
|
||||
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
|
||||
return ExtensionHostManager._convert(SIZE, sw.elapsed());
|
||||
}
|
||||
|
||||
private _createExtensionHostCustomers(protocol: IMessagePassingProtocol): ExtHostExtensionServiceShape {
|
||||
@@ -178,13 +177,13 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
logger = new RPCLogger();
|
||||
}
|
||||
|
||||
this._extensionHostProcessRPCProtocol = new RPCProtocol(protocol, logger);
|
||||
this._register(this._extensionHostProcessRPCProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState)));
|
||||
this._rpcProtocol = new RPCProtocol(protocol, logger);
|
||||
this._register(this._rpcProtocol.onDidChangeResponsiveState((responsiveState: ResponsiveState) => this._onDidChangeResponsiveState.fire(responsiveState)));
|
||||
const extHostContext: IExtHostContext = {
|
||||
remoteAuthority: this._remoteAuthority! /* TODO: alexdima, remove not-null assertion */,
|
||||
getProxy: <T>(identifier: ProxyIdentifier<T>): T => this._extensionHostProcessRPCProtocol!.getProxy(identifier),
|
||||
set: <T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R => this._extensionHostProcessRPCProtocol!.set(identifier, instance),
|
||||
assertRegistered: (identifiers: ProxyIdentifier<any>[]): void => this._extensionHostProcessRPCProtocol!.assertRegistered(identifiers),
|
||||
remoteAuthority: this._extensionHost.remoteAuthority,
|
||||
getProxy: <T>(identifier: ProxyIdentifier<T>): T => this._rpcProtocol!.getProxy(identifier),
|
||||
set: <T, R extends T>(identifier: ProxyIdentifier<T>, instance: R): R => this._rpcProtocol!.set(identifier, instance),
|
||||
assertRegistered: (identifiers: ProxyIdentifier<any>[]): void => this._rpcProtocol!.assertRegistered(identifiers),
|
||||
};
|
||||
|
||||
// Named customers
|
||||
@@ -192,28 +191,28 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
for (let i = 0, len = namedCustomers.length; i < len; i++) {
|
||||
const [id, ctor] = namedCustomers[i];
|
||||
const instance = this._instantiationService.createInstance(ctor, extHostContext);
|
||||
this._extensionHostProcessCustomers.push(instance);
|
||||
this._extensionHostProcessRPCProtocol.set(id, instance);
|
||||
this._customers.push(instance);
|
||||
this._rpcProtocol.set(id, instance);
|
||||
}
|
||||
|
||||
// Customers
|
||||
const customers = ExtHostCustomersRegistry.getCustomers();
|
||||
for (const ctor of customers) {
|
||||
const instance = this._instantiationService.createInstance(ctor, extHostContext);
|
||||
this._extensionHostProcessCustomers.push(instance);
|
||||
this._customers.push(instance);
|
||||
}
|
||||
|
||||
// Check that no named customers are missing
|
||||
// {{SQL CARBON EDIT}} filter out services we don't expose
|
||||
const filtered: ProxyIdentifier<any>[] = [MainContext.MainThreadDebugService, MainContext.MainThreadTask];
|
||||
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => (<any>MainContext)[key]).filter(v => !filtered.some(x => x === v));
|
||||
this._extensionHostProcessRPCProtocol.assertRegistered(expected);
|
||||
this._rpcProtocol.assertRegistered(expected);
|
||||
|
||||
return this._extensionHostProcessRPCProtocol.getProxy(ExtHostContext.ExtHostExtensionService);
|
||||
return this._rpcProtocol.getProxy(ExtHostContext.ExtHostExtensionService);
|
||||
}
|
||||
|
||||
public async activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return false;
|
||||
}
|
||||
@@ -221,10 +220,10 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
|
||||
public activateByEvent(activationEvent: string): Promise<void> {
|
||||
if (this._extensionHostProcessFinishedActivateEvents[activationEvent] || !this._extensionHostProcessProxy) {
|
||||
if (this._finishedActivateEvents[activationEvent] || !this._proxy) {
|
||||
return NO_OP_VOID_PROMISE;
|
||||
}
|
||||
return this._extensionHostProcessProxy.then((proxy) => {
|
||||
return this._proxy.then((proxy) => {
|
||||
if (!proxy) {
|
||||
// this case is already covered above and logged.
|
||||
// i.e. the extension host could not be started
|
||||
@@ -232,16 +231,16 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
return proxy.value.$activateByEvent(activationEvent);
|
||||
}).then(() => {
|
||||
this._extensionHostProcessFinishedActivateEvents[activationEvent] = true;
|
||||
this._finishedActivateEvents[activationEvent] = true;
|
||||
});
|
||||
}
|
||||
|
||||
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
if (this._extensionHostProcessWorker) {
|
||||
if (this._extensionHost) {
|
||||
if (tryEnableInspector) {
|
||||
await this._extensionHostProcessWorker.enableInspectPort();
|
||||
await this._extensionHost.enableInspectPort();
|
||||
}
|
||||
let port = this._extensionHostProcessWorker.getInspectPort();
|
||||
let port = this._extensionHost.getInspectPort();
|
||||
if (port) {
|
||||
return port;
|
||||
}
|
||||
@@ -262,7 +261,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
});
|
||||
}
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
throw new Error(`Cannot resolve authority`);
|
||||
}
|
||||
@@ -276,7 +275,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
|
||||
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
@@ -284,7 +283,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
|
||||
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
@@ -292,7 +291,7 @@ export class ExtensionHostProcessManager extends Disposable {
|
||||
}
|
||||
|
||||
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||
const proxy = await this._getExtensionHostProcessProxy();
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
@@ -396,7 +395,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 {
|
||||
value: nls.localize('measureExtHostLatency', "Measure Extension Host Latency"),
|
||||
original: 'Measure Extension Host Latency'
|
||||
},
|
||||
category: nls.localize('developer', "Developer"),
|
||||
category: nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"),
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
@@ -24,6 +24,8 @@ export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
|
||||
isBuiltin: false,
|
||||
});
|
||||
|
||||
export const webWorkerExtHostConfig = 'extensions.webWorker';
|
||||
|
||||
export const IExtensionService = createDecorator<IExtensionService>('extensionService');
|
||||
|
||||
export interface IMessage {
|
||||
@@ -84,7 +86,15 @@ export interface IExtensionHostProfile {
|
||||
getAggregatedTimes(): Map<ProfileSegmentId, number>;
|
||||
}
|
||||
|
||||
export interface IExtensionHostStarter {
|
||||
export const enum ExtensionHostKind {
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export interface IExtensionHost {
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly remoteAuthority: string | null;
|
||||
readonly onExit: Event<[number, string | null]>;
|
||||
|
||||
start(): Promise<IMessagePassingProtocol> | null;
|
||||
@@ -257,6 +267,17 @@ export function toExtension(extensionDescription: IExtensionDescription): IExten
|
||||
};
|
||||
}
|
||||
|
||||
export function toExtensionDescription(extension: IExtension): IExtensionDescription {
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(extension.identifier.id),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUnderDevelopment: false,
|
||||
extensionLocation: extension.location,
|
||||
...extension.manifest,
|
||||
uuid: extension.identifier.uuid
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export class NullExtensionService implements IExtensionService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/co
|
||||
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
||||
import { values } from 'vs/base/common/map';
|
||||
|
||||
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
|
||||
@@ -187,7 +187,7 @@ export const schema: IJSONSchema = {
|
||||
items: {
|
||||
oneOf: [{
|
||||
type: 'string',
|
||||
enum: ['Programming Languages', 'Snippets', 'Linters', 'Themes', 'Debuggers', 'Other', 'Keymaps', 'Formatters', 'Extension Packs', 'SCM Providers', 'Azure', 'Language Packs'],
|
||||
enum: EXTENSION_CATEGORIES,
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
@@ -271,7 +271,7 @@ export const schema: IJSONSchema = {
|
||||
},
|
||||
{
|
||||
label: 'onStartupFinished',
|
||||
description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all eager activated extensions have finished activating).'),
|
||||
description: nls.localize('vscode.extension.activationEvents.onStartupFinished', 'An activation event emitted after the start-up finished (after all `*` activated extensions have finished activating).'),
|
||||
body: 'onStartupFinished'
|
||||
},
|
||||
{
|
||||
|
||||
@@ -20,6 +20,11 @@ export function prefersExecuteOnWorkspace(manifest: IExtensionManifest, productS
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'workspace');
|
||||
}
|
||||
|
||||
export function prefersExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'web');
|
||||
}
|
||||
|
||||
export function canExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return extensionKind.some(kind => kind === 'ui');
|
||||
|
||||
@@ -13,9 +13,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { IExtensionHostStarter, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { IRemoteAuthorityResolverService, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -33,30 +32,37 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export interface IRemoteInitData {
|
||||
export interface IRemoteExtensionHostInitData {
|
||||
readonly connectionData: IRemoteConnectionData | null;
|
||||
readonly remoteEnvironment: IRemoteAgentEnvironment;
|
||||
readonly pid: number;
|
||||
readonly appRoot: URI;
|
||||
readonly appSettingsHome: URI;
|
||||
readonly extensionHostLogsPath: URI;
|
||||
readonly globalStorageHome: URI;
|
||||
readonly userHome: URI;
|
||||
readonly extensions: IExtensionDescription[];
|
||||
readonly allExtensions: IExtensionDescription[];
|
||||
}
|
||||
|
||||
export interface IInitDataProvider {
|
||||
export interface IRemoteExtensionHostDataProvider {
|
||||
readonly remoteAuthority: string;
|
||||
getInitData(): Promise<IRemoteInitData>;
|
||||
getInitData(): Promise<IRemoteExtensionHostInitData>;
|
||||
}
|
||||
|
||||
export class RemoteExtensionHostClient extends Disposable implements IExtensionHostStarter {
|
||||
export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.Remote;
|
||||
public readonly remoteAuthority: string;
|
||||
|
||||
private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>());
|
||||
public readonly onExit: Event<[number, string | null]> = this._onExit.event;
|
||||
|
||||
private _protocol: PersistentProtocol | null;
|
||||
|
||||
private _terminating: boolean;
|
||||
private readonly _isExtensionDevHost: boolean;
|
||||
|
||||
private _terminating: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly _allExtensions: Promise<IExtensionDescription[]>,
|
||||
private readonly _initDataProvider: IInitDataProvider,
|
||||
private readonly _initDataProvider: IRemoteExtensionHostDataProvider,
|
||||
private readonly _socketFactory: ISocketFactory,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@@ -70,6 +76,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
|
||||
@ISignService private readonly _signService: ISignService
|
||||
) {
|
||||
super();
|
||||
this.remoteAuthority = this._initDataProvider.remoteAuthority;
|
||||
this._protocol = null;
|
||||
this._terminating = false;
|
||||
|
||||
@@ -194,54 +201,52 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
|
||||
this._onExit.fire([0, null]);
|
||||
}
|
||||
|
||||
private _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise<IInitData> {
|
||||
return Promise.all([this._allExtensions, this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]).then(([allExtensions, telemetryInfo, remoteInitData]) => {
|
||||
// Collect all identifiers for extension ids which can be considered "resolved"
|
||||
const resolvedExtensions = allExtensions.filter(extension => !extension.main).map(extension => extension.identifier);
|
||||
const hostExtensions = allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
const remoteEnv = remoteInitData.remoteEnvironment;
|
||||
const r: IInitData = {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
|
||||
parentPid: remoteEnv.pid,
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug,
|
||||
appRoot: remoteEnv.appRoot,
|
||||
appSettingsHome: remoteEnv.appSettingsHome,
|
||||
appName: this._productService.nameLong,
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
|
||||
globalStorageHome: remoteEnv.globalStorageHome,
|
||||
userHome: remoteEnv.userHome,
|
||||
webviewResourceRoot: this._environmentService.webviewResourceRoot,
|
||||
webviewCspSource: this._environmentService.webviewCspSource,
|
||||
},
|
||||
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : {
|
||||
configuration: workspace.configuration,
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace)
|
||||
},
|
||||
remote: {
|
||||
isRemote: true,
|
||||
authority: this._initDataProvider.remoteAuthority,
|
||||
connectionData: remoteInitData.connectionData
|
||||
},
|
||||
resolvedExtensions: resolvedExtensions,
|
||||
hostExtensions: hostExtensions,
|
||||
extensions: remoteEnv.extensions,
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: remoteEnv.extensionHostLogsPath,
|
||||
logFile: joinPath(remoteEnv.extensionHostLogsPath, `${ExtensionHostLogFileName}.log`),
|
||||
autoStart: true,
|
||||
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
|
||||
};
|
||||
return r;
|
||||
});
|
||||
private async _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise<IInitData> {
|
||||
const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
|
||||
// Collect all identifiers for extension ids which can be considered "resolved"
|
||||
const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main).map(extension => extension.identifier);
|
||||
const hostExtensions = remoteInitData.allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
|
||||
parentPid: remoteInitData.pid,
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug,
|
||||
appRoot: remoteInitData.appRoot,
|
||||
appSettingsHome: remoteInitData.appSettingsHome,
|
||||
appName: this._productService.nameLong,
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
|
||||
globalStorageHome: remoteInitData.globalStorageHome,
|
||||
userHome: remoteInitData.userHome,
|
||||
webviewResourceRoot: this._environmentService.webviewResourceRoot,
|
||||
webviewCspSource: this._environmentService.webviewCspSource,
|
||||
},
|
||||
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : {
|
||||
configuration: workspace.configuration,
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace)
|
||||
},
|
||||
remote: {
|
||||
isRemote: true,
|
||||
authority: this._initDataProvider.remoteAuthority,
|
||||
connectionData: remoteInitData.connectionData
|
||||
},
|
||||
resolvedExtensions: resolvedExtensions,
|
||||
hostExtensions: hostExtensions,
|
||||
extensions: remoteInitData.extensions,
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: remoteInitData.extensionHostLogsPath,
|
||||
logFile: joinPath(remoteInitData.extensionHostLogsPath, `${ExtensionHostLogFileName}.log`),
|
||||
autoStart: true,
|
||||
uiKind: platform.isWeb ? UIKind.Web : UIKind.Desktop
|
||||
};
|
||||
}
|
||||
|
||||
getInspectPort(): number | undefined {
|
||||
@@ -1,40 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
|
||||
export const IStaticExtensionsService = createDecorator<IStaticExtensionsService>('IStaticExtensionsService');
|
||||
|
||||
export interface IStaticExtensionsService {
|
||||
readonly _serviceBrand: undefined;
|
||||
getExtensions(): Promise<IExtensionDescription[]>;
|
||||
}
|
||||
|
||||
export class StaticExtensionsService implements IStaticExtensionsService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _descriptions: IExtensionDescription[] = [];
|
||||
|
||||
constructor(@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService) {
|
||||
const staticExtensions = environmentService.options && Array.isArray(environmentService.options.staticExtensions) ? environmentService.options.staticExtensions : [];
|
||||
|
||||
this._descriptions = staticExtensions.map(data => <IExtensionDescription>{
|
||||
identifier: new ExtensionIdentifier(`${data.packageJSON.publisher}.${data.packageJSON.name}`),
|
||||
extensionLocation: data.extensionLocation,
|
||||
isBuiltin: !!data.isBuiltin,
|
||||
...data.packageJSON,
|
||||
});
|
||||
}
|
||||
|
||||
async getExtensions(): Promise<IExtensionDescription[]> {
|
||||
return this._descriptions;
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IStaticExtensionsService, StaticExtensionsService, true);
|
||||
@@ -3,28 +3,27 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
|
||||
import { LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
|
||||
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
|
||||
import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager';
|
||||
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 } from 'vs/platform/extensions/common/extensions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
@@ -32,7 +31,6 @@ import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteA
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
@@ -41,6 +39,8 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/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';
|
||||
|
||||
class DeltaExtensionsQueueItem {
|
||||
constructor(
|
||||
@@ -51,8 +51,9 @@ class DeltaExtensionsQueueItem {
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
private readonly _remoteEnvironment: Map<string, IRemoteAgentEnvironment>;
|
||||
|
||||
private readonly _enableLocalWebWorker: boolean;
|
||||
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
|
||||
private _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
private readonly _extensionScanner: CachedExtensionScanner;
|
||||
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
|
||||
|
||||
@@ -69,7 +70,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IStaticExtensionsService private readonly _staticExtensions: IStaticExtensionsService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@IElectronService private readonly _electronService: IElectronService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
|
||||
@@ -85,16 +86,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
productService
|
||||
);
|
||||
|
||||
if (this._extensionEnablementService.allUserExtensionsDisabled) {
|
||||
this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{
|
||||
label: nls.localize('Reload', "Reload"),
|
||||
run: () => {
|
||||
this._hostService.reload();
|
||||
}
|
||||
}]);
|
||||
}
|
||||
this._enableLocalWebWorker = this._configurationService.getValue<boolean>(webWorkerExtHostConfig);
|
||||
|
||||
this._remoteEnvironment = new Map<string, IRemoteAgentEnvironment>();
|
||||
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
|
||||
this._deltaExtensionsQueue = [];
|
||||
@@ -142,8 +137,28 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._initialize();
|
||||
}, 50 /*max delay*/);
|
||||
});
|
||||
|
||||
// delay notification for extensions disabled until workbench restored
|
||||
if (this._extensionEnablementService.allUserExtensionsDisabled) {
|
||||
this._lifecycleService.when(LifecyclePhase.Restored).then(() => {
|
||||
this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{
|
||||
label: nls.localize('Reload', "Reload"),
|
||||
run: () => {
|
||||
this._hostService.reload();
|
||||
}
|
||||
}]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
return extensionHostManager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//#region deltaExtensions
|
||||
|
||||
@@ -222,11 +237,12 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._checkEnableProposedApi(toAdd);
|
||||
|
||||
// Update extension points
|
||||
this._rehandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
|
||||
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
|
||||
|
||||
// Update the extension host
|
||||
if (this._extensionHostProcessManagers.length > 0) {
|
||||
await this._extensionHostProcessManagers[0].deltaExtensions(toAdd, toRemove.map(e => e.identifier));
|
||||
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++) {
|
||||
@@ -234,15 +250,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
}
|
||||
|
||||
private _rehandleExtensionPoints(extensionDescriptions: IExtensionDescription[]): void {
|
||||
this._doHandleExtensionPoints(extensionDescriptions);
|
||||
}
|
||||
|
||||
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
|
||||
return this._canAddExtension(toExtension(extensionDescription));
|
||||
}
|
||||
|
||||
public _canAddExtension(extension: IExtension): boolean {
|
||||
private _canAddExtension(extension: IExtension): boolean {
|
||||
if (this._environmentService.configuration.remoteAuthority) {
|
||||
return false;
|
||||
}
|
||||
@@ -338,57 +350,78 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
if (shouldActivate) {
|
||||
await Promise.all(
|
||||
this._extensionHostProcessManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
|
||||
).then(() => { });
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
private _createProvider(remoteAuthority: string): IInitDataProvider {
|
||||
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
|
||||
return flatten(await Promise.all([
|
||||
this._extensionScanner.scannedExtensions,
|
||||
this._webExtensionsScannerService.scanExtensions().then(extensions => extensions.map(parseScannedExtension))
|
||||
]));
|
||||
}
|
||||
|
||||
private _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation) {
|
||||
return {
|
||||
remoteAuthority: remoteAuthority,
|
||||
getInitData: async () => {
|
||||
await this.whenInstalledExtensionsRegistered();
|
||||
const connectionData = this._remoteAuthorityResolverService.getConnectionData(remoteAuthority);
|
||||
const remoteEnvironment = this._remoteEnvironment.get(remoteAuthority)!;
|
||||
return { connectionData, remoteEnvironment };
|
||||
if (isInitialStart) {
|
||||
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
|
||||
const runningLocation = determineRunningLocation(this._productService, this._configurationService, localExtensions, [], false, this._enableLocalWebWorker);
|
||||
const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: false,
|
||||
extensions: localProcessExtensions
|
||||
};
|
||||
} else {
|
||||
// restart case
|
||||
const allExtensions = await this.getExtensions();
|
||||
const localProcessExtensions = filterByRunningLocation(allExtensions, this._runningLocation, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: true,
|
||||
extensions: localProcessExtensions
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] {
|
||||
let autoStart: boolean;
|
||||
let extensions: Promise<IExtensionDescription[]>;
|
||||
if (isInitialStart) {
|
||||
autoStart = false;
|
||||
extensions = this._extensionScanner.scannedExtensions.then(extensions => extensions.filter(extension => this._isEnabled(extension))); // remove disabled extensions
|
||||
} else {
|
||||
// restart case
|
||||
autoStart = true;
|
||||
extensions = this.getExtensions().then((extensions) => extensions.filter(ext => ext.extensionLocation.scheme === Schemas.file));
|
||||
private _createRemoteExtensionHostDataProvider(remoteAuthority: string): IRemoteExtensionHostDataProvider {
|
||||
return {
|
||||
remoteAuthority: remoteAuthority,
|
||||
getInitData: async () => {
|
||||
await this.whenInstalledExtensionsRegistered();
|
||||
return this._remoteInitData.get(remoteAuthority)!;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
const localProcessExtHost = this._instantiationService.createInstance(LocalProcessExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalProcess));
|
||||
result.push(localProcessExtHost);
|
||||
|
||||
if (this._enableLocalWebWorker) {
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
|
||||
result.push(webWorkerExtHost);
|
||||
}
|
||||
|
||||
const result: ExtensionHostProcessManager[] = [];
|
||||
|
||||
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._environmentService.extHostLogsPath);
|
||||
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents);
|
||||
result.push(extHostProcessManager);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents);
|
||||
result.push(remoteExtHostProcessManager);
|
||||
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
result.push(remoteExtHost);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void {
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
|
||||
if (extensionHost.isLocal) {
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
|
||||
if (code === 55) {
|
||||
this._notificationService.prompt(
|
||||
Severity.Error,
|
||||
@@ -437,10 +470,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
return;
|
||||
}
|
||||
|
||||
const extensionHost = this._extensionHostProcessManagers[0];
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
|
||||
try {
|
||||
const result = await extensionHost.resolveAuthority(remoteAuthority);
|
||||
const result = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(result.authority, result.options);
|
||||
} catch (err) {
|
||||
this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err);
|
||||
@@ -451,25 +484,19 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._extensionScanner.startScanningExtensions(this.createLogger());
|
||||
|
||||
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
|
||||
const extensionHost = this._extensionHostProcessManagers[0];
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
|
||||
const allExtensions = flatten(await Promise.all([this._extensionScanner.scannedExtensions, this._staticExtensions.getExtensions()]));
|
||||
|
||||
// enable or disable proposed API per extension
|
||||
this._checkEnableProposedApi(allExtensions);
|
||||
|
||||
// remove disabled extensions
|
||||
let localExtensions = remove(allExtensions, extension => this._isDisabled(extension));
|
||||
let localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
|
||||
let remoteEnv: IRemoteAgentEnvironment | null = null;
|
||||
|
||||
if (remoteAuthority) {
|
||||
let resolvedAuthority: ResolverResult;
|
||||
let resolverResult: ResolverResult;
|
||||
|
||||
try {
|
||||
resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority);
|
||||
resolverResult = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
|
||||
} catch (err) {
|
||||
const remoteName = getRemoteName(remoteAuthority);
|
||||
if (RemoteAuthorityResolverError.isNoResolverFound(err)) {
|
||||
err.isHandled = await this._handleNoResolverFound(remoteName, allExtensions);
|
||||
err.isHandled = await this._handleNoResolverFound(remoteAuthority);
|
||||
} else {
|
||||
console.log(err);
|
||||
if (RemoteAuthorityResolverError.isHandled(err)) {
|
||||
@@ -479,22 +506,18 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err);
|
||||
|
||||
// Proceed with the local extension host
|
||||
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
|
||||
await this._startLocalExtensionHost(localExtensions);
|
||||
return;
|
||||
}
|
||||
|
||||
// set the resolved authority
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(resolvedAuthority.authority, resolvedAuthority.options);
|
||||
this._remoteExplorerService.setTunnelInformation(resolvedAuthority.tunnelInformation);
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(resolverResult.authority, resolverResult.options);
|
||||
this._remoteExplorerService.setTunnelInformation(resolverResult.tunnelInformation);
|
||||
|
||||
// monitor for breakage
|
||||
const connection = this._remoteAgentService.getConnection();
|
||||
if (connection) {
|
||||
connection.onDidStateChange(async (e) => {
|
||||
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
|
||||
if (!remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
if (e.type === PersistentConnectionEventType.ConnectionLost) {
|
||||
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
|
||||
}
|
||||
@@ -503,80 +526,64 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
|
||||
// fetch the remote environment
|
||||
const remoteEnv = (await this._remoteAgentService.getEnvironment());
|
||||
remoteEnv = await this._remoteAgentService.getEnvironment();
|
||||
|
||||
if (!remoteEnv) {
|
||||
this._notificationService.notify({ severity: Severity.Error, message: nls.localize('getEnvironmentFailure', "Could not fetch remote environment") });
|
||||
// Proceed with the local extension host
|
||||
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
|
||||
await this._startLocalExtensionHost(localExtensions);
|
||||
return;
|
||||
}
|
||||
|
||||
// enable or disable proposed API per extension
|
||||
this._checkEnableProposedApi(remoteEnv.extensions);
|
||||
|
||||
// remove disabled extensions
|
||||
remoteEnv.extensions = remove(remoteEnv.extensions, extension => this._isDisabled(extension));
|
||||
|
||||
// Determine where each extension will execute, based on extensionKind
|
||||
const isInstalledLocally = new Set<string>();
|
||||
localExtensions.forEach(ext => isInstalledLocally.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const isInstalledRemotely = new Set<string>();
|
||||
remoteEnv.extensions.forEach(ext => isInstalledRemotely.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const enum RunningLocation { None, Local, Remote }
|
||||
const pickRunningLocation = (extension: IExtensionDescription): RunningLocation => {
|
||||
for (const extensionKind of getExtensionKind(extension, this._productService, this._configurationService)) {
|
||||
if (extensionKind === 'ui') {
|
||||
if (isInstalledLocally.has(ExtensionIdentifier.toKey(extension.identifier))) {
|
||||
return RunningLocation.Local;
|
||||
}
|
||||
} else if (extensionKind === 'workspace') {
|
||||
if (isInstalledRemotely.has(ExtensionIdentifier.toKey(extension.identifier))) {
|
||||
return RunningLocation.Remote;
|
||||
}
|
||||
}
|
||||
}
|
||||
return RunningLocation.None;
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, RunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteEnv.extensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
|
||||
// remove non-UI extensions from the local extensions
|
||||
localExtensions = localExtensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Local);
|
||||
|
||||
// in case of UI extensions overlap, the local extension wins
|
||||
remoteEnv.extensions = remoteEnv.extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === RunningLocation.Remote);
|
||||
|
||||
// save for remote extension's init data
|
||||
this._remoteEnvironment.set(remoteAuthority, remoteEnv);
|
||||
|
||||
await this._startLocalExtensionHost(extensionHost, remoteEnv.extensions.concat(localExtensions), localExtensions.map(extension => extension.identifier));
|
||||
} else {
|
||||
await this._startLocalExtensionHost(extensionHost, localExtensions, localExtensions.map(extension => extension.identifier));
|
||||
}
|
||||
|
||||
await this._startLocalExtensionHost(localExtensions, remoteAuthority, remoteEnv);
|
||||
}
|
||||
|
||||
private async _startLocalExtensionHost(extensionHost: ExtensionHostProcessManager, allExtensions: IExtensionDescription[], localExtensions: ExtensionIdentifier[]): Promise<void> {
|
||||
this._registerAndHandleExtensions(allExtensions);
|
||||
extensionHost.start(localExtensions.filter(id => this._registry.containsExtension(id)));
|
||||
}
|
||||
private async _startLocalExtensionHost(localExtensions: IExtensionDescription[], remoteAuthority: string | undefined = undefined, remoteEnv: IRemoteAgentEnvironment | null = null): Promise<void> {
|
||||
|
||||
private _registerAndHandleExtensions(allExtensions: IExtensionDescription[]): void {
|
||||
const result = this._registry.deltaExtensions(allExtensions, []);
|
||||
let remoteExtensions = remoteEnv ? this._checkEnabledAndProposedAPI(remoteEnv.extensions) : [];
|
||||
|
||||
this._runningLocation = determineRunningLocation(this._productService, this._configurationService, localExtensions, remoteExtensions, Boolean(remoteAuthority), this._enableLocalWebWorker);
|
||||
|
||||
// remove non-UI extensions from the local extensions
|
||||
const localProcessExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalProcess);
|
||||
const localWebWorkerExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
|
||||
remoteExtensions = filterByRunningLocation(remoteExtensions, this._runningLocation, ExtensionRunningLocation.Remote);
|
||||
|
||||
const result = this._registry.deltaExtensions(remoteExtensions.concat(localProcessExtensions).concat(localWebWorkerExtensions), []);
|
||||
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(', ')));
|
||||
}
|
||||
|
||||
if (remoteAuthority && remoteEnv) {
|
||||
this._remoteInitData.set(remoteAuthority, {
|
||||
connectionData: this._remoteAuthorityResolverService.getConnectionData(remoteAuthority),
|
||||
pid: remoteEnv.pid,
|
||||
appRoot: remoteEnv.appRoot,
|
||||
appSettingsHome: remoteEnv.appSettingsHome,
|
||||
extensionHostLogsPath: remoteEnv.extensionHostLogsPath,
|
||||
globalStorageHome: remoteEnv.globalStorageHome,
|
||||
userHome: remoteEnv.userHome,
|
||||
extensions: remoteExtensions,
|
||||
allExtensions: this._registry.getAllExtensionDescriptions(),
|
||||
});
|
||||
}
|
||||
|
||||
this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions());
|
||||
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
localProcessExtensionHost.start(localProcessExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
|
||||
|
||||
const localWebWorkerExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalWebWorker);
|
||||
if (localWebWorkerExtensionHost) {
|
||||
localWebWorkerExtensionHost.start(localWebWorkerExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
|
||||
}
|
||||
}
|
||||
|
||||
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
if (this._extensionHostProcessManagers.length > 0) {
|
||||
return this._extensionHostProcessManagers[0].getInspectPort(tryEnableInspector);
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
return localProcessExtensionHost.getInspectPort(tryEnableInspector);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -591,7 +598,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleNoResolverFound(remoteName: string, allExtensions: IExtensionDescription[]): Promise<boolean> {
|
||||
private async _handleNoResolverFound(remoteAuthority: string): Promise<boolean> {
|
||||
const remoteName = getRemoteName(remoteAuthority);
|
||||
const recommendation = this._productService.remoteExtensionTips?.[remoteName];
|
||||
if (!recommendation) {
|
||||
return false;
|
||||
@@ -607,9 +615,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
};
|
||||
|
||||
const resolverExtensionId = recommendation.extensionId;
|
||||
const allExtensions = await this._scanAllLocalExtensions();
|
||||
const extension = allExtensions.filter(e => e.identifier.value === resolverExtensionId)[0];
|
||||
if (extension) {
|
||||
if (this._isDisabled(extension)) {
|
||||
if (!this._isEnabled(extension)) {
|
||||
const message = nls.localize('enableResolver', "Extension '{0}' is required to open the remote window.\nOK to enable?", recommendation.friendlyName);
|
||||
this._notificationService.prompt(Severity.Info, message,
|
||||
[{
|
||||
@@ -649,27 +658,59 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function remove(arr: IExtensionDescription[], predicate: (item: IExtensionDescription) => boolean): IExtensionDescription[];
|
||||
function remove(arr: IExtensionDescription[], toRemove: IExtensionDescription[]): IExtensionDescription[];
|
||||
function remove(arr: IExtensionDescription[], arg2: ((item: IExtensionDescription) => boolean) | IExtensionDescription[]): IExtensionDescription[] {
|
||||
if (typeof arg2 === 'function') {
|
||||
return _removePredicate(arr, arg2);
|
||||
}
|
||||
return _removeSet(arr, arg2);
|
||||
const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
function _removePredicate(arr: IExtensionDescription[], predicate: (item: IExtensionDescription) => boolean): IExtensionDescription[] {
|
||||
return arr.filter(extension => !predicate(extension));
|
||||
function determineRunningLocation(productService: IProductService, configurationService: IConfigurationService, localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], hasRemote: boolean, hasLocalWebWorker: boolean): Map<string, ExtensionRunningLocation> {
|
||||
const localExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const remoteExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
for (const extensionKind of getExtensionKind(extension, productService, configurationService)) {
|
||||
if (extensionKind === 'ui' && isInstalledLocally) {
|
||||
// ui extensions run locally if possible
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'workspace' && !hasRemote) {
|
||||
// workspace extensions also run locally if there is no remote
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally && hasLocalWebWorker) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
if (typeof extension.browser !== 'undefined') {
|
||||
// The "browser" field determines the entry point
|
||||
(<any>extension).main = extension.browser;
|
||||
}
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
return ExtensionRunningLocation.None;
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
return runningLocation;
|
||||
}
|
||||
|
||||
function _removeSet(arr: IExtensionDescription[], toRemove: IExtensionDescription[]): IExtensionDescription[] {
|
||||
const toRemoveSet = new Set<string>();
|
||||
toRemove.forEach(extension => toRemoveSet.add(ExtensionIdentifier.toKey(extension.identifier)));
|
||||
return arr.filter(extension => !toRemoveSet.has(ExtensionIdentifier.toKey(extension.identifier)));
|
||||
function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === desiredRunningLocation);
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionService, ExtensionService);
|
||||
@@ -693,4 +734,4 @@ class RestartExtensionHostAction extends Action {
|
||||
}
|
||||
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(RestartExtensionHostAction), 'Developer: Restart Extension Host', nls.localize('developer', "Developer"));
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(RestartExtensionHostAction), 'Developer: Restart Extension Host', nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"));
|
||||
|
||||
@@ -37,7 +37,7 @@ import { 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 { IExtensionHostStarter, ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
@@ -45,7 +45,19 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output/common/output';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService';
|
||||
|
||||
export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
export interface ILocalProcessExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
readonly extensions: IExtensionDescription[];
|
||||
}
|
||||
|
||||
export interface ILocalProcessExtensionHostDataProvider {
|
||||
getInitData(): Promise<ILocalProcessExtensionHostInitData>;
|
||||
}
|
||||
|
||||
export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalProcess;
|
||||
public readonly remoteAuthority = null;
|
||||
|
||||
private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>();
|
||||
public readonly onExit: Event<[number, string]> = this._onExit.event;
|
||||
@@ -73,9 +85,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
private readonly _extensionHostLogFile: URI;
|
||||
|
||||
constructor(
|
||||
private readonly _autoStart: boolean,
|
||||
private readonly _extensions: Promise<IExtensionDescription[]>,
|
||||
private readonly _extensionHostLogsLocation: URI,
|
||||
private readonly _initDataProvider: ILocalProcessExtensionHostDataProvider,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IElectronService private readonly _electronService: IElectronService,
|
||||
@@ -103,7 +113,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
this._extensionHostConnection = null;
|
||||
this._messageProtocol = null;
|
||||
|
||||
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
|
||||
this._extensionHostLogFile = joinPath(this._environmentService.extHostLogsPath, `${ExtensionHostLogFileName}.log`);
|
||||
|
||||
this._toDispose.add(this._onExit);
|
||||
this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e)));
|
||||
@@ -410,52 +420,49 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
|
||||
});
|
||||
}
|
||||
|
||||
private _createExtHostInitData(): Promise<IInitData> {
|
||||
return Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions])
|
||||
.then(([telemetryInfo, extensionDescriptions]) => {
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
const r: IInitData = {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
|
||||
parentPid: process.pid,
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
|
||||
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
|
||||
appSettingsHome: this._environmentService.appSettingsHome ? this._environmentService.appSettingsHome : undefined,
|
||||
appName: this._productService.nameLong,
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
|
||||
globalStorageHome: URI.file(this._environmentService.globalStorageHome),
|
||||
userHome: this._environmentService.userHome,
|
||||
webviewResourceRoot: this._environmentService.webviewResourceRoot,
|
||||
webviewCspSource: this._environmentService.webviewCspSource,
|
||||
},
|
||||
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
|
||||
configuration: withNullAsUndefined(workspace.configuration),
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace),
|
||||
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false
|
||||
},
|
||||
remote: {
|
||||
authority: this._environmentService.configuration.remoteAuthority,
|
||||
connectionData: null,
|
||||
isRemote: false
|
||||
},
|
||||
resolvedExtensions: [],
|
||||
hostExtensions: [],
|
||||
extensions: extensionDescriptions,
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: this._extensionHostLogsLocation,
|
||||
logFile: this._extensionHostLogFile,
|
||||
autoStart: this._autoStart,
|
||||
uiKind: UIKind.Desktop
|
||||
};
|
||||
return r;
|
||||
});
|
||||
private async _createExtHostInitData(): Promise<IInitData> {
|
||||
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
|
||||
parentPid: process.pid,
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
|
||||
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
|
||||
appSettingsHome: this._environmentService.appSettingsHome ? this._environmentService.appSettingsHome : undefined,
|
||||
appName: this._productService.nameLong,
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
|
||||
globalStorageHome: URI.file(this._environmentService.globalStorageHome),
|
||||
userHome: this._environmentService.userHome,
|
||||
webviewResourceRoot: this._environmentService.webviewResourceRoot,
|
||||
webviewCspSource: this._environmentService.webviewCspSource,
|
||||
},
|
||||
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : {
|
||||
configuration: withNullAsUndefined(workspace.configuration),
|
||||
id: workspace.id,
|
||||
name: this._labelService.getWorkspaceLabel(workspace),
|
||||
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false
|
||||
},
|
||||
remote: {
|
||||
authority: this._environmentService.configuration.remoteAuthority,
|
||||
connectionData: null,
|
||||
isRemote: false
|
||||
},
|
||||
resolvedExtensions: [],
|
||||
hostExtensions: [],
|
||||
extensions: initData.extensions,
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: this._environmentService.extHostLogsPath,
|
||||
logFile: this._extensionHostLogFile,
|
||||
autoStart: initData.autoStart,
|
||||
uiKind: UIKind.Desktop
|
||||
};
|
||||
}
|
||||
|
||||
private _logExtensionHostMessage(entry: IRemoteConsoleLog) {
|
||||
@@ -22,6 +22,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/worker/extHostLogService';
|
||||
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
import { NotImplementedProxy } from 'vs/base/common/types';
|
||||
|
||||
// register singleton services
|
||||
@@ -29,6 +30,7 @@ registerSingleton(ILogService, ExtHostLogService);
|
||||
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
|
||||
registerSingleton(IExtHostOutputService, ExtHostOutputService);
|
||||
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
|
||||
registerSingleton(IExtHostWindow, ExtHostWindow);
|
||||
registerSingleton(IExtHostDecorations, ExtHostDecorations);
|
||||
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
|
||||
registerSingleton(IExtHostCommands, ExtHostCommands);
|
||||
|
||||
Reference in New Issue
Block a user