mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
Merge pull request #144840 from microsoft/alex/multiple-local-extension-hosts
Run multiple local extension hosts
This commit is contained in:
commit
5f5e1ca791
|
@ -197,9 +197,9 @@ class ExtensionHostProxy implements IExtensionHostProxy {
|
|||
resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
return this._actual.$resolveAuthority(remoteAuthority, resolveAttempt);
|
||||
}
|
||||
async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI | null> {
|
||||
const uriComponents = await this._actual.$getCanonicalURI(remoteAuthority, uri);
|
||||
return URI.revive(uriComponents);
|
||||
return (uriComponents ? URI.revive(uriComponents) : uriComponents);
|
||||
}
|
||||
startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
return this._actual.$startExtensionHost(enabledExtensionIds);
|
||||
|
|
|
@ -1339,7 +1339,10 @@ export interface ExtHostSearchShape {
|
|||
|
||||
export interface ExtHostExtensionServiceShape {
|
||||
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||
$getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise<UriComponents>;
|
||||
/**
|
||||
* Returns `null` if no resolver for `remoteAuthority` is found.
|
||||
*/
|
||||
$getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise<UriComponents | null>;
|
||||
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
$extensionTestsExecute(): Promise<number>;
|
||||
$extensionTestsExit(code: number): Promise<void>;
|
||||
|
|
|
@ -753,12 +753,13 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
|||
}
|
||||
}
|
||||
|
||||
public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise<UriComponents> {
|
||||
public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise<UriComponents | null> {
|
||||
this._logService.info(`$getCanonicalURI invoked for authority (${getRemoteAuthorityPrefix(remoteAuthority)})`);
|
||||
|
||||
const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority);
|
||||
const { resolver } = await this._activateAndGetResolver(remoteAuthority);
|
||||
if (!resolver) {
|
||||
throw new Error(`Cannot get canonical URI because no remote extension is installed to resolve ${authorityPrefix}`);
|
||||
// Return `null` if no resolver for `remoteAuthority` is found.
|
||||
return null;
|
||||
}
|
||||
|
||||
const uri = URI.revive(uriComponents);
|
||||
|
|
|
@ -11,7 +11,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IExtensionService, IExtensionsStatus, IExtensionHostProfile, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IExtensionsStatus, IExtensionHostProfile, LocalWebWorkerRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { append, $, Dimension, clearNode, addDisposableListener } from 'vs/base/browser/dom';
|
||||
|
@ -36,6 +36,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/common/runtimeExtensionsInput';
|
||||
import { Action2, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
interface IExtensionProfileInformation {
|
||||
/**
|
||||
|
@ -80,6 +81,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
|
|||
@IStorageService storageService: IStorageService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||
) {
|
||||
super(AbstractRuntimeExtensionsEditor.ID, telemetryService, themeService, storageService);
|
||||
|
||||
|
@ -370,7 +372,7 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
|
|||
}
|
||||
|
||||
let extraLabel: string | null = null;
|
||||
if (element.status.runningLocation === ExtensionRunningLocation.LocalWebWorker) {
|
||||
if (element.status.runningLocation && element.status.runningLocation.equals(new LocalWebWorkerRunningLocation())) {
|
||||
extraLabel = `$(globe) web worker`;
|
||||
} else if (element.description.extensionLocation.scheme === Schemas.vscodeRemote) {
|
||||
const hostLabel = this._labelService.getHostLabel(Schemas.vscodeRemote, this._environmentService.remoteAuthority);
|
||||
|
@ -379,6 +381,8 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
|
|||
} else {
|
||||
extraLabel = `$(remote) ${element.description.extensionLocation.authority}`;
|
||||
}
|
||||
} else if (element.status.runningLocation && element.status.runningLocation.affinity > 0) {
|
||||
extraLabel = `$(server-process) local process ${element.status.runningLocation.affinity + 1}`;
|
||||
}
|
||||
|
||||
if (extraLabel) {
|
||||
|
@ -427,11 +431,21 @@ export abstract class AbstractRuntimeExtensionsEditor extends EditorPane {
|
|||
|
||||
const actions: IAction[] = [];
|
||||
|
||||
actions.push(new Action(
|
||||
'runtimeExtensionsEditor.action.copyId',
|
||||
nls.localize('copy id', "Copy id ({0})", e.element!.description.identifier.value),
|
||||
undefined,
|
||||
true,
|
||||
() => {
|
||||
this._clipboardService.writeText(e.element!.description.identifier.value);
|
||||
}
|
||||
));
|
||||
|
||||
const reportExtensionIssueAction = this._createReportExtensionIssueAction(e.element);
|
||||
if (reportExtensionIssueAction) {
|
||||
actions.push(reportExtensionIssueAction);
|
||||
actions.push(new Separator());
|
||||
}
|
||||
actions.push(new Separator());
|
||||
|
||||
if (e.element!.marketplaceInfo) {
|
||||
actions.push(new Action('runtimeExtensionsEditor.action.disableWorkspace', nls.localize('disable workspace', "Disable (Workspace)"), undefined, true, () => this._extensionsWorkbenchService.setEnablement(e.element!.marketplaceInfo!, EnablementState.DisabledWorkspace)));
|
||||
|
|
|
@ -4,38 +4,12 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IExtensionService, IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { AbstractRuntimeExtensionsEditor, IRuntimeExtension } from 'vs/workbench/contrib/extensions/browser/abstractRuntimeExtensionsEditor';
|
||||
|
||||
export class RuntimeExtensionsEditor extends AbstractRuntimeExtensionsEditor {
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
) {
|
||||
super(telemetryService, themeService, contextKeyService, extensionsWorkbenchService, extensionService, notificationService, contextMenuService, instantiationService, storageService, labelService, environmentService);
|
||||
}
|
||||
|
||||
protected _getProfileInfo(): IExtensionHostProfile | null {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as nls from 'vs/nls';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IDebugService } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
|
@ -29,8 +29,8 @@ export class DebugExtensionHostAction extends Action {
|
|||
|
||||
override async run(): Promise<any> {
|
||||
|
||||
const inspectPort = await this._extensionService.getInspectPort(false);
|
||||
if (!inspectPort) {
|
||||
const inspectPorts = await this._extensionService.getInspectPorts(ExtensionHostKind.LocalProcess, false);
|
||||
if (inspectPorts.length === 0) {
|
||||
const res = await this._dialogService.confirm({
|
||||
type: 'info',
|
||||
message: nls.localize('restart1', "Profile Extensions"),
|
||||
|
@ -45,11 +45,16 @@ export class DebugExtensionHostAction extends Action {
|
|||
return;
|
||||
}
|
||||
|
||||
if (inspectPorts.length > 1) {
|
||||
// TODO
|
||||
console.warn(`There are multiple extension hosts available for debugging. Picking the first one...`);
|
||||
}
|
||||
|
||||
return this._debugService.startDebugging(undefined, {
|
||||
type: 'node',
|
||||
name: nls.localize('debugExtensionHost.launch.name', "Attach Extension Host"),
|
||||
request: 'attach',
|
||||
port: inspectPort
|
||||
port: inspectPorts[0]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import * as nls from 'vs/nls';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHostProfile, ProfileSession, IExtensionService, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/browser/statusbar';
|
||||
|
@ -116,8 +116,9 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
|
|||
return null;
|
||||
}
|
||||
|
||||
const inspectPort = await this._extensionService.getInspectPort(true);
|
||||
if (!inspectPort) {
|
||||
const inspectPorts = await this._extensionService.getInspectPorts(ExtensionHostKind.LocalProcess, true);
|
||||
|
||||
if (inspectPorts.length === 0) {
|
||||
return this._dialogService.confirm({
|
||||
type: 'info',
|
||||
message: nls.localize('restart1', "Profile Extensions"),
|
||||
|
@ -131,9 +132,14 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
|
|||
});
|
||||
}
|
||||
|
||||
if (inspectPorts.length > 1) {
|
||||
// TODO
|
||||
console.warn(`There are multiple extension hosts available for profiling. Picking the first one...`);
|
||||
}
|
||||
|
||||
this._setState(ProfileSessionState.Starting);
|
||||
|
||||
return this._instantiationService.createInstance(ExtensionHostProfiler, inspectPort).start().then((value) => {
|
||||
return this._instantiationService.createInstance(ExtensionHostProfiler, inspectPorts[0]).start().then((value) => {
|
||||
this._profileSession = value;
|
||||
this._setState(ProfileSessionState.Running);
|
||||
}, (err) => {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, IExtensionHostProfile, ProfileSession } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IResponsiveStateChangeEvent, IExtensionHostProfile, ProfileSession, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
@ -46,8 +46,11 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont
|
|||
}
|
||||
|
||||
private async _onDidChangeResponsiveChange(event: IResponsiveStateChangeEvent): Promise<void> {
|
||||
if (event.extensionHostKind !== ExtensionHostKind.LocalProcess) {
|
||||
return;
|
||||
}
|
||||
|
||||
const port = await this._extensionService.getInspectPort(true);
|
||||
const port = await this._extensionService.getInspectPort(event.extensionHostId, true);
|
||||
|
||||
if (!port) {
|
||||
return;
|
||||
|
|
|
@ -26,6 +26,7 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IV8Profile, Utils } from 'vs/platform/profiling/common/profiling';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export const IExtensionHostProfileService = createDecorator<IExtensionHostProfileService>('extensionHostProfileService');
|
||||
export const CONTEXT_PROFILE_SESSION_STATE = new RawContextKey<string>('profileSessionState', 'none');
|
||||
|
@ -72,9 +73,10 @@ export class RuntimeExtensionsEditor extends AbstractRuntimeExtensionsEditor {
|
|||
@IStorageService storageService: IStorageService,
|
||||
@ILabelService labelService: ILabelService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService,
|
||||
) {
|
||||
super(telemetryService, themeService, contextKeyService, extensionsWorkbenchService, extensionService, notificationService, contextMenuService, instantiationService, storageService, labelService, environmentService);
|
||||
super(telemetryService, themeService, contextKeyService, extensionsWorkbenchService, extensionService, notificationService, contextMenuService, instantiationService, storageService, labelService, environmentService, clipboardService);
|
||||
this._profileInfo = this._extensionHostProfileService.lastProfile;
|
||||
this._extensionsHostRecorded = CONTEXT_EXTENSION_HOST_PROFILE_RECORDED.bindTo(contextKeyService);
|
||||
this._profileSessionState = CONTEXT_PROFILE_SESSION_STATE.bindTo(contextKeyService);
|
||||
|
|
|
@ -9,14 +9,14 @@ import { IWorkbenchExtensionEnablementService, IWebExtensionsScannerService } fr
|
|||
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, IExtensionHost, toExtensionDescription, ExtensionRunningLocation, extensionRunningLocationToString } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IExtensionHost, toExtensionDescription, ExtensionRunningLocation, ExtensionHostKind, extensionHostKindToString } 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, ExtensionRunningPreference, extensionRunningPreferenceToString } 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 { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IWebWorkerExtensionHostDataProvider, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExtensionIdentifier, IExtensionDescription, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionKind } from 'vs/platform/environment/common/environment';
|
||||
|
@ -72,8 +72,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
logService
|
||||
);
|
||||
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
// Initialize installed extensions first and do it only after workbench is ready
|
||||
this._lifecycleService.when(LifecyclePhase.Ready).then(async () => {
|
||||
await this._userDataInitializationService.initializeInstalledExtensions(this._instantiationService);
|
||||
|
@ -107,11 +105,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
this._disposables.add(this._fileService.registerProvider(Schemas.https, provider));
|
||||
}
|
||||
|
||||
private _createLocalExtensionHostDataProvider() {
|
||||
private _createLocalExtensionHostDataProvider(desiredRunningLocation: ExtensionRunningLocation): IWebWorkerExtensionHostDataProvider {
|
||||
return {
|
||||
getInitData: async () => {
|
||||
const allExtensions = await this.getExtensions();
|
||||
const localWebWorkerExtensions = filterByRunningLocation(allExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
|
||||
const localWebWorkerExtensions = this._filterByRunningLocation(allExtensions, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: true,
|
||||
extensions: localWebWorkerExtensions
|
||||
|
@ -130,20 +128,20 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
};
|
||||
}
|
||||
|
||||
protected _pickRunningLocation(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation {
|
||||
protected _pickExtensionHostKind(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionHostKind | null {
|
||||
const result = ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference);
|
||||
this._logService.trace(`pickRunningLocation for ${extensionId.value}, extension kinds: [${extensionKinds.join(', ')}], isInstalledLocally: ${isInstalledLocally}, isInstalledRemotely: ${isInstalledRemotely}, preference: ${extensionRunningPreferenceToString(preference)} => ${extensionRunningLocationToString(result)}`);
|
||||
this._logService.trace(`pickRunningLocation for ${extensionId.value}, extension kinds: [${extensionKinds.join(', ')}], isInstalledLocally: ${isInstalledLocally}, isInstalledRemotely: ${isInstalledRemotely}, preference: ${extensionRunningPreferenceToString(preference)} => ${extensionHostKindToString(result)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation {
|
||||
const result: ExtensionRunningLocation[] = [];
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionHostKind | null {
|
||||
const result: ExtensionHostKind[] = [];
|
||||
let canRunRemotely = false;
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledRemotely) {
|
||||
// ui extensions run remotely if possible (but only as a last resort)
|
||||
if (preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
return ExtensionHostKind.Remote;
|
||||
} else {
|
||||
canRunRemotely = true;
|
||||
}
|
||||
|
@ -151,39 +149,42 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
return ExtensionHostKind.Remote;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
result.push(ExtensionHostKind.Remote);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'web' && (isInstalledLocally || isInstalledRemotely)) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
return ExtensionHostKind.LocalWebWorker;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalWebWorker);
|
||||
result.push(ExtensionHostKind.LocalWebWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (canRunRemotely) {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
result.push(ExtensionHostKind.Remote);
|
||||
}
|
||||
return (result.length > 0 ? result[0] : ExtensionRunningLocation.None);
|
||||
return (result.length > 0 ? result[0] : null);
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, false, this._createLocalExtensionHostDataProvider());
|
||||
result.push(webWorkerExtHost);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
result.push(remoteExtHost);
|
||||
protected _createExtensionHost(runningLocation: ExtensionRunningLocation, _isInitialStart: boolean): IExtensionHost | null {
|
||||
switch (runningLocation.kind) {
|
||||
case ExtensionHostKind.LocalProcess: {
|
||||
return null;
|
||||
}
|
||||
case ExtensionHostKind.LocalWebWorker: {
|
||||
return this._instantiationService.createInstance(WebWorkerExtensionHost, runningLocation, false, this._createLocalExtensionHostDataProvider(runningLocation));
|
||||
}
|
||||
case ExtensionHostKind.Remote: {
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
return this._instantiationService.createInstance(RemoteExtensionHost, runningLocation, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async _scanAndHandleExtensions(): Promise<void> {
|
||||
|
@ -199,12 +200,12 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
// `determineRunningLocation` will look at the complete picture (e.g. an extension installed on both sides),
|
||||
// takes care of duplicates and picks a running location for each extension
|
||||
this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions);
|
||||
this._initializeRunningLocation(localExtensions, remoteExtensions);
|
||||
|
||||
// Some remote extensions could run locally in the web worker, so store them
|
||||
const remoteExtensionsThatNeedToRunLocally = filterByRunningLocation(remoteExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
|
||||
localExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
|
||||
remoteExtensions = filterByRunningLocation(remoteExtensions, this._runningLocation, ExtensionRunningLocation.Remote);
|
||||
const remoteExtensionsThatNeedToRunLocally = this._filterByExtensionHostKind(remoteExtensions, ExtensionHostKind.LocalWebWorker);
|
||||
localExtensions = this._filterByExtensionHostKind(localExtensions, ExtensionHostKind.LocalWebWorker);
|
||||
remoteExtensions = this._filterByExtensionHostKind(remoteExtensions, ExtensionHostKind.Remote);
|
||||
|
||||
// Add locally the remote extensions that need to run locally in the web worker
|
||||
for (const ext of remoteExtensionsThatNeedToRunLocally) {
|
||||
|
@ -246,10 +247,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
}
|
||||
}
|
||||
|
||||
function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === desiredRunningLocation);
|
||||
}
|
||||
|
||||
function includes(extensions: IExtensionDescription[], identifier: ExtensionIdentifier): boolean {
|
||||
for (const extension of extensions) {
|
||||
if (ExtensionIdentifier.equals(extension.identifier, identifier)) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
|
|||
import * as platform from 'vs/base/common/platform';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, LocalWebWorkerRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
|
@ -30,6 +30,7 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
|||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { parentOriginHash } from 'vs/workbench/browser/webview';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
|
||||
export interface IWebWorkerExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
|
@ -42,9 +43,9 @@ export interface IWebWorkerExtensionHostDataProvider {
|
|||
|
||||
export class WebWorkerExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalWebWorker;
|
||||
public readonly remoteAuthority = null;
|
||||
public readonly lazyStart: boolean;
|
||||
public readonly extensions = new ExtensionDescriptionRegistry([]);
|
||||
|
||||
private readonly _onDidExit = this._register(new Emitter<[number, string | null]>());
|
||||
public readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
|
||||
|
@ -57,6 +58,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
|||
private readonly _extensionHostLogFile: URI;
|
||||
|
||||
constructor(
|
||||
public readonly runningLocation: LocalWebWorkerRunningLocation,
|
||||
lazyStart: boolean,
|
||||
private readonly _initDataProvider: IWebWorkerExtensionHostDataProvider,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
|
@ -265,6 +267,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
|||
private async _createExtHostInitData(): Promise<IExtensionHostInitData> {
|
||||
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
this.extensions.deltaExtensions(initData.extensions, []);
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
|
@ -288,7 +291,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
|||
},
|
||||
resolvedExtensions: [],
|
||||
hostExtensions: [],
|
||||
extensions: initData.extensions,
|
||||
extensions: this.extensions.getAllExtensionDescriptions(),
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: this._extensionHostLogsLocation,
|
||||
|
|
|
@ -15,7 +15,7 @@ import { IWebExtensionsScannerService, IWorkbenchExtensionEnablementService } fr
|
|||
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, IExtensionHost, ActivationKind, ExtensionHostKind, toExtensionDescription, ExtensionRunningLocation, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind, toExtensionDescription, ExtensionRunningLocation, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService, RemoteRunningLocation, LocalProcessRunningLocation, LocalWebWorkerRunningLocation } 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';
|
||||
|
@ -132,29 +132,28 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
protected readonly _onDidRegisterExtensions: Emitter<void> = this._register(new Emitter<void>());
|
||||
private readonly _onDidRegisterExtensions: Emitter<void> = this._register(new Emitter<void>());
|
||||
public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event;
|
||||
|
||||
protected readonly _onDidChangeExtensionsStatus: Emitter<ExtensionIdentifier[]> = this._register(new Emitter<ExtensionIdentifier[]>());
|
||||
private readonly _onDidChangeExtensionsStatus: Emitter<ExtensionIdentifier[]> = this._register(new Emitter<ExtensionIdentifier[]>());
|
||||
public readonly onDidChangeExtensionsStatus: Event<ExtensionIdentifier[]> = this._onDidChangeExtensionsStatus.event;
|
||||
|
||||
protected readonly _onDidChangeExtensions: Emitter<void> = this._register(new Emitter<void>({ leakWarningThreshold: 400 }));
|
||||
private readonly _onDidChangeExtensions: Emitter<void> = this._register(new Emitter<void>({ leakWarningThreshold: 400 }));
|
||||
public readonly onDidChangeExtensions: Event<void> = this._onDidChangeExtensions.event;
|
||||
|
||||
protected readonly _onWillActivateByEvent = this._register(new Emitter<IWillActivateEvent>());
|
||||
private readonly _onWillActivateByEvent = this._register(new Emitter<IWillActivateEvent>());
|
||||
public readonly onWillActivateByEvent: Event<IWillActivateEvent> = this._onWillActivateByEvent.event;
|
||||
|
||||
protected readonly _onDidChangeResponsiveChange = this._register(new Emitter<IResponsiveStateChangeEvent>());
|
||||
private readonly _onDidChangeResponsiveChange = this._register(new Emitter<IResponsiveStateChangeEvent>());
|
||||
public readonly onDidChangeResponsiveChange: Event<IResponsiveStateChangeEvent> = this._onDidChangeResponsiveChange.event;
|
||||
|
||||
protected readonly _runningLocationClassifier: ExtensionRunningLocationClassifier;
|
||||
protected readonly _registry: ExtensionDescriptionRegistry;
|
||||
private readonly _registryLock: Lock;
|
||||
|
||||
private readonly _installedExtensionsReady: Barrier;
|
||||
protected readonly _isDev: boolean;
|
||||
private readonly _isDev: boolean;
|
||||
private readonly _extensionsMessages: Map<string, IMessage[]>;
|
||||
protected readonly _allRequestedActivateEvents = new Set<string>();
|
||||
private readonly _allRequestedActivateEvents = new Set<string>();
|
||||
private readonly _proposedApiController: ProposedApiController;
|
||||
private readonly _isExtensionDevHost: boolean;
|
||||
protected readonly _isExtensionDevTestFromCli: boolean;
|
||||
|
@ -162,10 +161,12 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
|
||||
private _inHandleDeltaExtensions: boolean;
|
||||
|
||||
protected _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
private _runningLocation: Map<string, ExtensionRunningLocation | null>;
|
||||
private _lastExtensionHostId: number = 0;
|
||||
private _maxLocalProcessAffinity: number = 0;
|
||||
|
||||
// --- Members used per extension host process
|
||||
protected _extensionHostManagers: IExtensionHostManager[];
|
||||
private _extensionHostManagers: IExtensionHostManager[];
|
||||
protected _extensionHostActiveExtensions: Map<string, ExtensionIdentifier>;
|
||||
private _extensionHostActivationTimes: Map<string, ActivationTimes>;
|
||||
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
|
||||
|
@ -187,11 +188,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
) {
|
||||
super();
|
||||
|
||||
this._runningLocationClassifier = new ExtensionRunningLocationClassifier(
|
||||
(extension) => this._getExtensionKind(extension),
|
||||
(extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference) => this._pickRunningLocation(extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference)
|
||||
);
|
||||
|
||||
// help the file service to activate providers by activating extensions by file system event
|
||||
this._register(this._fileService.onWillActivateFileSystemProvider(e => {
|
||||
if (e.scheme !== Schemas.vscodeRemote) {
|
||||
|
@ -264,17 +260,247 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription);
|
||||
}
|
||||
|
||||
protected abstract _pickRunningLocation(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation;
|
||||
protected abstract _pickExtensionHostKind(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionHostKind | null;
|
||||
|
||||
protected _getExtensionHostManager(kind: ExtensionHostKind): IExtensionHostManager | null {
|
||||
protected _getExtensionHostManagers(kind: ExtensionHostKind): IExtensionHostManager[] {
|
||||
return this._extensionHostManagers.filter(extHostManager => extHostManager.kind === kind);
|
||||
}
|
||||
|
||||
protected _getExtensionHostManagerByRunningLocation(runningLocation: ExtensionRunningLocation): IExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
if (extensionHostManager.representsRunningLocation(runningLocation)) {
|
||||
return extensionHostManager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//#region running location
|
||||
|
||||
private _computeAffinity(inputExtensions: IExtensionDescription[], extensionHostKind: ExtensionHostKind, isInitialAllocation: boolean): { affinities: Map<string, number>; maxAffinity: number } {
|
||||
// Only analyze extensions that can execute
|
||||
const extensions = new Map<string, IExtensionDescription>();
|
||||
for (const extension of inputExtensions) {
|
||||
if (extension.main || extension.browser) {
|
||||
extensions.set(ExtensionIdentifier.toKey(extension.identifier), extension);
|
||||
}
|
||||
}
|
||||
// Also add existing extensions of the same kind that can execute
|
||||
for (const extension of this._registry.getAllExtensionDescriptions()) {
|
||||
if (extension.main || extension.browser) {
|
||||
const runningLocation = this._runningLocation.get(ExtensionIdentifier.toKey(extension.identifier));
|
||||
if (runningLocation && runningLocation.kind === extensionHostKind) {
|
||||
extensions.set(ExtensionIdentifier.toKey(extension.identifier), extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initially, each extension belongs to its own group
|
||||
const groups = new Map<string, number>();
|
||||
let groupNumber = 0;
|
||||
for (const [_, extension] of extensions) {
|
||||
groups.set(ExtensionIdentifier.toKey(extension.identifier), ++groupNumber);
|
||||
}
|
||||
|
||||
const changeGroup = (from: number, to: number) => {
|
||||
for (const [key, group] of groups) {
|
||||
if (group === from) {
|
||||
groups.set(key, to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We will group things together when there are dependencies
|
||||
for (const [_, extension] of extensions) {
|
||||
if (!extension.extensionDependencies) {
|
||||
continue;
|
||||
}
|
||||
const myGroup = groups.get(ExtensionIdentifier.toKey(extension.identifier))!;
|
||||
for (const depId of extension.extensionDependencies) {
|
||||
const depGroup = groups.get(ExtensionIdentifier.toKey(depId));
|
||||
if (!depGroup) {
|
||||
// probably can't execute, so it has no impact
|
||||
continue;
|
||||
}
|
||||
|
||||
if (depGroup === myGroup) {
|
||||
// already in the same group
|
||||
continue;
|
||||
}
|
||||
|
||||
changeGroup(depGroup, myGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize with existing affinities
|
||||
const resultingAffinities = new Map<number, number>();
|
||||
let lastAffinity = 0;
|
||||
for (const [_, extension] of extensions) {
|
||||
const runningLocation = this._runningLocation.get(ExtensionIdentifier.toKey(extension.identifier));
|
||||
if (runningLocation) {
|
||||
const group = groups.get(ExtensionIdentifier.toKey(extension.identifier))!;
|
||||
resultingAffinities.set(group, runningLocation.affinity);
|
||||
lastAffinity = Math.max(lastAffinity, runningLocation.affinity);
|
||||
}
|
||||
}
|
||||
|
||||
// Go through each configured affinity and try to accomodate it
|
||||
const configuredAffinities = this._configurationService.getValue<{ [extensionId: string]: number } | undefined>('extensions.experimental.affinity') || {};
|
||||
const configuredExtensionIds = Object.keys(configuredAffinities);
|
||||
const configuredAffinityToResultingAffinity = new Map<number, number>();
|
||||
for (const extensionId of configuredExtensionIds) {
|
||||
const configuredAffinity = configuredAffinities[extensionId];
|
||||
if (typeof configuredAffinity !== 'number' || configuredAffinity <= 0 || Math.floor(configuredAffinity) !== configuredAffinity) {
|
||||
this._logService.info(`Ignoring configured affinity for '${extensionId}' because the value is not a positive integer.`);
|
||||
continue;
|
||||
}
|
||||
const group = groups.get(ExtensionIdentifier.toKey(extensionId));
|
||||
if (!group) {
|
||||
this._logService.info(`Ignoring configured affinity for '${extensionId}' because the extension is unknown or cannot execute.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const affinity1 = resultingAffinities.get(group);
|
||||
if (affinity1) {
|
||||
// Affinity for this group is already established
|
||||
configuredAffinityToResultingAffinity.set(configuredAffinity, affinity1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const affinity2 = configuredAffinityToResultingAffinity.get(configuredAffinity);
|
||||
if (affinity2) {
|
||||
// Affinity for this configuration is already established
|
||||
resultingAffinities.set(group, affinity2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isInitialAllocation) {
|
||||
this._logService.info(`Ignoring configured affinity for '${extensionId}' because extension host(s) are already running. Reload window.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const affinity3 = ++lastAffinity;
|
||||
configuredAffinityToResultingAffinity.set(configuredAffinity, affinity3);
|
||||
resultingAffinities.set(group, affinity3);
|
||||
}
|
||||
|
||||
const result = new Map<string, number>();
|
||||
for (const extension of inputExtensions) {
|
||||
const group = groups.get(ExtensionIdentifier.toKey(extension.identifier)) || 0;
|
||||
const affinity = resultingAffinities.get(group) || 0;
|
||||
result.set(ExtensionIdentifier.toKey(extension.identifier), affinity);
|
||||
}
|
||||
|
||||
if (lastAffinity > 0 && isInitialAllocation) {
|
||||
for (let affinity = 1; affinity <= lastAffinity; affinity++) {
|
||||
const extensionIds: ExtensionIdentifier[] = [];
|
||||
for (const extension of inputExtensions) {
|
||||
if (result.get(ExtensionIdentifier.toKey(extension.identifier)) === affinity) {
|
||||
extensionIds.push(extension.identifier);
|
||||
}
|
||||
}
|
||||
this._logService.info(`Placing extension(s) ${extensionIds.map(e => e.value).join(', ')} on a separate extension host.`);
|
||||
}
|
||||
}
|
||||
|
||||
return { affinities: result, maxAffinity: lastAffinity };
|
||||
}
|
||||
|
||||
private _computeRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], isInitialAllocation: boolean): { runningLocation: Map<string, ExtensionRunningLocation | null>; maxLocalProcessAffinity: number } {
|
||||
const extensionHostKinds = ExtensionHostKindClassifier.determineExtensionHostKinds(
|
||||
localExtensions,
|
||||
remoteExtensions,
|
||||
(extension) => this._getExtensionKind(extension),
|
||||
(extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference) => this._pickExtensionHostKind(extensionId, extensionKinds, isInstalledLocally, isInstalledRemotely, preference)
|
||||
);
|
||||
|
||||
const extensions = new Map<string, IExtensionDescription>();
|
||||
for (const extension of localExtensions) {
|
||||
extensions.set(ExtensionIdentifier.toKey(extension.identifier), extension);
|
||||
}
|
||||
for (const extension of remoteExtensions) {
|
||||
extensions.set(ExtensionIdentifier.toKey(extension.identifier), extension);
|
||||
}
|
||||
|
||||
const result = new Map<string, ExtensionRunningLocation | null>();
|
||||
const localProcessExtensions: IExtensionDescription[] = [];
|
||||
for (const [extensionIdKey, extensionHostKind] of extensionHostKinds) {
|
||||
let runningLocation: ExtensionRunningLocation | null = null;
|
||||
if (extensionHostKind === ExtensionHostKind.LocalProcess) {
|
||||
const extensionDescription = extensions.get(ExtensionIdentifier.toKey(extensionIdKey));
|
||||
if (extensionDescription) {
|
||||
localProcessExtensions.push(extensionDescription);
|
||||
}
|
||||
} else if (extensionHostKind === ExtensionHostKind.LocalWebWorker) {
|
||||
runningLocation = new LocalWebWorkerRunningLocation();
|
||||
} else if (extensionHostKind === ExtensionHostKind.Remote) {
|
||||
runningLocation = new RemoteRunningLocation();
|
||||
}
|
||||
result.set(extensionIdKey, runningLocation);
|
||||
}
|
||||
|
||||
const { affinities, maxAffinity } = this._computeAffinity(localProcessExtensions, ExtensionHostKind.LocalProcess, isInitialAllocation);
|
||||
for (const extension of localProcessExtensions) {
|
||||
const affinity = affinities.get(ExtensionIdentifier.toKey(extension.identifier)) || 0;
|
||||
result.set(ExtensionIdentifier.toKey(extension.identifier), new LocalProcessRunningLocation(affinity));
|
||||
}
|
||||
|
||||
return { runningLocation: result, maxLocalProcessAffinity: maxAffinity };
|
||||
}
|
||||
|
||||
protected _determineRunningLocation(localExtensions: IExtensionDescription[]): Map<string, ExtensionRunningLocation | null> {
|
||||
return this._computeRunningLocation(localExtensions, [], false).runningLocation;
|
||||
}
|
||||
|
||||
protected _initializeRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[]): void {
|
||||
const { runningLocation, maxLocalProcessAffinity } = this._computeRunningLocation(localExtensions, remoteExtensions, true);
|
||||
this._runningLocation = runningLocation;
|
||||
this._maxLocalProcessAffinity = maxLocalProcessAffinity;
|
||||
this._startExtensionHostsIfNecessary(true, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update `this._runningLocation` with running locations for newly enabled/installed extensions.
|
||||
*/
|
||||
private _updateRunningLocationForAddedExtensions(toAdd: IExtensionDescription[]): void {
|
||||
// Determine new running location
|
||||
const localProcessExtensions: IExtensionDescription[] = [];
|
||||
for (const extension of toAdd) {
|
||||
const extensionKind = this._getExtensionKind(extension);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const extensionHostKind = this._pickExtensionHostKind(extension.identifier, extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
let runningLocation: ExtensionRunningLocation | null = null;
|
||||
if (extensionHostKind === ExtensionHostKind.LocalProcess) {
|
||||
localProcessExtensions.push(extension);
|
||||
} else if (extensionHostKind === ExtensionHostKind.LocalWebWorker) {
|
||||
runningLocation = new LocalWebWorkerRunningLocation();
|
||||
} else if (extensionHostKind === ExtensionHostKind.Remote) {
|
||||
runningLocation = new RemoteRunningLocation();
|
||||
}
|
||||
this._runningLocation.set(ExtensionIdentifier.toKey(extension.identifier), runningLocation);
|
||||
}
|
||||
|
||||
const { affinities } = this._computeAffinity(localProcessExtensions, ExtensionHostKind.LocalProcess, false);
|
||||
for (const extension of localProcessExtensions) {
|
||||
const affinity = affinities.get(ExtensionIdentifier.toKey(extension.identifier)) || 0;
|
||||
this._runningLocation.set(ExtensionIdentifier.toKey(extension.identifier), new LocalProcessRunningLocation(affinity));
|
||||
}
|
||||
}
|
||||
|
||||
protected _filterByRunningLocation(extensions: IExtensionDescription[], desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return filterByRunningLocation(extensions, this._runningLocation, desiredRunningLocation);
|
||||
}
|
||||
|
||||
protected _filterByExtensionHostKind(extensions: IExtensionDescription[], desiredExtensionHostKind: ExtensionHostKind): IExtensionDescription[] {
|
||||
return filterByExtensionHostKind(extensions, this._runningLocation, desiredExtensionHostKind);
|
||||
}
|
||||
|
||||
protected _filterByExtensionHostManager(extensions: IExtensionDescription[], extensionHostManager: IExtensionHostManager): IExtensionDescription[] {
|
||||
return filterByExtensionHostManager(extensions, this._runningLocation, extensionHostManager);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region deltaExtensions
|
||||
|
||||
private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise<void> {
|
||||
|
@ -374,47 +600,32 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
}
|
||||
|
||||
private async _updateExtensionsOnExtHosts(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
const groupedToRemove: ExtensionIdentifier[][] = [];
|
||||
const groupRemove = (extensionHostKind: ExtensionHostKind, extensionRunningLocation: ExtensionRunningLocation) => {
|
||||
groupedToRemove[extensionHostKind] = filterByRunningLocation(toRemove, extId => extId, this._runningLocation, extensionRunningLocation);
|
||||
};
|
||||
groupRemove(ExtensionHostKind.LocalProcess, ExtensionRunningLocation.LocalProcess);
|
||||
groupRemove(ExtensionHostKind.LocalWebWorker, ExtensionRunningLocation.LocalWebWorker);
|
||||
groupRemove(ExtensionHostKind.Remote, ExtensionRunningLocation.Remote);
|
||||
|
||||
// Remove old running location
|
||||
const removedRunningLocation = new Map<string, ExtensionRunningLocation | null>();
|
||||
for (const extensionId of toRemove) {
|
||||
this._runningLocation.delete(ExtensionIdentifier.toKey(extensionId));
|
||||
const extensionKey = ExtensionIdentifier.toKey(extensionId);
|
||||
removedRunningLocation.set(extensionKey, this._runningLocation.get(extensionKey) || null);
|
||||
this._runningLocation.delete(extensionKey);
|
||||
}
|
||||
|
||||
const groupedToAdd: IExtensionDescription[][] = [];
|
||||
const groupAdd = (extensionHostKind: ExtensionHostKind, extensionRunningLocation: ExtensionRunningLocation) => {
|
||||
groupedToAdd[extensionHostKind] = filterByRunningLocation(toAdd, ext => ext.identifier, this._runningLocation, extensionRunningLocation);
|
||||
};
|
||||
for (const extension of toAdd) {
|
||||
const extensionKind = this._getExtensionKind(extension);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._pickRunningLocation(extension.identifier, extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
this._runningLocation.set(ExtensionIdentifier.toKey(extension.identifier), runningLocation);
|
||||
}
|
||||
groupAdd(ExtensionHostKind.LocalProcess, ExtensionRunningLocation.LocalProcess);
|
||||
groupAdd(ExtensionHostKind.LocalWebWorker, ExtensionRunningLocation.LocalWebWorker);
|
||||
groupAdd(ExtensionHostKind.Remote, ExtensionRunningLocation.Remote);
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (const extensionHostKind of [ExtensionHostKind.LocalProcess, ExtensionHostKind.LocalWebWorker, ExtensionHostKind.Remote]) {
|
||||
const toAdd = groupedToAdd[extensionHostKind];
|
||||
const toRemove = groupedToRemove[extensionHostKind];
|
||||
if (toAdd.length > 0 || toRemove.length > 0) {
|
||||
const extensionHostManager = this._getExtensionHostManager(extensionHostKind);
|
||||
if (extensionHostManager) {
|
||||
promises.push(extensionHostManager.deltaExtensions(toAdd, toRemove));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Determine new running location
|
||||
this._updateRunningLocationForAddedExtensions(toAdd);
|
||||
|
||||
const promises = this._extensionHostManagers.map(
|
||||
extHostManager => this._updateExtensionsOnExtHost(extHostManager, toAdd, toRemove, removedRunningLocation)
|
||||
);
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
private async _updateExtensionsOnExtHost(extensionHostManager: IExtensionHostManager, _toAdd: IExtensionDescription[], _toRemove: ExtensionIdentifier[], removedRunningLocation: Map<string, ExtensionRunningLocation | null>): Promise<void> {
|
||||
const toAdd = filterByExtensionHostManager(_toAdd, this._runningLocation, extensionHostManager);
|
||||
const toRemove = _filterByExtensionHostManager(_toRemove, extId => extId, removedRunningLocation, extensionHostManager);
|
||||
if (toRemove.length > 0 || toAdd.length > 0) {
|
||||
await extensionHostManager.deltaExtensions(toAdd, toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
public canAddExtension(extension: IExtensionDescription): boolean {
|
||||
const existing = this._registry.getExtensionDescription(extension.identifier);
|
||||
if (existing) {
|
||||
|
@ -429,8 +640,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
|
||||
const extensionKind = this._getExtensionKind(extension);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._pickRunningLocation(extension.identifier, extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
if (runningLocation === ExtensionRunningLocation.None) {
|
||||
const extensionHostKind = this._pickExtensionHostKind(extension.identifier, extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
if (extensionHostKind === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -518,7 +729,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
|
||||
protected async _initialize(): Promise<void> {
|
||||
perf.mark('code/willLoadExtensions');
|
||||
this._startExtensionHosts(true, []);
|
||||
this._startExtensionHostsIfNecessary(true, []);
|
||||
|
||||
const lock = await this._registryLock.acquire('_initialize');
|
||||
try {
|
||||
|
@ -558,38 +769,31 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
this._onExtensionHostExit(exitCode);
|
||||
}
|
||||
|
||||
private findTestExtensionHost(testLocation: URI): IExtensionHostManager | undefined | null {
|
||||
let extensionHostKind: ExtensionHostKind | undefined;
|
||||
private findTestExtensionHost(testLocation: URI): IExtensionHostManager | null {
|
||||
let runningLocation: ExtensionRunningLocation | null = null;
|
||||
|
||||
for (const extension of this._registry.getAllExtensionDescriptions()) {
|
||||
if (isEqualOrParent(testLocation, extension.extensionLocation)) {
|
||||
const runningLocation = this._runningLocation.get(ExtensionIdentifier.toKey(extension.identifier));
|
||||
if (runningLocation === ExtensionRunningLocation.LocalProcess) {
|
||||
extensionHostKind = ExtensionHostKind.LocalProcess;
|
||||
} else if (runningLocation === ExtensionRunningLocation.LocalWebWorker) {
|
||||
extensionHostKind = ExtensionHostKind.LocalWebWorker;
|
||||
} else if (runningLocation === ExtensionRunningLocation.Remote) {
|
||||
extensionHostKind = ExtensionHostKind.Remote;
|
||||
}
|
||||
runningLocation = this._runningLocation.get(ExtensionIdentifier.toKey(extension.identifier)) || null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (extensionHostKind === undefined) {
|
||||
if (runningLocation === null) {
|
||||
// not sure if we should support that, but it was possible to have an test outside an extension
|
||||
|
||||
if (testLocation.scheme === Schemas.vscodeRemote) {
|
||||
extensionHostKind = ExtensionHostKind.Remote;
|
||||
runningLocation = new RemoteRunningLocation();
|
||||
} else {
|
||||
// When a debugger attaches to the extension host, it will surface all console.log messages from the extension host,
|
||||
// but not necessarily from the window. So it would be best if any errors get printed to the console of the extension host.
|
||||
// That is why here we use the local process extension host even for non-file URIs
|
||||
extensionHostKind = ExtensionHostKind.LocalProcess;
|
||||
runningLocation = new LocalProcessRunningLocation(0);
|
||||
}
|
||||
}
|
||||
if (extensionHostKind !== undefined) {
|
||||
return this._getExtensionHostManager(extensionHostKind);
|
||||
if (runningLocation !== null) {
|
||||
return this._getExtensionHostManagerByRunningLocation(runningLocation);
|
||||
}
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
private _releaseBarrier(): void {
|
||||
|
@ -619,14 +823,42 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
}
|
||||
}
|
||||
|
||||
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
const extensionHosts = this._createExtensionHosts(isInitialStart);
|
||||
extensionHosts.forEach((extensionHost) => {
|
||||
const processManager: IExtensionHostManager = createExtensionHostManager(this._instantiationService, extensionHost, isInitialStart, initialActivationEvents, this._acquireInternalAPI());
|
||||
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
|
||||
processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
|
||||
this._extensionHostManagers.push(processManager);
|
||||
private _startExtensionHostsIfNecessary(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
const locations: ExtensionRunningLocation[] = [];
|
||||
for (let affinity = 0; affinity <= this._maxLocalProcessAffinity; affinity++) {
|
||||
locations.push(new LocalProcessRunningLocation(affinity));
|
||||
}
|
||||
locations.push(new LocalWebWorkerRunningLocation());
|
||||
locations.push(new RemoteRunningLocation());
|
||||
for (const location of locations) {
|
||||
if (this._getExtensionHostManagerByRunningLocation(location)) {
|
||||
// already running
|
||||
continue;
|
||||
}
|
||||
const extHostManager = this._createExtensionHostManager(location, isInitialStart, initialActivationEvents);
|
||||
if (extHostManager) {
|
||||
this._extensionHostManagers.push(extHostManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _createExtensionHostManager(runningLocation: ExtensionRunningLocation, isInitialStart: boolean, initialActivationEvents: string[]): IExtensionHostManager | null {
|
||||
const extensionHost = this._createExtensionHost(runningLocation, isInitialStart);
|
||||
if (!extensionHost) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const extensionHostId = String(++this._lastExtensionHostId);
|
||||
const processManager: IExtensionHostManager = createExtensionHostManager(this._instantiationService, extensionHostId, extensionHost, isInitialStart, initialActivationEvents, this._acquireInternalAPI());
|
||||
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
|
||||
processManager.onDidChangeResponsiveState((responsiveState) => {
|
||||
this._onDidChangeResponsiveChange.fire({
|
||||
extensionHostId: extensionHostId,
|
||||
extensionHostKind: processManager.kind,
|
||||
isResponsive: responsiveState === ResponsiveState.Responsive
|
||||
});
|
||||
});
|
||||
return processManager;
|
||||
}
|
||||
|
||||
private _onExtensionHostCrashOrExit(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
|
||||
|
@ -660,12 +892,10 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
|
||||
const lock = await this._registryLock.acquire('startExtensionHosts');
|
||||
try {
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
this._startExtensionHostsIfNecessary(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
await localProcessExtensionHost.ready();
|
||||
}
|
||||
const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess);
|
||||
await Promise.all(localProcessExtensionHosts.map(extHost => extHost.ready()));
|
||||
} finally {
|
||||
lock.dispose();
|
||||
}
|
||||
|
@ -771,15 +1001,28 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
messages: this._extensionsMessages.get(extensionKey) || [],
|
||||
activationTimes: this._extensionHostActivationTimes.get(extensionKey),
|
||||
runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [],
|
||||
runningLocation: this._runningLocation.get(extensionKey) || ExtensionRunningLocation.None,
|
||||
runningLocation: this._runningLocation.get(extensionKey) || null,
|
||||
};
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public getInspectPort(_tryEnableInspector: boolean): Promise<number> {
|
||||
return Promise.resolve(0);
|
||||
public async getInspectPort(extensionHostId: string, tryEnableInspector: boolean): Promise<number> {
|
||||
for (const extHostManager of this._extensionHostManagers) {
|
||||
if (extHostManager.extensionHostId === extensionHostId) {
|
||||
return extHostManager.getInspectPort(tryEnableInspector);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async getInspectPorts(extensionHostKind: ExtensionHostKind, tryEnableInspector: boolean): Promise<number[]> {
|
||||
const result = await Promise.all(
|
||||
this._getExtensionHostManagers(extensionHostKind).map(extHost => extHost.getInspectPort(tryEnableInspector))
|
||||
);
|
||||
// remove 0s:
|
||||
return result.filter(element => Boolean(element));
|
||||
}
|
||||
|
||||
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||
|
@ -1040,7 +1283,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
|||
|
||||
//#endregion
|
||||
|
||||
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
|
||||
protected abstract _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null;
|
||||
protected abstract _scanAndHandleExtensions(): Promise<void>;
|
||||
protected abstract _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null>;
|
||||
public abstract _onExtensionHostExit(code: number): void;
|
||||
|
@ -1094,25 +1337,28 @@ class ExtensionInfo {
|
|||
}
|
||||
}
|
||||
|
||||
class ExtensionRunningLocationClassifier {
|
||||
constructor(
|
||||
private readonly getExtensionKind: (extensionDescription: IExtensionDescription) => ExtensionKind[],
|
||||
private readonly pickRunningLocation: (extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference) => ExtensionRunningLocation,
|
||||
) {
|
||||
}
|
||||
class ExtensionHostKindClassifier {
|
||||
|
||||
private _toExtensionWithKind(extensions: IExtensionDescription[]): Map<string, ExtensionWithKind> {
|
||||
private static _toExtensionWithKind(
|
||||
extensions: IExtensionDescription[],
|
||||
getExtensionKind: (extensionDescription: IExtensionDescription) => ExtensionKind[]
|
||||
): Map<string, ExtensionWithKind> {
|
||||
const result = new Map<string, ExtensionWithKind>();
|
||||
extensions.forEach((desc) => {
|
||||
const ext = new ExtensionWithKind(desc, this.getExtensionKind(desc));
|
||||
const ext = new ExtensionWithKind(desc, getExtensionKind(desc));
|
||||
result.set(ext.key, ext);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public determineRunningLocation(_localExtensions: IExtensionDescription[], _remoteExtensions: IExtensionDescription[]): Map<string, ExtensionRunningLocation> {
|
||||
const localExtensions = this._toExtensionWithKind(_localExtensions);
|
||||
const remoteExtensions = this._toExtensionWithKind(_remoteExtensions);
|
||||
public static determineExtensionHostKinds(
|
||||
_localExtensions: IExtensionDescription[],
|
||||
_remoteExtensions: IExtensionDescription[],
|
||||
getExtensionKind: (extensionDescription: IExtensionDescription) => ExtensionKind[],
|
||||
pickExtensionHostKind: (extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference) => ExtensionHostKind | null
|
||||
): Map<string, ExtensionHostKind | null> {
|
||||
const localExtensions = this._toExtensionWithKind(_localExtensions, getExtensionKind);
|
||||
const remoteExtensions = this._toExtensionWithKind(_remoteExtensions, getExtensionKind);
|
||||
|
||||
const allExtensions = new Map<string, ExtensionInfo>();
|
||||
const collectExtension = (ext: ExtensionWithKind) => {
|
||||
|
@ -1127,7 +1373,7 @@ class ExtensionRunningLocationClassifier {
|
|||
localExtensions.forEach((ext) => collectExtension(ext));
|
||||
remoteExtensions.forEach((ext) => collectExtension(ext));
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
const extensionHostKinds = new Map<string, ExtensionHostKind | null>();
|
||||
allExtensions.forEach((ext) => {
|
||||
const isInstalledLocally = Boolean(ext.local);
|
||||
const isInstalledRemotely = Boolean(ext.remote);
|
||||
|
@ -1142,10 +1388,10 @@ class ExtensionRunningLocationClassifier {
|
|||
preference = ExtensionRunningPreference.Remote;
|
||||
}
|
||||
|
||||
runningLocation.set(ext.key, this.pickRunningLocation(ext.identifier, ext.kind, isInstalledLocally, isInstalledRemotely, preference));
|
||||
extensionHostKinds.set(ext.key, pickExtensionHostKind(ext.identifier, ext.kind, isInstalledLocally, isInstalledRemotely, preference));
|
||||
});
|
||||
|
||||
return runningLocation;
|
||||
return extensionHostKinds;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1244,6 +1490,29 @@ class ProposedApiController {
|
|||
}
|
||||
}
|
||||
|
||||
function filterByRunningLocation<T>(extensions: T[], extId: (item: T) => ExtensionIdentifier, runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): T[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(extId(ext))) === desiredRunningLocation);
|
||||
export function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation | null>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return _filterByRunningLocation(extensions, ext => ext.identifier, runningLocation, desiredRunningLocation);
|
||||
}
|
||||
|
||||
function _filterByRunningLocation<T>(extensions: T[], extId: (item: T) => ExtensionIdentifier, runningLocation: Map<string, ExtensionRunningLocation | null>, desiredRunningLocation: ExtensionRunningLocation): T[] {
|
||||
return _filterExtensions(extensions, extId, runningLocation, extRunningLocation => desiredRunningLocation.equals(extRunningLocation));
|
||||
}
|
||||
|
||||
function filterByExtensionHostKind(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation | null>, desiredExtensionHostKind: ExtensionHostKind): IExtensionDescription[] {
|
||||
return _filterExtensions(extensions, ext => ext.identifier, runningLocation, extRunningLocation => extRunningLocation.kind === desiredExtensionHostKind);
|
||||
}
|
||||
|
||||
function filterByExtensionHostManager(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation | null>, extensionHostManager: IExtensionHostManager): IExtensionDescription[] {
|
||||
return _filterByExtensionHostManager(extensions, ext => ext.identifier, runningLocation, extensionHostManager);
|
||||
}
|
||||
|
||||
function _filterByExtensionHostManager<T>(extensions: T[], extId: (item: T) => ExtensionIdentifier, runningLocation: Map<string, ExtensionRunningLocation | null>, extensionHostManager: IExtensionHostManager): T[] {
|
||||
return _filterExtensions(extensions, extId, runningLocation, extRunningLocation => extensionHostManager.representsRunningLocation(extRunningLocation));
|
||||
}
|
||||
|
||||
function _filterExtensions<T>(extensions: T[], extId: (item: T) => ExtensionIdentifier, runningLocation: Map<string, ExtensionRunningLocation | null>, predicate: (extRunningLocation: ExtensionRunningLocation) => boolean): T[] {
|
||||
return extensions.filter((ext) => {
|
||||
const extRunningLocation = runningLocation.get(ExtensionIdentifier.toKey(extId(ext)));
|
||||
return extRunningLocation && predicate(extRunningLocation);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,49 +12,54 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
|
|||
import { ExtHostCustomersRegistry, IInternalExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { Proxied, ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as nls from 'vs/nls';
|
||||
import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IExtensionHost, ExtensionHostKind, ActivationKind, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostKind, ActivationKind, extensionHostKindToString, ExtensionActivationReason, IInternalExtensionService, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IExtensionHostProxy } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
||||
import { IExtensionHostProxy, IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
const LOG_USE_COLORS = true;
|
||||
|
||||
export interface IExtensionHostManager {
|
||||
readonly extensionHostId: string;
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly onDidExit: Event<[number, string | null]>;
|
||||
readonly onDidChangeResponsiveState: Event<ResponsiveState>;
|
||||
dispose(): void;
|
||||
ready(): Promise<void>;
|
||||
representsRunningLocation(runningLocation: ExtensionRunningLocation): boolean;
|
||||
deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
|
||||
activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
|
||||
activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
|
||||
activationEventIsDone(activationEvent: string): boolean;
|
||||
getInspectPort(tryEnableInspector: boolean): Promise<number>;
|
||||
resolveAuthority(remoteAuthority: string): Promise<ResolverResult>;
|
||||
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI>;
|
||||
resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||
/**
|
||||
* Returns `null` if no resolver for `remoteAuthority` is found.
|
||||
*/
|
||||
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI | null>;
|
||||
start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
extensionTestsExecute(): Promise<number>;
|
||||
extensionTestsSendExit(exitCode: number): Promise<void>;
|
||||
setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
|
||||
}
|
||||
|
||||
export function createExtensionHostManager(instantiationService: IInstantiationService, extensionHost: IExtensionHost, isInitialStart: boolean, initialActivationEvents: string[], internalExtensionService: IInternalExtensionService): IExtensionHostManager {
|
||||
export function createExtensionHostManager(instantiationService: IInstantiationService, extensionHostId: string, extensionHost: IExtensionHost, isInitialStart: boolean, initialActivationEvents: string[], internalExtensionService: IInternalExtensionService): IExtensionHostManager {
|
||||
if (extensionHost.lazyStart && isInitialStart && initialActivationEvents.length === 0) {
|
||||
return instantiationService.createInstance(LazyStartExtensionHostManager, extensionHost, internalExtensionService);
|
||||
return instantiationService.createInstance(LazyStartExtensionHostManager, extensionHostId, extensionHost, internalExtensionService);
|
||||
}
|
||||
return instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents, internalExtensionService);
|
||||
return instantiationService.createInstance(ExtensionHostManager, extensionHostId, extensionHost, initialActivationEvents, internalExtensionService);
|
||||
}
|
||||
|
||||
export type ExtensionHostStartupClassification = {
|
||||
|
@ -77,7 +82,6 @@ export type ExtensionHostStartupEvent = {
|
|||
|
||||
class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
||||
|
||||
public readonly kind: ExtensionHostKind;
|
||||
public readonly onDidExit: Event<[number, string | null]>;
|
||||
|
||||
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
|
||||
|
@ -92,10 +96,14 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
private readonly _customers: IDisposable[];
|
||||
private readonly _extensionHost: IExtensionHost;
|
||||
private _proxy: Promise<IExtensionHostProxy | null> | null;
|
||||
private _resolveAuthorityAttempt: number;
|
||||
private _hasStarted = false;
|
||||
|
||||
public get kind(): ExtensionHostKind {
|
||||
return this._extensionHost.runningLocation.kind;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly extensionHostId: string,
|
||||
extensionHost: IExtensionHost,
|
||||
initialActivationEvents: string[],
|
||||
private readonly _internalExtensionService: IInternalExtensionService,
|
||||
|
@ -111,7 +119,6 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
this._customers = [];
|
||||
|
||||
this._extensionHost = extensionHost;
|
||||
this.kind = this._extensionHost.kind;
|
||||
this.onDidExit = this._extensionHost.onExit;
|
||||
|
||||
const startingTelemetryEvent: ExtensionHostStartupEvent = {
|
||||
|
@ -166,7 +173,6 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
measure: () => this.measure()
|
||||
}));
|
||||
});
|
||||
this._resolveAuthorityAttempt = 0;
|
||||
}
|
||||
|
||||
public override dispose(): void {
|
||||
|
@ -190,7 +196,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
}
|
||||
|
||||
private async measure(): Promise<ExtHostLatencyResult | null> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return null;
|
||||
}
|
||||
|
@ -205,12 +211,8 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
};
|
||||
}
|
||||
|
||||
private async _getProxy(): Promise<IExtensionHostProxy | null> {
|
||||
return this._proxy;
|
||||
}
|
||||
|
||||
public async ready(): Promise<void> {
|
||||
await this._getProxy();
|
||||
await this._proxy;
|
||||
}
|
||||
|
||||
private async _measureLatency(proxy: IExtensionHostProxy): Promise<number> {
|
||||
|
@ -310,7 +312,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
}
|
||||
|
||||
public async activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return false;
|
||||
}
|
||||
|
@ -359,57 +361,52 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public async resolveAuthority(remoteAuthority: string): Promise<ResolverResult> {
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
// This authority does not need to be resolved, simply parse the port number
|
||||
const lastColon = remoteAuthority.lastIndexOf(':');
|
||||
return Promise.resolve({
|
||||
authority: {
|
||||
authority: remoteAuthority,
|
||||
host: remoteAuthority.substring(0, lastColon),
|
||||
port: parseInt(remoteAuthority.substring(lastColon + 1), 10),
|
||||
connectionToken: undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
const proxy = await this._getProxy();
|
||||
public async resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
throw new Error(`Cannot resolve authority`);
|
||||
return {
|
||||
type: 'error',
|
||||
error: {
|
||||
message: `Cannot resolve authority`,
|
||||
code: RemoteAuthorityResolverErrorCode.Unknown,
|
||||
detail: undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
this._resolveAuthorityAttempt++;
|
||||
const result = await proxy.resolveAuthority(remoteAuthority, this._resolveAuthorityAttempt);
|
||||
if (result.type === 'ok') {
|
||||
return result.value;
|
||||
} else {
|
||||
throw new RemoteAuthorityResolverError(result.error.message, result.error.code, result.error.detail);
|
||||
|
||||
try {
|
||||
return proxy.resolveAuthority(remoteAuthority, resolveAttempt);
|
||||
} catch (err) {
|
||||
return {
|
||||
type: 'error',
|
||||
error: {
|
||||
message: err.message,
|
||||
code: RemoteAuthorityResolverErrorCode.Unknown,
|
||||
detail: err
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
// This authority does not use a resolver
|
||||
return uri;
|
||||
}
|
||||
const proxy = await this._getProxy();
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI | null> {
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
throw new Error(`Cannot resolve canonical URI`);
|
||||
}
|
||||
const result = await proxy.getCanonicalURI(remoteAuthority, uri);
|
||||
return URI.revive(result);
|
||||
return proxy.getCanonicalURI(remoteAuthority, uri);
|
||||
}
|
||||
|
||||
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
this._extensionHost.extensions.keepOnly(enabledExtensionIds);
|
||||
return proxy.startExtensionHost(enabledExtensionIds);
|
||||
}
|
||||
|
||||
public async extensionTestsExecute(): Promise<number> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
throw new Error('Could not obtain Extension Host Proxy');
|
||||
}
|
||||
|
@ -417,7 +414,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
}
|
||||
|
||||
public async extensionTestsSendExit(exitCode: number): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
|
@ -430,16 +427,21 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
}
|
||||
}
|
||||
|
||||
public representsRunningLocation(runningLocation: ExtensionRunningLocation): boolean {
|
||||
return this._extensionHost.runningLocation.equals(runningLocation);
|
||||
}
|
||||
|
||||
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
this._extensionHost.extensions.deltaExtensions(toAdd, toRemove);
|
||||
return proxy.deltaExtensions(toAdd, toRemove);
|
||||
}
|
||||
|
||||
public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
const proxy = await this._proxy;
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
|
@ -452,7 +454,7 @@ class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
|||
* Waits until `start()` and only if it has extensions proceeds to really start.
|
||||
*/
|
||||
class LazyStartExtensionHostManager extends Disposable implements IExtensionHostManager {
|
||||
public readonly kind: ExtensionHostKind;
|
||||
|
||||
public readonly onDidExit: Event<[number, string | null]>;
|
||||
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
|
||||
public readonly onDidChangeResponsiveState: Event<ResponsiveState> = this._onDidChangeResponsiveState.event;
|
||||
|
@ -461,7 +463,12 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost
|
|||
private _startCalled: Barrier;
|
||||
private _actual: ExtensionHostManager | null;
|
||||
|
||||
public get kind(): ExtensionHostKind {
|
||||
return this._extensionHost.runningLocation.kind;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly extensionHostId: string,
|
||||
extensionHost: IExtensionHost,
|
||||
private readonly _internalExtensionService: IInternalExtensionService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
|
@ -469,7 +476,6 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost
|
|||
) {
|
||||
super();
|
||||
this._extensionHost = extensionHost;
|
||||
this.kind = extensionHost.kind;
|
||||
this.onDidExit = extensionHost.onExit;
|
||||
this._startCalled = new Barrier();
|
||||
this._actual = null;
|
||||
|
@ -477,7 +483,7 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost
|
|||
|
||||
private _createActual(reason: string): ExtensionHostManager {
|
||||
this._logService.info(`Creating lazy extension host: ${reason}`);
|
||||
this._actual = this._register(this._instantiationService.createInstance(ExtensionHostManager, this._extensionHost, [], this._internalExtensionService));
|
||||
this._actual = this._register(this._instantiationService.createInstance(ExtensionHostManager, this.extensionHostId, this._extensionHost, [], this._internalExtensionService));
|
||||
this._register(this._actual.onDidChangeResponsiveState((e) => this._onDidChangeResponsiveState.fire(e)));
|
||||
return this._actual;
|
||||
}
|
||||
|
@ -498,6 +504,9 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost
|
|||
await this._actual.ready();
|
||||
}
|
||||
}
|
||||
public representsRunningLocation(runningLocation: ExtensionRunningLocation): boolean {
|
||||
return this._extensionHost.runningLocation.equals(runningLocation);
|
||||
}
|
||||
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
const extensionHostAlreadyStarted = Boolean(this._actual);
|
||||
|
@ -543,14 +552,21 @@ class LazyStartExtensionHostManager extends Disposable implements IExtensionHost
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
public async resolveAuthority(remoteAuthority: string): Promise<ResolverResult> {
|
||||
public async resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.resolveAuthority(remoteAuthority);
|
||||
return this._actual.resolveAuthority(remoteAuthority, resolveAttempt);
|
||||
}
|
||||
throw new Error(`Cannot resolve authority`);
|
||||
return {
|
||||
type: 'error',
|
||||
error: {
|
||||
message: `Cannot resolve authority`,
|
||||
code: RemoteAuthorityResolverErrorCode.Unknown,
|
||||
detail: undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI | null> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.getCanonicalURI(remoteAuthority, uri);
|
||||
|
|
|
@ -27,7 +27,10 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut
|
|||
|
||||
export interface IExtensionHostProxy {
|
||||
resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI>;
|
||||
/**
|
||||
* Returns `null` if no resolver for `remoteAuthority` is found.
|
||||
*/
|
||||
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI | null>;
|
||||
startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
extensionTestsExecute(): Promise<number>;
|
||||
extensionTestsExit(code: number): Promise<void>;
|
||||
|
|
|
@ -13,6 +13,7 @@ import { getExtensionId, getGalleryExtensionId } from 'vs/platform/extensionMana
|
|||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ApiProposalName } from 'vs/workbench/services/extensions/common/extensionsApiProposals';
|
||||
import { IV8Profile } from 'vs/platform/profiling/common/profiling';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
|
||||
export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
|
||||
identifier: new ExtensionIdentifier('nullExtensionDescription'),
|
||||
|
@ -36,31 +37,48 @@ export interface IMessage {
|
|||
extensionPointId: string;
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export function extensionRunningLocationToString(location: ExtensionRunningLocation) {
|
||||
switch (location) {
|
||||
case ExtensionRunningLocation.None:
|
||||
return 'None';
|
||||
case ExtensionRunningLocation.LocalProcess:
|
||||
export class LocalProcessRunningLocation {
|
||||
public readonly kind = ExtensionHostKind.LocalProcess;
|
||||
constructor(
|
||||
public readonly affinity: number
|
||||
) { }
|
||||
public equals(other: ExtensionRunningLocation) {
|
||||
return (this.kind === other.kind && this.affinity === other.affinity);
|
||||
}
|
||||
public asString(): string {
|
||||
if (this.affinity === 0) {
|
||||
return 'LocalProcess';
|
||||
case ExtensionRunningLocation.LocalWebWorker:
|
||||
return 'LocalWebWorker';
|
||||
case ExtensionRunningLocation.Remote:
|
||||
return 'Remote';
|
||||
}
|
||||
return `LocalProcess${this.affinity}`;
|
||||
}
|
||||
}
|
||||
export class LocalWebWorkerRunningLocation {
|
||||
public readonly kind = ExtensionHostKind.LocalWebWorker;
|
||||
public readonly affinity = 0;
|
||||
public equals(other: ExtensionRunningLocation) {
|
||||
return (this.kind === other.kind);
|
||||
}
|
||||
public asString(): string {
|
||||
return 'LocalWebWorker';
|
||||
}
|
||||
}
|
||||
export class RemoteRunningLocation {
|
||||
public readonly kind = ExtensionHostKind.Remote;
|
||||
public readonly affinity = 0;
|
||||
public equals(other: ExtensionRunningLocation) {
|
||||
return (this.kind === other.kind);
|
||||
}
|
||||
public asString(): string {
|
||||
return 'Remote';
|
||||
}
|
||||
}
|
||||
export type ExtensionRunningLocation = LocalProcessRunningLocation | LocalWebWorkerRunningLocation | RemoteRunningLocation;
|
||||
|
||||
export interface IExtensionsStatus {
|
||||
messages: IMessage[];
|
||||
activationTimes: ActivationTimes | undefined;
|
||||
runtimeErrors: Error[];
|
||||
runningLocation: ExtensionRunningLocation;
|
||||
runningLocation: ExtensionRunningLocation | null;
|
||||
}
|
||||
|
||||
export class MissingExtensionDependency {
|
||||
|
@ -108,12 +126,15 @@ export interface IExtensionHostProfile {
|
|||
}
|
||||
|
||||
export const enum ExtensionHostKind {
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
LocalProcess = 1,
|
||||
LocalWebWorker = 2,
|
||||
Remote = 3
|
||||
}
|
||||
|
||||
export function extensionHostKindToString(kind: ExtensionHostKind): string {
|
||||
export function extensionHostKindToString(kind: ExtensionHostKind | null): string {
|
||||
if (kind === null) {
|
||||
return 'None';
|
||||
}
|
||||
switch (kind) {
|
||||
case ExtensionHostKind.LocalProcess: return 'LocalProcess';
|
||||
case ExtensionHostKind.LocalWebWorker: return 'LocalWebWorker';
|
||||
|
@ -122,9 +143,14 @@ export function extensionHostKindToString(kind: ExtensionHostKind): string {
|
|||
}
|
||||
|
||||
export interface IExtensionHost {
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly runningLocation: ExtensionRunningLocation;
|
||||
readonly remoteAuthority: string | null;
|
||||
readonly lazyStart: boolean;
|
||||
/**
|
||||
* A collection of extensions that will execute or are executing on this extension host.
|
||||
* **NOTE**: this will reflect extensions correctly only after `start()` resolves.
|
||||
*/
|
||||
readonly extensions: ExtensionDescriptionRegistry;
|
||||
readonly onExit: Event<[number, string | null]>;
|
||||
|
||||
start(): Promise<IMessagePassingProtocol> | null;
|
||||
|
@ -186,6 +212,8 @@ export interface IWillActivateEvent {
|
|||
}
|
||||
|
||||
export interface IResponsiveStateChangeEvent {
|
||||
extensionHostId: string;
|
||||
extensionHostKind: ExtensionHostKind;
|
||||
isResponsive: boolean;
|
||||
}
|
||||
|
||||
|
@ -288,10 +316,15 @@ export interface IExtensionService {
|
|||
getExtensionsStatus(): { [id: string]: IExtensionsStatus };
|
||||
|
||||
/**
|
||||
* Return the inspect port or `0`, the latter means inspection
|
||||
* is not possible.
|
||||
* Return the inspect port or `0` for a certain extension host.
|
||||
* `0` means inspection is not possible.
|
||||
*/
|
||||
getInspectPort(tryEnableInspector: boolean): Promise<number>;
|
||||
getInspectPort(extensionHostId: string, tryEnableInspector: boolean): Promise<number>;
|
||||
|
||||
/**
|
||||
* Return the inspect ports (if inspection is possible) for extension hosts of kind `extensionHostKind`.
|
||||
*/
|
||||
getInspectPorts(extensionHostKind: ExtensionHostKind, tryEnableInspector: boolean): Promise<number[]>;
|
||||
|
||||
/**
|
||||
* Stops the extension hosts.
|
||||
|
@ -372,7 +405,8 @@ export class NullExtensionService implements IExtensionService {
|
|||
getExtension() { return Promise.resolve(undefined); }
|
||||
readExtensionPointContributions<T>(_extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> { return Promise.resolve(Object.create(null)); }
|
||||
getExtensionsStatus(): { [id: string]: IExtensionsStatus } { return Object.create(null); }
|
||||
getInspectPort(_tryEnableInspector: boolean): Promise<number> { return Promise.resolve(0); }
|
||||
getInspectPort(_extensionHostId: string, _tryEnableInspector: boolean): Promise<number> { return Promise.resolve(0); }
|
||||
getInspectPorts(_extensionHostKind: ExtensionHostKind, _tryEnableInspector: boolean): Promise<number[]> { return Promise.resolve([]); }
|
||||
stopExtensionHosts(): void { }
|
||||
async restartExtensionHost(): Promise<void> { }
|
||||
async startExtensionHosts(): Promise<void> { }
|
||||
|
|
|
@ -25,9 +25,10 @@ import { ISignService } from 'vs/platform/sign/common/sign';
|
|||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { createMessageOfType, isMessageOfType, MessageType, IExtensionHostInitData, UIKind } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { ExtensionHostKind, ExtensionHostLogFileName, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostLogFileName, IExtensionHost, RemoteRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Extensions, IOutputChannelRegistry } from 'vs/workbench/services/output/common/output';
|
||||
|
||||
|
@ -49,9 +50,9 @@ export interface IRemoteExtensionHostDataProvider {
|
|||
|
||||
export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.Remote;
|
||||
public readonly remoteAuthority: string;
|
||||
public readonly lazyStart = false;
|
||||
public readonly extensions = new ExtensionDescriptionRegistry([]);
|
||||
|
||||
private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>());
|
||||
public readonly onExit: Event<[number, string | null]> = this._onExit.event;
|
||||
|
@ -62,6 +63,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
|||
private readonly _isExtensionDevHost: boolean;
|
||||
|
||||
constructor(
|
||||
public readonly runningLocation: RemoteRunningLocation,
|
||||
private readonly _initDataProvider: IRemoteExtensionHostDataProvider,
|
||||
private readonly _socketFactory: ISocketFactory,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
|
@ -222,6 +224,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
|||
.filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier)
|
||||
);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
this.extensions.deltaExtensions(remoteInitData.extensions, []);
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
|
@ -251,7 +254,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
|||
},
|
||||
resolvedExtensions: resolvedExtensions,
|
||||
hostExtensions: hostExtensions,
|
||||
extensions: remoteInitData.extensions,
|
||||
extensions: this.extensions.getAllExtensionDescriptions(),
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: remoteInitData.extensionHostLogsPath,
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
|
||||
import { ILocalProcessExtensionHostDataProvider, LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
|
||||
|
||||
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { AbstractExtensionService, ExtensionRunningPreference, extensionRunningPreferenceToString } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningPreference, extensionRunningPreferenceToString, filterByRunningLocation } 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';
|
||||
|
@ -16,13 +16,13 @@ import { IWorkbenchExtensionEnablementService, EnablementState, IWebExtensionsSc
|
|||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
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 { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/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, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig, ExtensionRunningLocation, WebWorkerExtHostConfigValue, extensionRunningLocationToString, extensionHostKindToString } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig, ExtensionRunningLocation, WebWorkerExtHostConfigValue, extensionHostKindToString } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionKind } from 'vs/platform/environment/common/environment';
|
||||
|
@ -35,7 +35,7 @@ import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remo
|
|||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IWebWorkerExtensionHostDataProvider, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
|
@ -48,6 +48,8 @@ import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/w
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { isCI } from 'vs/base/common/platform';
|
||||
import { IResolveAuthorityErrorResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
|
@ -56,6 +58,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
|
||||
private readonly _extensionScanner: CachedExtensionScanner;
|
||||
private readonly _crashTracker = new ExtensionHostCrashTracker();
|
||||
private _resolveAuthorityAttempt: number = 0;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
|
@ -151,13 +154,13 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
]));
|
||||
}
|
||||
|
||||
private _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation) {
|
||||
private _createLocalExtensionHostDataProvider(isInitialStart: boolean, desiredRunningLocation: ExtensionRunningLocation): ILocalProcessExtensionHostDataProvider & IWebWorkerExtensionHostDataProvider {
|
||||
return {
|
||||
getInitData: async () => {
|
||||
if (isInitialStart) {
|
||||
// Here we load even extensions that would be disabled by workspace trust
|
||||
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions(), /* ignore workspace trust */true);
|
||||
const runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, []);
|
||||
const runningLocation = this._determineRunningLocation(localExtensions);
|
||||
const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: false,
|
||||
|
@ -166,7 +169,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
} else {
|
||||
// restart case
|
||||
const allExtensions = await this.getExtensions();
|
||||
const localProcessExtensions = filterByRunningLocation(allExtensions, this._runningLocation, desiredRunningLocation);
|
||||
const localProcessExtensions = this._filterByRunningLocation(allExtensions, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: true,
|
||||
extensions: localProcessExtensions
|
||||
|
@ -186,69 +189,70 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
};
|
||||
}
|
||||
|
||||
protected _pickRunningLocation(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation {
|
||||
const result = ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference, Boolean(this._environmentService.remoteAuthority), this._enableLocalWebWorker);
|
||||
this._logService.trace(`pickRunningLocation for ${extensionId.value}, extension kinds: [${extensionKinds.join(', ')}], isInstalledLocally: ${isInstalledLocally}, isInstalledRemotely: ${isInstalledRemotely}, preference: ${extensionRunningPreferenceToString(preference)} => ${extensionRunningLocationToString(result)}`);
|
||||
protected _pickExtensionHostKind(extensionId: ExtensionIdentifier, extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionHostKind | null {
|
||||
const result = ExtensionService.pickExtensionHostKind(extensionKinds, isInstalledLocally, isInstalledRemotely, preference, Boolean(this._environmentService.remoteAuthority), this._enableLocalWebWorker);
|
||||
this._logService.trace(`pickRunningLocation for ${extensionId.value}, extension kinds: [${extensionKinds.join(', ')}], isInstalledLocally: ${isInstalledLocally}, isInstalledRemotely: ${isInstalledRemotely}, preference: ${extensionRunningPreferenceToString(preference)} => ${extensionHostKindToString(result)}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference, hasRemoteExtHost: boolean, hasWebWorkerExtHost: boolean): ExtensionRunningLocation {
|
||||
const result: ExtensionRunningLocation[] = [];
|
||||
public static pickExtensionHostKind(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference, hasRemoteExtHost: boolean, hasWebWorkerExtHost: boolean): ExtensionHostKind | null {
|
||||
const result: ExtensionHostKind[] = [];
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledLocally) {
|
||||
// ui extensions run locally if possible
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
return ExtensionHostKind.LocalProcess;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalProcess);
|
||||
result.push(ExtensionHostKind.LocalProcess);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
return ExtensionHostKind.Remote;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
result.push(ExtensionHostKind.Remote);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'workspace' && !hasRemoteExtHost) {
|
||||
// workspace extensions also run locally if there is no remote
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
return ExtensionHostKind.LocalProcess;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalProcess);
|
||||
result.push(ExtensionHostKind.LocalProcess);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally && hasWebWorkerExtHost) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
return ExtensionHostKind.LocalWebWorker;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalWebWorker);
|
||||
result.push(ExtensionHostKind.LocalWebWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (result.length > 0 ? result[0] : ExtensionRunningLocation.None);
|
||||
return (result.length > 0 ? result[0] : null);
|
||||
}
|
||||
|
||||
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._lazyLocalWebWorker, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
|
||||
result.push(webWorkerExtHost);
|
||||
protected _createExtensionHost(runningLocation: ExtensionRunningLocation, isInitialStart: boolean): IExtensionHost | null {
|
||||
switch (runningLocation.kind) {
|
||||
case ExtensionHostKind.LocalProcess: {
|
||||
return this._instantiationService.createInstance(LocalProcessExtensionHost, runningLocation, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation));
|
||||
}
|
||||
case ExtensionHostKind.LocalWebWorker: {
|
||||
if (this._enableLocalWebWorker) {
|
||||
return this._instantiationService.createInstance(WebWorkerExtensionHost, runningLocation, this._lazyLocalWebWorker, this._createLocalExtensionHostDataProvider(isInitialStart, runningLocation));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case ExtensionHostKind.Remote: {
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
return this._instantiationService.createInstance(RemoteExtensionHost, runningLocation, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
if (remoteAgentConnection) {
|
||||
const remoteExtHost = this._instantiationService.createInstance(RemoteExtensionHost, this._createRemoteExtensionHostDataProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory);
|
||||
result.push(remoteExtHost);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
|
||||
|
@ -340,18 +344,88 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
|
||||
// --- impl
|
||||
|
||||
private async _resolveAuthority(remoteAuthority: string): Promise<ResolverResult> {
|
||||
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
// This authority does not need to be resolved, simply parse the port number
|
||||
const lastColon = remoteAuthority.lastIndexOf(':');
|
||||
return {
|
||||
authority: {
|
||||
authority: remoteAuthority,
|
||||
host: remoteAuthority.substring(0, lastColon),
|
||||
port: parseInt(remoteAuthority.substring(lastColon + 1), 10),
|
||||
connectionToken: undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHosts.length === 0) {
|
||||
// no local process extension hosts
|
||||
throw new Error(`Cannot resolve authority`);
|
||||
}
|
||||
|
||||
this._resolveAuthorityAttempt++;
|
||||
const results = await Promise.all(localProcessExtensionHosts.map(extHost => extHost.resolveAuthority(remoteAuthority, this._resolveAuthorityAttempt)));
|
||||
|
||||
let bestErrorResult: IResolveAuthorityErrorResult | null = null;
|
||||
for (const result of results) {
|
||||
if (result.type === 'ok') {
|
||||
return result.value;
|
||||
}
|
||||
if (!bestErrorResult) {
|
||||
bestErrorResult = result;
|
||||
continue;
|
||||
}
|
||||
const bestErrorIsUnknown = (bestErrorResult.error.code === RemoteAuthorityResolverErrorCode.Unknown);
|
||||
const errorIsUnknown = (result.error.code === RemoteAuthorityResolverErrorCode.Unknown);
|
||||
if (bestErrorIsUnknown && !errorIsUnknown) {
|
||||
bestErrorResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this if there is an error
|
||||
throw new RemoteAuthorityResolverError(bestErrorResult!.error.message, bestErrorResult!.error.code, bestErrorResult!.error.detail);
|
||||
}
|
||||
|
||||
private async _getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
// This authority does not use a resolver
|
||||
return uri;
|
||||
}
|
||||
|
||||
const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHosts.length === 0) {
|
||||
// no local process extension hosts
|
||||
throw new Error(`Cannot resolve canonical URI`);
|
||||
}
|
||||
|
||||
const results = await Promise.all(localProcessExtensionHosts.map(extHost => extHost.getCanonicalURI(remoteAuthority, uri)));
|
||||
|
||||
for (const result of results) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this if there was no resolver extension that can return the cannonical uri
|
||||
throw new Error(`Cannot get canonical URI because no extension is installed to resolve ${getRemoteAuthorityPrefix(remoteAuthority)}`);
|
||||
}
|
||||
|
||||
private async _resolveAuthorityAgain(): Promise<void> {
|
||||
const remoteAuthority = this._environmentService.remoteAuthority;
|
||||
if (!remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
|
||||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`);
|
||||
try {
|
||||
const result = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
|
||||
const result = await this._resolveAuthority(remoteAuthority);
|
||||
this._logService.info(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${result.authority.host}:${result.authority.port}' after ${sw.elapsed()} ms`);
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(result.authority, result.options);
|
||||
} catch (err) {
|
||||
|
@ -364,7 +438,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
this._extensionScanner.startScanningExtensions(this.createLogger());
|
||||
|
||||
const remoteAuthority = this._environmentService.remoteAuthority;
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
|
||||
let remoteEnv: IRemoteAgentEnvironment | null = null;
|
||||
let remoteExtensions: IExtensionDescription[] = [];
|
||||
|
@ -376,12 +449,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
// The current remote authority resolver cannot give the canonical URI for this URI
|
||||
return uri;
|
||||
}
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
if (isCI) {
|
||||
this._logService.info(`Invoking getCanonicalURI for authority ${getRemoteAuthorityPrefix(remoteAuthority)}...`);
|
||||
}
|
||||
try {
|
||||
return localProcessExtensionHost.getCanonicalURI(remoteAuthority, uri);
|
||||
return this._getCanonicalURI(remoteAuthority, uri);
|
||||
} finally {
|
||||
if (isCI) {
|
||||
this._logService.info(`getCanonicalURI returned for authority ${getRemoteAuthorityPrefix(remoteAuthority)}.`);
|
||||
|
@ -407,7 +479,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`);
|
||||
try {
|
||||
resolverResult = await localProcessExtensionHost.resolveAuthority(remoteAuthority);
|
||||
resolverResult = await this._resolveAuthority(remoteAuthority);
|
||||
this._logService.info(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${resolverResult.authority.host}:${resolverResult.authority.port}' after ${sw.elapsed()} ms`);
|
||||
} catch (err) {
|
||||
this._logService.error(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned an error after ${sw.elapsed()} ms`, err);
|
||||
|
@ -471,12 +543,12 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
|
||||
remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions, false);
|
||||
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions(), false);
|
||||
this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions);
|
||||
this._initializeRunningLocation(localExtensions, remoteExtensions);
|
||||
|
||||
// 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 localProcessExtensions = this._filterByExtensionHostKind(localExtensions, ExtensionHostKind.LocalProcess);
|
||||
const localWebWorkerExtensions = this._filterByExtensionHostKind(localExtensions, ExtensionHostKind.LocalWebWorker);
|
||||
remoteExtensions = this._filterByExtensionHostKind(remoteExtensions, ExtensionHostKind.Remote);
|
||||
|
||||
const result = this._registry.deltaExtensions(remoteExtensions.concat(localProcessExtensions).concat(localWebWorkerExtensions), []);
|
||||
if (result.removedDueToLooping.length > 0) {
|
||||
|
@ -498,23 +570,22 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||
|
||||
this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions());
|
||||
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
localProcessExtensionHost.start(localProcessExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
|
||||
const localProcessExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalProcess);
|
||||
const filteredLocalProcessExtensions = localProcessExtensions.filter(extension => this._registry.containsExtension(extension.identifier));
|
||||
for (const extHost of localProcessExtensionHosts) {
|
||||
this._startExtensionHost(extHost, filteredLocalProcessExtensions);
|
||||
}
|
||||
|
||||
const localWebWorkerExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalWebWorker);
|
||||
if (localWebWorkerExtensionHost) {
|
||||
localWebWorkerExtensionHost.start(localWebWorkerExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id)));
|
||||
const localWebWorkerExtensionHosts = this._getExtensionHostManagers(ExtensionHostKind.LocalWebWorker);
|
||||
const filteredLocalWebWorkerExtensions = localWebWorkerExtensions.filter(extension => this._registry.containsExtension(extension.identifier));
|
||||
for (const extHost of localWebWorkerExtensionHosts) {
|
||||
this._startExtensionHost(extHost, filteredLocalWebWorkerExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
public override async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
return localProcessExtensionHost.getInspectPort(tryEnableInspector);
|
||||
}
|
||||
return 0;
|
||||
private _startExtensionHost(extensionHostManager: IExtensionHostManager, _extensions: IExtensionDescription[]): void {
|
||||
const extensions = this._filterByExtensionHostManager(_extensions, extensionHostManager);
|
||||
extensionHostManager.start(extensions.map(extension => extension.identifier));
|
||||
}
|
||||
|
||||
public _onExtensionHostExit(code: number): void {
|
||||
|
@ -630,10 +701,6 @@ function getRemoteAuthorityPrefix(remoteAuthority: string): string {
|
|||
return remoteAuthority.substring(0, plusIndex);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
class RestartExtensionHostAction extends Action2 {
|
||||
|
|
|
@ -34,7 +34,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 { IExtensionHost, ExtensionHostLogFileName, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHost, ExtensionHostLogFileName, LocalProcessRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
@ -44,6 +44,7 @@ import { IExtensionHostProcessOptions, IExtensionHostStarter } from 'vs/platform
|
|||
import { SerializedError } from 'vs/base/common/errors';
|
||||
import { removeDangerousEnvVariables } from 'vs/base/node/processes';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
|
||||
export interface ILocalProcessExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
|
@ -105,9 +106,9 @@ class ExtensionHostProcess {
|
|||
|
||||
export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalProcess;
|
||||
public readonly remoteAuthority = null;
|
||||
public readonly lazyStart = false;
|
||||
public readonly extensions = new ExtensionDescriptionRegistry([]);
|
||||
|
||||
private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>();
|
||||
public readonly onExit: Event<[number, string]> = this._onExit.event;
|
||||
|
@ -135,6 +136,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
|||
private readonly _extensionHostLogFile: URI;
|
||||
|
||||
constructor(
|
||||
public readonly runningLocation: LocalProcessRunningLocation,
|
||||
private readonly _initDataProvider: ILocalProcessExtensionHostDataProvider,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
|
@ -502,6 +504,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
|||
private async _createExtHostInitData(): Promise<IExtensionHostInitData> {
|
||||
const [telemetryInfo, initData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
this.extensions.deltaExtensions(initData.extensions, []);
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
version: this._productService.version,
|
||||
|
@ -532,7 +535,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
|||
},
|
||||
resolvedExtensions: [],
|
||||
hostExtensions: [],
|
||||
extensions: initData.extensions,
|
||||
extensions: this.extensions.getAllExtensionDescriptions(),
|
||||
telemetryInfo,
|
||||
logLevel: this._logService.getLevel(),
|
||||
logsLocation: this._environmentService.extHostLogsPath,
|
||||
|
|
|
@ -6,84 +6,84 @@
|
|||
import * as assert from 'assert';
|
||||
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
|
||||
import { ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
suite('BrowserExtensionService', () => {
|
||||
test('pickRunningLocation', () => {
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, true, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, true, ExtensionRunningPreference.None), null);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, false, ExtensionRunningPreference.None), null);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false, ExtensionRunningPreference.None), ExtensionHostKind.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true, ExtensionRunningPreference.None), ExtensionHostKind.Remote);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue