mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 (#15681)
* Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 * Fixes and cleanup * Distro * Fix hygiene yarn * delete no yarn lock changes file * Fix hygiene * Fix layer check * Fix CI * Skip lib checks * Remove tests deleted in vs code * Fix tests * Distro * Fix tests and add removed extension point * Skip failing notebook tests for now * Disable broken tests and cleanup build folder * Update yarn.lock and fix smoke tests * Bump sqlite * fix contributed actions and file spacing * Fix user data path * Update yarn.locks Co-authored-by: ADS Merger <karlb@microsoft.com>
This commit is contained in:
@@ -9,11 +9,11 @@ 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, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IExtensionHost } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { RemoteExtensionHost, IRemoteExtensionHostDataProvider, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
@@ -26,8 +26,8 @@ import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remot
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
@@ -49,12 +49,13 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
@IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService,
|
||||
) {
|
||||
super(
|
||||
new ExtensionRunningLocationClassifier(
|
||||
productService,
|
||||
configurationService,
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely) => ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely)
|
||||
(extension) => this._getExtensionKind(extension),
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely, preference) => ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference)
|
||||
),
|
||||
instantiationService,
|
||||
notificationService,
|
||||
@@ -66,35 +67,25 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
extensionManifestPropertiesService
|
||||
);
|
||||
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
// Initialize only after workbench is ready
|
||||
this._lifecycleService.when(LifecyclePhase.Ready).then(() => this._initialize());
|
||||
// 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);
|
||||
this._initialize();
|
||||
});
|
||||
|
||||
this._initFetchFileSystem();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
this._disposables.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalWebWorker) {
|
||||
if (code === ExtensionHostExitCode.StartTimeout60s) {
|
||||
this._notificationService.prompt(
|
||||
Severity.Error,
|
||||
nls.localize('extensionService.startTimeout', "The Web Worker Extension Host did not start in 60s."),
|
||||
[]
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
|
||||
if (extension.location.scheme === Schemas.vscodeRemote) {
|
||||
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
|
||||
@@ -137,23 +128,39 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
};
|
||||
}
|
||||
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean): ExtensionRunningLocation {
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation {
|
||||
const result: ExtensionRunningLocation[] = [];
|
||||
let canRunRemotely = false;
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledRemotely) {
|
||||
// ui extensions run remotely if possible (but only as a last resort)
|
||||
canRunRemotely = true;
|
||||
if (preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
} else {
|
||||
canRunRemotely = true;
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalWebWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (canRunRemotely ? ExtensionRunningLocation.Remote : ExtensionRunningLocation.None);
|
||||
if (canRunRemotely) {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
}
|
||||
return (result.length > 0 ? result[0] : ExtensionRunningLocation.None);
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
|
||||
@@ -211,7 +218,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
public _onExtensionHostExit(code: number): void {
|
||||
// Dispose everything associated with the extension host
|
||||
this._stopExtensionHosts();
|
||||
this.stopExtensionHosts();
|
||||
|
||||
// We log the exit code to the console. Do NOT remove this
|
||||
// code as the automated integration tests in browser rely
|
||||
|
||||
@@ -85,14 +85,6 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
|
||||
}
|
||||
|
||||
private _wrapInIframe(): boolean {
|
||||
if (this._environmentService.options && typeof this._environmentService.options._wrapWebWorkerExtHostInIframe === 'boolean') {
|
||||
return this._environmentService.options._wrapWebWorkerExtHostInIframe;
|
||||
}
|
||||
// wrap in <iframe> by default
|
||||
return true;
|
||||
}
|
||||
|
||||
private _webWorkerExtensionHostIframeSrc(): string | null {
|
||||
if (this._environmentService.options && this._environmentService.options.webWorkerExtensionHostIframeSrc) {
|
||||
return this._environmentService.options.webWorkerExtensionHostIframeSrc;
|
||||
@@ -119,7 +111,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
if (!this._protocolPromise) {
|
||||
if (platform.isWeb) {
|
||||
const webWorkerExtensionHostIframeSrc = this._webWorkerExtensionHostIframeSrc();
|
||||
if (webWorkerExtensionHostIframeSrc && this._wrapInIframe()) {
|
||||
if (webWorkerExtensionHostIframeSrc) {
|
||||
this._protocolPromise = this._startInsideIframe(webWorkerExtensionHostIframeSrc);
|
||||
} else {
|
||||
console.warn(`The web worker extension host is started without an iframe sandbox!`);
|
||||
@@ -166,7 +158,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
};
|
||||
|
||||
startTimeout = setTimeout(() => {
|
||||
rejectBarrier(ExtensionHostExitCode.StartTimeout60s, new Error('The Web Worker Extension Host did not start in 60s'));
|
||||
console.warn(`The Web Worker Extension Host did not start in 60s, that might be a problem.`);
|
||||
}, 60000);
|
||||
|
||||
this._register(dom.addDisposableListener(window, 'message', (event) => {
|
||||
@@ -333,7 +325,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this._isTerminating) {
|
||||
return;
|
||||
}
|
||||
@@ -366,7 +358,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
extensionTestsLocationURI: undefined, // never run extension tests in web worker extension host
|
||||
extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI,
|
||||
globalStorageHome: this._environmentService.globalStorageHome,
|
||||
workspaceStorageHome: this._environmentService.workspaceStorageHome,
|
||||
webviewResourceRoot: this._environmentService.webviewResourceRoot,
|
||||
|
||||
@@ -21,7 +21,7 @@ import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensi
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind, IExtensionContributions } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
@@ -29,9 +29,10 @@ import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtens
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
@@ -41,7 +42,7 @@ export function parseScannedExtension(extension: ITranslatedScannedExtension): I
|
||||
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
isUnderDevelopment: extension.isUnderDevelopment,
|
||||
extensionLocation: extension.location,
|
||||
...extension.packageJSON,
|
||||
};
|
||||
@@ -61,6 +62,12 @@ export const enum ExtensionRunningLocation {
|
||||
Remote
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningPreference {
|
||||
None,
|
||||
Local,
|
||||
Remote
|
||||
}
|
||||
|
||||
export abstract class AbstractExtensionService extends Disposable implements IExtensionService {
|
||||
|
||||
public _serviceBrand: undefined;
|
||||
@@ -71,7 +78,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
protected 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>());
|
||||
protected 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>());
|
||||
@@ -88,8 +95,11 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
private readonly _proposedApiController: ProposedApiController;
|
||||
private readonly _isExtensionDevHost: boolean;
|
||||
protected readonly _isExtensionDevTestFromCli: boolean;
|
||||
|
||||
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
|
||||
private _inHandleDeltaExtensions: boolean;
|
||||
private readonly _onDidFinishHandleDeltaExtensions = this._register(new Emitter<void>());
|
||||
|
||||
protected _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
|
||||
// --- Members used per extension host process
|
||||
@@ -110,6 +120,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
@IExtensionManagementService protected readonly _extensionManagementService: IExtensionManagementService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IConfigurationService protected readonly _configurationService: IConfigurationService,
|
||||
@IExtensionManifestPropertiesService protected readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -135,6 +146,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
this._deltaExtensionsQueue = [];
|
||||
this._inHandleDeltaExtensions = false;
|
||||
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
this._register(this._extensionEnablementService.onEnablementChanged((extensions) => {
|
||||
@@ -169,6 +181,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}));
|
||||
}
|
||||
|
||||
protected _getExtensionKind(extensionDescription: IExtensionDescription): ExtensionKind[] {
|
||||
if (extensionDescription.isUnderDevelopment && this._environmentService.extensionDevelopmentKind) {
|
||||
return this._environmentService.extensionDevelopmentKind;
|
||||
}
|
||||
|
||||
return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription);
|
||||
}
|
||||
|
||||
protected _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
@@ -196,6 +216,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._inHandleDeltaExtensions = false;
|
||||
}
|
||||
}
|
||||
|
||||
this._onDidFinishHandleDeltaExtensions.fire();
|
||||
}
|
||||
|
||||
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
|
||||
@@ -203,16 +225,16 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
for (let i = 0, len = _toAdd.length; i < len; i++) {
|
||||
const extension = _toAdd[i];
|
||||
|
||||
if (!this._canAddExtension(extension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const extensionDescription = await this._scanSingleExtension(extension);
|
||||
if (!extensionDescription) {
|
||||
// could not scan extension...
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.canAddExtension(extensionDescription)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
toAdd.push(extensionDescription);
|
||||
}
|
||||
|
||||
@@ -277,9 +299,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
groupedToAdd[extensionHostKind] = filterByRunningLocation(toAdd, ext => ext.identifier, this._runningLocation, extensionRunningLocation);
|
||||
};
|
||||
for (const extension of toAdd) {
|
||||
const extensionKind = getExtensionKind(extension, this._productService, this._configurationService);
|
||||
const extensionKind = this._getExtensionKind(extension);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote);
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
this._runningLocation.set(ExtensionIdentifier.toKey(extension.identifier), runningLocation);
|
||||
}
|
||||
groupAdd(ExtensionHostKind.LocalProcess, ExtensionRunningLocation.LocalProcess);
|
||||
@@ -302,25 +324,21 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
|
||||
return this._canAddExtension(toExtension(extensionDescription));
|
||||
}
|
||||
|
||||
private _canAddExtension(extension: IExtension): boolean {
|
||||
const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id);
|
||||
if (extensionDescription) {
|
||||
public canAddExtension(extension: IExtensionDescription): boolean {
|
||||
const existing = this._registry.getExtensionDescription(extension.identifier);
|
||||
if (existing) {
|
||||
// this extension is already running (most likely at a different version)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if extension is renamed
|
||||
if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) {
|
||||
if (extension.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extensionKind = getExtensionKind(extension.manifest, this._productService, this._configurationService);
|
||||
const isRemote = extension.location.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote);
|
||||
const extensionKind = this._getExtensionKind(extension);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote, ExtensionRunningPreference.None);
|
||||
if (runningLocation === ExtensionRunningLocation.None) {
|
||||
return false;
|
||||
}
|
||||
@@ -412,6 +430,67 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
await this._scanAndHandleExtensions();
|
||||
this._releaseBarrier();
|
||||
perf.mark('code/didLoadExtensions');
|
||||
await this._handleExtensionTests();
|
||||
}
|
||||
|
||||
private async _handleExtensionTests(): Promise<void> {
|
||||
if (!this._environmentService.isExtensionDevelopment || !this._environmentService.extensionTestsLocationURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
const extensionHostManager = this.findTestExtensionHost(this._environmentService.extensionTestsLocationURI);
|
||||
if (!extensionHostManager) {
|
||||
const msg = nls.localize('extensionTestError', "No extension host found that can launch the test runner at {0}.", this._environmentService.extensionTestsLocationURI.toString());
|
||||
console.error(msg);
|
||||
this._notificationService.error(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let exitCode: number;
|
||||
try {
|
||||
exitCode = await extensionHostManager.extensionTestsExecute();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
exitCode = 1 /* ERROR */;
|
||||
}
|
||||
|
||||
await extensionHostManager.extensionTestsSendExit(exitCode);
|
||||
this._onExtensionHostExit(exitCode);
|
||||
}
|
||||
|
||||
private findTestExtensionHost(testLocation: URI): ExtensionHostManager | undefined | null {
|
||||
let extensionHostKind: ExtensionHostKind | undefined;
|
||||
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (extensionHostKind === undefined) {
|
||||
// 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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
if (extensionHostKind !== undefined) {
|
||||
return this._getExtensionHostManager(extensionHostKind);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _releaseBarrier(): void {
|
||||
@@ -420,7 +499,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier));
|
||||
}
|
||||
|
||||
protected _stopExtensionHosts(): void {
|
||||
//#region Stopping / Starting / Restarting
|
||||
|
||||
public stopExtensionHosts(): void {
|
||||
let previouslyActivatedExtensionIds: ExtensionIdentifier[] = [];
|
||||
this._extensionHostActiveExtensions.forEach((value) => {
|
||||
previouslyActivatedExtensionIds.push(value);
|
||||
@@ -440,8 +521,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
|
||||
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
this._stopExtensionHosts();
|
||||
|
||||
const extensionHosts = this._createExtensionHosts(isInitialStart);
|
||||
extensionHosts.forEach((extensionHost) => {
|
||||
const processManager = this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
|
||||
@@ -465,21 +544,37 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal);
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
|
||||
this._stopExtensionHosts();
|
||||
this.stopExtensionHosts();
|
||||
} else if (extensionHost.kind === ExtensionHostKind.Remote) {
|
||||
for (let i = 0; i < this._extensionHostManagers.length; i++) {
|
||||
if (this._extensionHostManagers[i] === extensionHost) {
|
||||
this._extensionHostManagers[i].dispose();
|
||||
this._extensionHostManagers.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async startExtensionHosts(): Promise<void> {
|
||||
this.stopExtensionHosts();
|
||||
|
||||
if (this._inHandleDeltaExtensions) {
|
||||
await Event.toPromise(this._onDidFinishHandleDeltaExtensions.event);
|
||||
}
|
||||
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
}
|
||||
|
||||
public async restartExtensionHost(): Promise<void> {
|
||||
this.stopExtensionHosts();
|
||||
await this.startExtensionHosts();
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region IExtensionService
|
||||
|
||||
public restartExtensionHost(): void {
|
||||
this._stopExtensionHosts();
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
}
|
||||
|
||||
protected startExtensionHost(): void {
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
}
|
||||
|
||||
public activateByEvent(activationEvent: string, activationKind: ActivationKind = ActivationKind.Normal): Promise<void> {
|
||||
if (this._installedExtensionsReady.isOpen()) {
|
||||
// Extensions have been scanned and interpreted
|
||||
@@ -535,14 +630,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
});
|
||||
}
|
||||
|
||||
public readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> {
|
||||
public readExtensionPointContributions<T extends IExtensionContributions[keyof IExtensionContributions]>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]> {
|
||||
return this._installedExtensionsReady.wait().then(() => {
|
||||
const availableExtensions = this._registry.getAllExtensionDescriptions();
|
||||
|
||||
const result: ExtensionPointContribution<T>[] = [];
|
||||
for (const desc of availableExtensions) {
|
||||
if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) {
|
||||
result.push(new ExtensionPointContribution<T>(desc, desc.contributes[extPoint.name])); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
result.push(new ExtensionPointContribution<T>(desc, desc.contributes[extPoint.name as keyof typeof desc.contributes] as T));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,23 +688,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
return extensions.filter(extension => this._isEnabled(extension));
|
||||
}
|
||||
|
||||
private _isExtensionUnderDevelopment(extension: IExtensionDescription): boolean {
|
||||
if (this._environmentService.isExtensionDevelopment) {
|
||||
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
|
||||
if (extDevLocs) {
|
||||
const extLocation = extension.extensionLocation;
|
||||
for (let p of extDevLocs) {
|
||||
if (isEqualOrParent(extLocation, p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected _isEnabled(extension: IExtensionDescription): boolean {
|
||||
if (this._isExtensionUnderDevelopment(extension)) {
|
||||
if (extension.isUnderDevelopment) {
|
||||
// Never disable extensions under development
|
||||
return true;
|
||||
}
|
||||
@@ -691,13 +771,13 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
}
|
||||
|
||||
private static _handleExtensionPoint<T>(extensionPoint: ExtensionPoint<T>, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void {
|
||||
private static _handleExtensionPoint<T extends IExtensionContributions[keyof IExtensionContributions]>(extensionPoint: ExtensionPoint<T>, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void {
|
||||
const users: IExtensionPointUser<T>[] = [];
|
||||
for (const desc of availableExtensions) {
|
||||
if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) {
|
||||
users.push({
|
||||
description: desc,
|
||||
value: desc.contributes[extensionPoint.name], // {{SQL CARBON EDIT}} strict-null-checks
|
||||
value: desc.contributes[extensionPoint.name as keyof typeof desc.contributes] as T,
|
||||
collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name)
|
||||
});
|
||||
}
|
||||
@@ -725,7 +805,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
//#region Called by extension host
|
||||
|
||||
public _logOrShowMessage(severity: Severity, msg: string): void {
|
||||
protected _logOrShowMessage(severity: Severity, msg: string): void {
|
||||
if (this._isDev) {
|
||||
this._showMessageToUser(severity, msg);
|
||||
} else {
|
||||
@@ -752,6 +832,21 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onDidChangeExtensionsStatus.fire([extensionId]);
|
||||
}
|
||||
|
||||
public _onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void {
|
||||
type ExtensionActivationErrorClassification = {
|
||||
extensionId: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
error: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
};
|
||||
type ExtensionActivationErrorEvent = {
|
||||
extensionId: string;
|
||||
error: string;
|
||||
};
|
||||
this._telemetryService.publicLog2<ExtensionActivationErrorEvent, ExtensionActivationErrorClassification>('extensionActivationError', {
|
||||
extensionId: extensionId.value,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
|
||||
public _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void {
|
||||
const extensionKey = ExtensionIdentifier.toKey(extensionId);
|
||||
if (!this._extensionHostExtensionRuntimeErrors.has(extensionKey)) {
|
||||
@@ -771,33 +866,57 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
export class ExtensionRunningLocationClassifier {
|
||||
constructor(
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
public readonly pickRunningLocation: (extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean) => ExtensionRunningLocation,
|
||||
public readonly getExtensionKind: (extensionDescription: IExtensionDescription) => ExtensionKind[],
|
||||
public readonly pickRunningLocation: (extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference) => ExtensionRunningLocation,
|
||||
) {
|
||||
}
|
||||
|
||||
public determineRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[]): Map<string, ExtensionRunningLocation> {
|
||||
const allExtensionKinds = new Map<string, ExtensionKind[]>();
|
||||
localExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, this._productService, this._configurationService)));
|
||||
remoteExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, this._productService, this._configurationService)));
|
||||
localExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), this.getExtensionKind(ext)));
|
||||
remoteExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), this.getExtensionKind(ext)));
|
||||
|
||||
const localExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const localUnderDevelopmentExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach((ext) => {
|
||||
if (ext.isUnderDevelopment) {
|
||||
localUnderDevelopmentExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier));
|
||||
}
|
||||
});
|
||||
|
||||
const remoteExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const extensionKinds = allExtensionKinds.get(ExtensionIdentifier.toKey(extension.identifier)) || [];
|
||||
return this.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely);
|
||||
const remoteUnderDevelopmentExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach((ext) => {
|
||||
if (ext.isUnderDevelopment) {
|
||||
remoteUnderDevelopmentExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier));
|
||||
}
|
||||
});
|
||||
|
||||
const pickRunningLocation = (extensionIdentifier: ExtensionIdentifier): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extensionIdentifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extensionIdentifier));
|
||||
|
||||
const isLocallyUnderDevelopment = localUnderDevelopmentExtensionsSet.has(ExtensionIdentifier.toKey(extensionIdentifier));
|
||||
const isRemotelyUnderDevelopment = remoteUnderDevelopmentExtensionsSet.has(ExtensionIdentifier.toKey(extensionIdentifier));
|
||||
|
||||
let preference = ExtensionRunningPreference.None;
|
||||
if (isLocallyUnderDevelopment && !isRemotelyUnderDevelopment) {
|
||||
preference = ExtensionRunningPreference.Local;
|
||||
} else if (isRemotelyUnderDevelopment && !isLocallyUnderDevelopment) {
|
||||
preference = ExtensionRunningPreference.Remote;
|
||||
}
|
||||
|
||||
const extensionKinds = allExtensionKinds.get(ExtensionIdentifier.toKey(extensionIdentifier)) || [];
|
||||
return this.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference);
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext.identifier)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext.identifier)));
|
||||
return runningLocation;
|
||||
}
|
||||
}
|
||||
@@ -817,7 +936,7 @@ class ProposedApiController {
|
||||
|
||||
this.enableProposedApiForAll =
|
||||
!_environmentService.isBuilt || // always allow proposed API when running out of sources
|
||||
(!!_environmentService.extensionDevelopmentLocationURI && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
|
||||
(_environmentService.isExtensionDevelopment && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
|
||||
(this.enableProposedApiFor.length === 0 && Array.isArray(_environmentService.extensionEnabledProposedApi)); // always allow proposed API if --enable-proposed-api is provided without extension ID
|
||||
|
||||
this.productAllowProposedApi = new Set<string>();
|
||||
|
||||
@@ -23,6 +23,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IExtensionHost, ExtensionHostKind, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
@@ -70,7 +71,7 @@ export class ExtensionHostManager extends Disposable {
|
||||
return { value: this._createExtensionHostCustomers(protocol) };
|
||||
},
|
||||
(err) => {
|
||||
console.error('Error received from starting extension host');
|
||||
console.error(`Error received from starting extension host (kind: ${this.kind})`);
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
@@ -84,7 +85,7 @@ export class ExtensionHostManager extends Disposable {
|
||||
this._resolveAuthorityAttempt = 0;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
if (this._extensionHost) {
|
||||
this._extensionHost.dispose();
|
||||
}
|
||||
@@ -294,6 +295,28 @@ export class ExtensionHostManager extends Disposable {
|
||||
return proxy.$startExtensionHost(enabledExtensionIds);
|
||||
}
|
||||
|
||||
public async extensionTestsExecute(): Promise<number> {
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
throw new Error('Could not obtain Extension Host Proxy');
|
||||
}
|
||||
return proxy.$extensionTestsExecute();
|
||||
}
|
||||
|
||||
public async extensionTestsSendExit(exitCode: number): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
// This method does not wait for the actual RPC to be confirmed
|
||||
// It waits for the socket to drain (i.e. the message has been sent)
|
||||
// It also times out after 5s in case drain takes too long
|
||||
proxy.$extensionTestsExit(exitCode);
|
||||
if (this._rpcProtocol) {
|
||||
await Promise.race([this._rpcProtocol.drain(), timeout(5000)]);
|
||||
}
|
||||
}
|
||||
|
||||
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
const proxy = await this._getProxy();
|
||||
if (!proxy) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
||||
export const enum ExtensionHostExitCode {
|
||||
// nodejs uses codes 1-13 and exit codes >128 are signal exits
|
||||
VersionMismatch = 55,
|
||||
StartTimeout60s = 56,
|
||||
UnexpectedError = 81,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ExtensionUntrustedWorkspaceSupport } from 'vs/base/common/product';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isWorkspaceTrustEnabled, WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
|
||||
export const IExtensionManifestPropertiesService = createDecorator<IExtensionManifestPropertiesService>('extensionManifestPropertiesService');
|
||||
|
||||
export interface IExtensionManifestPropertiesService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
prefersExecuteOnUI(manifest: IExtensionManifest): boolean;
|
||||
prefersExecuteOnWorkspace(manifest: IExtensionManifest): boolean;
|
||||
prefersExecuteOnWeb(manifest: IExtensionManifest): boolean;
|
||||
|
||||
canExecuteOnUI(manifest: IExtensionManifest): boolean;
|
||||
canExecuteOnWorkspace(manifest: IExtensionManifest): boolean;
|
||||
canExecuteOnWeb(manifest: IExtensionManifest): boolean;
|
||||
|
||||
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[];
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType;
|
||||
canSupportVirtualWorkspace(manifest: IExtensionManifest): boolean;
|
||||
}
|
||||
|
||||
export class ExtensionManifestPropertiesService extends Disposable implements IExtensionManifestPropertiesService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private _uiExtensionPoints: Set<string> | null = null;
|
||||
private _productExtensionKindsMap: Map<string, ExtensionKind[]> | null = null;
|
||||
private _configuredExtensionKindsMap: Map<string, ExtensionKind | ExtensionKind[]> | null = null;
|
||||
|
||||
private _productVirtualWorkspaceSupportMap: Map<string, { default?: boolean, override?: boolean }> | null = null;
|
||||
private _configuredVirtualWorkspaceSupportMap: Map<string, boolean> | null = null;
|
||||
|
||||
private readonly _configuredExtensionWorkspaceTrustRequestMap: Map<string, { supported: ExtensionUntrustedWorkpaceSupportType, version?: string }>;
|
||||
private readonly _productExtensionWorkspaceTrustRequestMap: Map<string, ExtensionUntrustedWorkspaceSupport>;
|
||||
|
||||
constructor(
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
// Workspace trust request type (settings.json)
|
||||
this._configuredExtensionWorkspaceTrustRequestMap = new Map<string, { supported: ExtensionUntrustedWorkpaceSupportType, version?: string }>();
|
||||
const configuredExtensionWorkspaceTrustRequests = configurationService.inspect<{ [key: string]: { supported: ExtensionUntrustedWorkpaceSupportType, version?: string } }>(WORKSPACE_TRUST_EXTENSION_SUPPORT).userValue || {};
|
||||
for (const id of Object.keys(configuredExtensionWorkspaceTrustRequests)) {
|
||||
this._configuredExtensionWorkspaceTrustRequestMap.set(ExtensionIdentifier.toKey(id), configuredExtensionWorkspaceTrustRequests[id]);
|
||||
}
|
||||
|
||||
// Workpace trust request type (products.json)
|
||||
this._productExtensionWorkspaceTrustRequestMap = new Map<string, ExtensionUntrustedWorkspaceSupport>();
|
||||
if (productService.extensionUntrustedWorkspaceSupport) {
|
||||
for (const id of Object.keys(productService.extensionUntrustedWorkspaceSupport)) {
|
||||
this._productExtensionWorkspaceTrustRequestMap.set(ExtensionIdentifier.toKey(id), productService.extensionUntrustedWorkspaceSupport[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prefersExecuteOnUI(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'ui');
|
||||
}
|
||||
|
||||
prefersExecuteOnWorkspace(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'workspace');
|
||||
}
|
||||
|
||||
prefersExecuteOnWeb(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'web');
|
||||
}
|
||||
|
||||
canExecuteOnUI(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'ui');
|
||||
}
|
||||
|
||||
canExecuteOnWorkspace(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'workspace');
|
||||
}
|
||||
|
||||
canExecuteOnWeb(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'web');
|
||||
}
|
||||
|
||||
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
// check in config
|
||||
let result = this.getConfiguredExtensionKind(manifest);
|
||||
if (typeof result !== 'undefined') {
|
||||
return this.toArray(result);
|
||||
}
|
||||
|
||||
// check product.json
|
||||
result = this.getProductExtensionKind(manifest);
|
||||
if (typeof result !== 'undefined') {
|
||||
return result;
|
||||
}
|
||||
|
||||
// check the manifest itself
|
||||
result = manifest.extensionKind;
|
||||
if (typeof result !== 'undefined') {
|
||||
return this.toArray(result);
|
||||
}
|
||||
|
||||
return this.deduceExtensionKind(manifest);
|
||||
}
|
||||
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType {
|
||||
// Workspace trust feature is disabled, or extension has no entry point
|
||||
if (!isWorkspaceTrustEnabled(this.configurationService) || !manifest.main) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get extension workspace trust requirements from settings.json
|
||||
const configuredWorkspaceTrustRequest = this.getConfiguredExtensionWorkspaceTrustRequest(manifest);
|
||||
|
||||
// Get extension workspace trust requirements from product.json
|
||||
const productWorkspaceTrustRequest = this.getProductExtensionWorkspaceTrustRequest(manifest);
|
||||
|
||||
// Use settings.json override value if it exists
|
||||
if (configuredWorkspaceTrustRequest) {
|
||||
return configuredWorkspaceTrustRequest;
|
||||
}
|
||||
|
||||
// Use product.json override value if it exists
|
||||
if (productWorkspaceTrustRequest?.override) {
|
||||
return productWorkspaceTrustRequest.override;
|
||||
}
|
||||
|
||||
// Use extension manifest value if it exists
|
||||
if (manifest.capabilities?.untrustedWorkspaces?.supported !== undefined) {
|
||||
return manifest.capabilities.untrustedWorkspaces.supported;
|
||||
}
|
||||
|
||||
// Use product.json default value if it exists
|
||||
if (productWorkspaceTrustRequest?.default) {
|
||||
return productWorkspaceTrustRequest.default;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
canSupportVirtualWorkspace(manifest: IExtensionManifest): boolean {
|
||||
// check user configured
|
||||
const userConfiguredVirtualWorkspaceSupport = this.getConfiguredVirtualWorkspaceSupport(manifest);
|
||||
if (userConfiguredVirtualWorkspaceSupport !== undefined) {
|
||||
return userConfiguredVirtualWorkspaceSupport;
|
||||
}
|
||||
|
||||
const productConfiguredWorkspaceSchemes = this.getProductVirtualWorkspaceSupport(manifest);
|
||||
|
||||
// check override from product
|
||||
if (productConfiguredWorkspaceSchemes?.override !== undefined) {
|
||||
return productConfiguredWorkspaceSchemes.override;
|
||||
}
|
||||
|
||||
// check the manifest
|
||||
if (manifest.capabilities?.virtualWorkspaces !== undefined) {
|
||||
return manifest.capabilities?.virtualWorkspaces;
|
||||
}
|
||||
|
||||
// check default from product
|
||||
if (productConfiguredWorkspaceSchemes?.default !== undefined) {
|
||||
return productConfiguredWorkspaceSchemes.default;
|
||||
}
|
||||
|
||||
// Default - supports virtual workspace
|
||||
return true;
|
||||
}
|
||||
|
||||
deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
// Not an UI extension if it has main
|
||||
if (manifest.main) {
|
||||
if (manifest.browser) {
|
||||
return ['workspace', 'web'];
|
||||
}
|
||||
return ['workspace'];
|
||||
}
|
||||
|
||||
if (manifest.browser) {
|
||||
return ['web'];
|
||||
}
|
||||
|
||||
// Not an UI nor web extension if it has dependencies or an extension pack
|
||||
if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) {
|
||||
return ['workspace'];
|
||||
}
|
||||
|
||||
if (manifest.contributes) {
|
||||
// Not an UI nor web extension if it has no ui contributions
|
||||
for (const contribution of Object.keys(manifest.contributes)) {
|
||||
if (!this.isUIExtensionPoint(contribution)) {
|
||||
return ['workspace'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['ui', 'workspace', 'web'];
|
||||
}
|
||||
|
||||
private isUIExtensionPoint(extensionPoint: string): boolean {
|
||||
if (this._uiExtensionPoints === null) {
|
||||
const uiExtensionPoints = new Set<string>();
|
||||
ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => {
|
||||
uiExtensionPoints.add(e.name);
|
||||
});
|
||||
this._uiExtensionPoints = uiExtensionPoints;
|
||||
}
|
||||
return this._uiExtensionPoints.has(extensionPoint);
|
||||
}
|
||||
|
||||
private getProductExtensionKind(manifest: IExtensionManifest): ExtensionKind[] | undefined {
|
||||
if (this._productExtensionKindsMap === null) {
|
||||
const productExtensionKindsMap = new Map<string, ExtensionKind[]>();
|
||||
if (this.productService.extensionKind) {
|
||||
for (const id of Object.keys(this.productService.extensionKind)) {
|
||||
productExtensionKindsMap.set(ExtensionIdentifier.toKey(id), this.productService.extensionKind[id]);
|
||||
}
|
||||
}
|
||||
this._productExtensionKindsMap = productExtensionKindsMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private getConfiguredExtensionKind(manifest: IExtensionManifest): ExtensionKind | ExtensionKind[] | undefined {
|
||||
if (this._configuredExtensionKindsMap === null) {
|
||||
const configuredExtensionKindsMap = new Map<string, ExtensionKind | ExtensionKind[]>();
|
||||
const configuredExtensionKinds = this.configurationService.getValue<{ [key: string]: ExtensionKind | ExtensionKind[] }>('remote.extensionKind') || {};
|
||||
for (const id of Object.keys(configuredExtensionKinds)) {
|
||||
configuredExtensionKindsMap.set(ExtensionIdentifier.toKey(id), configuredExtensionKinds[id]);
|
||||
}
|
||||
this._configuredExtensionKindsMap = configuredExtensionKindsMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private getProductVirtualWorkspaceSupport(manifest: IExtensionManifest): { default?: boolean, override?: boolean } | undefined {
|
||||
if (this._productVirtualWorkspaceSupportMap === null) {
|
||||
const productWorkspaceSchemesMap = new Map<string, { default?: boolean, override?: boolean }>();
|
||||
if (this.productService.extensionVirtualWorkspacesSupport) {
|
||||
for (const id of Object.keys(this.productService.extensionVirtualWorkspacesSupport)) {
|
||||
productWorkspaceSchemesMap.set(ExtensionIdentifier.toKey(id), this.productService.extensionVirtualWorkspacesSupport[id]);
|
||||
}
|
||||
}
|
||||
this._productVirtualWorkspaceSupportMap = productWorkspaceSchemesMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._productVirtualWorkspaceSupportMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private getConfiguredVirtualWorkspaceSupport(manifest: IExtensionManifest): boolean | undefined {
|
||||
if (this._configuredVirtualWorkspaceSupportMap === null) {
|
||||
const configuredWorkspaceSchemesMap = new Map<string, boolean>();
|
||||
const configuredWorkspaceSchemes = this.configurationService.getValue<{ [key: string]: boolean }>('extensions.supportVirtualWorkspaces') || {};
|
||||
for (const id of Object.keys(configuredWorkspaceSchemes)) {
|
||||
if (configuredWorkspaceSchemes[id] !== undefined) {
|
||||
configuredWorkspaceSchemesMap.set(ExtensionIdentifier.toKey(id), configuredWorkspaceSchemes[id]);
|
||||
}
|
||||
}
|
||||
this._configuredVirtualWorkspaceSupportMap = configuredWorkspaceSchemesMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._configuredVirtualWorkspaceSupportMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType | undefined {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
const extensionWorkspaceTrustRequest = this._configuredExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
|
||||
if (extensionWorkspaceTrustRequest && (extensionWorkspaceTrustRequest.version === undefined || extensionWorkspaceTrustRequest.version === manifest.version)) {
|
||||
return extensionWorkspaceTrustRequest.supported;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getProductExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupport | undefined {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return this._productExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[] {
|
||||
if (Array.isArray(extensionKind)) {
|
||||
return extensionKind;
|
||||
}
|
||||
return extensionKind === 'ui' ? ['ui', 'workspace'] : [extensionKind];
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionManifestPropertiesService, ExtensionManifestPropertiesService);
|
||||
@@ -8,7 +8,7 @@ import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, IExtensionContributions } from 'vs/platform/extensions/common/extensions';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
@@ -41,8 +41,7 @@ export interface IExtensionsStatus {
|
||||
runtimeErrors: Error[];
|
||||
}
|
||||
|
||||
export type ExtensionActivationError = string | MissingDependencyError;
|
||||
export class MissingDependencyError {
|
||||
export class MissingExtensionDependency {
|
||||
constructor(readonly dependency: string) { }
|
||||
}
|
||||
|
||||
@@ -224,7 +223,7 @@ export interface IExtensionService {
|
||||
/**
|
||||
* Read all contributions to an extension point.
|
||||
*/
|
||||
readExtensionPointContributions<T>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
|
||||
readExtensionPointContributions<T extends IExtensionContributions[keyof IExtensionContributions]>(extPoint: IExtensionPoint<T>): Promise<ExtensionPointContribution<T>[]>;
|
||||
|
||||
/**
|
||||
* Get information about extensions status.
|
||||
@@ -237,10 +236,20 @@ export interface IExtensionService {
|
||||
*/
|
||||
getInspectPort(tryEnableInspector: boolean): Promise<number>;
|
||||
|
||||
/**
|
||||
* Stops the extension hosts.
|
||||
*/
|
||||
stopExtensionHosts(): void;
|
||||
|
||||
/**
|
||||
* Restarts the extension host.
|
||||
*/
|
||||
restartExtensionHost(): void;
|
||||
restartExtensionHost(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Starts the extension hosts.
|
||||
*/
|
||||
startExtensionHosts(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Modify the environment of the remote extension host
|
||||
@@ -248,12 +257,11 @@ export interface IExtensionService {
|
||||
*/
|
||||
setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
|
||||
|
||||
_logOrShowMessage(severity: Severity, msg: string): void;
|
||||
_activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
|
||||
_onWillActivateExtension(extensionId: ExtensionIdentifier): void;
|
||||
_onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
|
||||
_onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void;
|
||||
_onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void;
|
||||
_onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
export interface ProfileSession {
|
||||
@@ -307,14 +315,16 @@ export class NullExtensionService implements IExtensionService {
|
||||
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); }
|
||||
restartExtensionHost(): void { }
|
||||
stopExtensionHosts(): void { }
|
||||
async restartExtensionHost(): Promise<void> { }
|
||||
async startExtensionHosts(): Promise<void> { }
|
||||
async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise<void> { }
|
||||
canAddExtension(): boolean { return false; }
|
||||
canRemoveExtension(): boolean { return false; }
|
||||
_logOrShowMessage(_severity: Severity, _msg: string): void { }
|
||||
_activateById(_extensionId: ExtensionIdentifier, _reason: ExtensionActivationReason): Promise<void> { return Promise.resolve(); }
|
||||
_onWillActivateExtension(_extensionId: ExtensionIdentifier): void { }
|
||||
_onDidActivateExtension(_extensionId: ExtensionIdentifier, _codeLoadingTime: number, _activateCallTime: number, _activateResolvedTime: number, _activationReason: ExtensionActivationReason): void { }
|
||||
_onDidActivateExtensionError(_extensionId: ExtensionIdentifier, _error: Error): void { }
|
||||
_onExtensionRuntimeError(_extensionId: ExtensionIdentifier, _err: Error): void { }
|
||||
_onExtensionHostExit(code: number): void { }
|
||||
}
|
||||
|
||||
@@ -315,6 +315,11 @@ export const schema: IJSONSchema = {
|
||||
body: 'onNotebook:${10:viewType}',
|
||||
description: nls.localize('vscode.extension.activationEvents.onNotebook', 'An activation event emitted whenever the specified notebook document is opened.'),
|
||||
},
|
||||
{
|
||||
label: 'onAuthenticationRequest',
|
||||
body: 'onAuthenticationRequest:${11:authenticationProviderId}',
|
||||
description: nls.localize('vscode.extension.activationEvents.onAuthenticationRequest', 'An activation event emitted whenever sessions are requested from the specified authentication provider.')
|
||||
},
|
||||
{
|
||||
label: '*',
|
||||
description: nls.localize('vscode.extension.activationEvents.star', 'An activation event emitted on VS Code startup. To ensure a great end user experience, please use this activation event in your extension only when no other activation events combination works in your use-case.'),
|
||||
@@ -410,6 +415,48 @@ export const schema: IJSONSchema = {
|
||||
}
|
||||
]
|
||||
},
|
||||
capabilities: {
|
||||
description: nls.localize('vscode.extension.capabilities', "Declare the set of supported capabilities by the extension."),
|
||||
type: 'object',
|
||||
properties: {
|
||||
virtualWorkspaces: {
|
||||
description: nls.localize('vscode.extension.capabilities.virtualWorkspaces', "Declares whether the extension should be enabled in virtual workspaces. A virtual workspace is a workspace which is not backed by any on-disk resources. When false, this extension will be automatically disabled in virtual workspaces. Default is true."),
|
||||
type: 'boolean',
|
||||
default: true
|
||||
},
|
||||
untrustedWorkspaces: {
|
||||
description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces', 'Declares how the extension should be handled in untrusted workspaces.'),
|
||||
type: 'object',
|
||||
required: ['supported'],
|
||||
defaultSnippets: [
|
||||
{ body: { supported: '${1:limited}', description: '${2}' } },
|
||||
],
|
||||
properties: {
|
||||
supported: {
|
||||
markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported', "Declares the level of support for untrusted workspaces by the extension."),
|
||||
type: ['string', 'boolean'],
|
||||
enum: ['limited', true, false],
|
||||
enumDescriptions: [
|
||||
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.limited', "The extension will be enabled in untrusted workspaces with some functionality disabled."),
|
||||
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.true', "The extension will be enabled in untrusted workspaces with all functionality enabled."),
|
||||
nls.localize('vscode.extension.capabilities.untrustedWorkspaces.supported.false', "The extension will not be enabled in untrusted workspaces."),
|
||||
]
|
||||
},
|
||||
restrictedConfigurations: {
|
||||
description: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.restrictedConfigurations', "A list of configuration keys contributed by the extension that should not use workspace values in untrusted workspaces."),
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
markdownDescription: nls.localize('vscode.extension.capabilities.untrustedWorkspaces.description', "A description of how workspace trust affects the extensions behavior and why it is needed. This only applies when `supported` is not `true`."),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
scripts: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
@@ -10,56 +10,63 @@ import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/ex
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
export function prefersExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'ui');
|
||||
}
|
||||
|
||||
export function prefersExecuteOnWorkspace(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'workspace');
|
||||
}
|
||||
|
||||
export function prefersExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'web');
|
||||
}
|
||||
|
||||
export function canExecuteOnUI(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return extensionKind.some(kind => kind === 'ui');
|
||||
}
|
||||
|
||||
export function canExecuteOnWorkspace(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return extensionKind.some(kind => kind === 'workspace');
|
||||
}
|
||||
|
||||
export function canExecuteOnWeb(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean {
|
||||
const extensionKind = getExtensionKind(manifest, productService, configurationService);
|
||||
return extensionKind.some(kind => kind === 'web');
|
||||
}
|
||||
|
||||
export function getExtensionKind(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): ExtensionKind[] {
|
||||
// check in config
|
||||
let result = getConfiguredExtensionKind(manifest, configurationService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
export class ExtensionKindController2 {
|
||||
constructor(
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
}
|
||||
prefersExecuteOnUI(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'ui');
|
||||
}
|
||||
|
||||
// check product.json
|
||||
result = getProductExtensionKind(manifest, productService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return result;
|
||||
prefersExecuteOnWorkspace(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'workspace');
|
||||
}
|
||||
|
||||
// check the manifest itself
|
||||
result = manifest.extensionKind;
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
prefersExecuteOnWeb(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return (extensionKind.length > 0 && extensionKind[0] === 'web');
|
||||
}
|
||||
|
||||
return deduceExtensionKind(manifest);
|
||||
canExecuteOnUI(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'ui');
|
||||
}
|
||||
|
||||
canExecuteOnWorkspace(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'workspace');
|
||||
}
|
||||
|
||||
canExecuteOnWeb(manifest: IExtensionManifest): boolean {
|
||||
const extensionKind = this.getExtensionKind(manifest);
|
||||
return extensionKind.some(kind => kind === 'web');
|
||||
}
|
||||
|
||||
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
// check in config
|
||||
let result = getConfiguredExtensionKind(manifest, this.configurationService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
}
|
||||
|
||||
// check product.json
|
||||
result = getProductExtensionKind(manifest, this.productService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return result;
|
||||
}
|
||||
|
||||
// check the manifest itself
|
||||
result = manifest.extensionKind;
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
}
|
||||
|
||||
return deduceExtensionKind(manifest);
|
||||
}
|
||||
}
|
||||
|
||||
export function deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
@@ -141,3 +148,4 @@ function toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[
|
||||
}
|
||||
return extensionKind === 'ui' ? ['ui', 'workspace'] : [extensionKind];
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
this._hasLostConnection = false;
|
||||
this._terminating = false;
|
||||
|
||||
this._register(this._lifecycleService.onShutdown(reason => this.dispose()));
|
||||
this._register(this._lifecycleService.onDidShutdown(() => this.dispose()));
|
||||
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
this._isExtensionDevHost = devOpts.isExtensionDevHost;
|
||||
@@ -270,7 +270,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this._terminating = true;
|
||||
|
||||
@@ -110,7 +110,7 @@ export class RPCProtocol extends Disposable implements IRPCProtocol {
|
||||
this._protocol.onMessage((msg) => this._receiveOneMessage(msg));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
public override dispose(): void {
|
||||
this._isDisposed = true;
|
||||
|
||||
// Release all outstanding promises with a canceled error
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { LocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-browser/localProcessExtensionHost';
|
||||
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -15,7 +15,7 @@ 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, RemoteTrustOption, 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';
|
||||
@@ -42,6 +42,12 @@ import { Schemas } from 'vs/base/common/network';
|
||||
import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { updateProxyConfigurationsScope } from 'vs/platform/request/common/request';
|
||||
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
|
||||
const MACHINE_PROMPT = false;
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
@@ -52,7 +58,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@INotificationService notificationService: INotificationService,
|
||||
@IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IWorkbenchEnvironmentService _environmentService: IWorkbenchEnvironmentService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IFileService fileService: IFileService,
|
||||
@@ -69,12 +75,14 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
|
||||
@IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IDialogService private readonly _dialogService: IDialogService,
|
||||
@IWorkspaceTrustManagementService private readonly _workspaceTrustManagementService: IWorkspaceTrustManagementService,
|
||||
@IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
) {
|
||||
super(
|
||||
new ExtensionRunningLocationClassifier(
|
||||
productService,
|
||||
configurationService,
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely) => this._pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely)
|
||||
(extension) => this._getExtensionKind(extension),
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely, preference) => this._pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference)
|
||||
),
|
||||
instantiationService,
|
||||
notificationService,
|
||||
@@ -86,9 +94,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
extensionManifestPropertiesService
|
||||
);
|
||||
|
||||
this._enableLocalWebWorker = this._configurationService.getValue<boolean>(webWorkerExtHostConfig);
|
||||
this._enableLocalWebWorker = this._isLocalWebWorkerEnabled();
|
||||
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
|
||||
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
|
||||
|
||||
@@ -106,6 +115,16 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
});
|
||||
}
|
||||
|
||||
private _isLocalWebWorkerEnabled() {
|
||||
if (this._configurationService.getValue<boolean>(webWorkerExtHostConfig)) {
|
||||
return true;
|
||||
}
|
||||
if (this._environmentService.isExtensionDevelopment && this._environmentService.extensionDevelopmentKind?.some(k => k === 'web')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
|
||||
if (extension.location.scheme === Schemas.vscodeRemote) {
|
||||
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
|
||||
@@ -155,26 +174,47 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
};
|
||||
}
|
||||
|
||||
private _pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean): ExtensionRunningLocation {
|
||||
private _pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference): ExtensionRunningLocation {
|
||||
return ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely, preference, Boolean(this._environmentService.remoteAuthority), this._enableLocalWebWorker);
|
||||
}
|
||||
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean, preference: ExtensionRunningPreference, hasRemoteExtHost: boolean, hasWebWorkerExtHost: boolean): ExtensionRunningLocation {
|
||||
const result: ExtensionRunningLocation[] = [];
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledLocally) {
|
||||
// ui extensions run locally if possible
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalProcess);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Remote) {
|
||||
return ExtensionRunningLocation.Remote;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.Remote);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'workspace' && !this._environmentService.remoteAuthority) {
|
||||
if (extensionKind === 'workspace' && !hasRemoteExtHost) {
|
||||
// workspace extensions also run locally if there is no remote
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalProcess);
|
||||
}
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally && this._enableLocalWebWorker) {
|
||||
if (extensionKind === 'web' && isInstalledLocally && hasWebWorkerExtHost) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
if (preference === ExtensionRunningPreference.None || preference === ExtensionRunningPreference.Local) {
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
} else {
|
||||
result.push(ExtensionRunningLocation.LocalWebWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ExtensionRunningLocation.None;
|
||||
return (result.length > 0 ? result[0] : ExtensionRunningLocation.None);
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(isInitialStart: boolean): IExtensionHost[] {
|
||||
@@ -197,7 +237,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
return result;
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
protected override _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
const activatedExtensions = Array.from(this._extensionHostActiveExtensions.values());
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
|
||||
@@ -229,7 +269,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
},
|
||||
{
|
||||
label: nls.localize('restart', "Restart Extension Host"),
|
||||
run: () => this.startExtensionHost()
|
||||
run: () => this.startExtensionHosts()
|
||||
}]
|
||||
);
|
||||
|
||||
@@ -328,6 +368,38 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
return;
|
||||
}
|
||||
|
||||
let promptForMachineTrust = MACHINE_PROMPT;
|
||||
|
||||
if (resolverResult.options?.trust === RemoteTrustOption.DisableTrust) {
|
||||
promptForMachineTrust = false;
|
||||
this._workspaceTrustManagementService.setWorkspaceTrust(true);
|
||||
} else if (resolverResult.options?.trust === RemoteTrustOption.MachineTrusted) {
|
||||
promptForMachineTrust = false;
|
||||
}
|
||||
|
||||
if (promptForMachineTrust) {
|
||||
const dialogResult = await this._dialogService.show(
|
||||
Severity.Info,
|
||||
nls.localize('machineTrustQuestion', "Do you trust the machine you're connecting to?"),
|
||||
[nls.localize('yes', "Yes, connect."), nls.localize('no', "No, do not connect.")],
|
||||
{
|
||||
cancelId: 1,
|
||||
custom: {
|
||||
icon: Codicon.remoteExplorer
|
||||
},
|
||||
// checkbox: { label: nls.localize('remember', "Remember my choice"), checked: true }
|
||||
}
|
||||
);
|
||||
|
||||
if (dialogResult.choice !== 0) {
|
||||
// Did not confirm trust
|
||||
this._notificationService.notify({ severity: Severity.Warning, message: nls.localize('trustFailure', "Refused to connect to untrusted machine.") });
|
||||
// Proceed with the local extension host
|
||||
await this._startLocalExtensionHost(localExtensions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set the resolved authority
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(resolverResult.authority, resolverResult.options);
|
||||
this._remoteExplorerService.setTunnelInformation(resolverResult.tunnelInformation);
|
||||
@@ -403,7 +475,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
}
|
||||
|
||||
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
public override async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
return localProcessExtensionHost.getInspectPort(tryEnableInspector);
|
||||
@@ -413,7 +485,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
public _onExtensionHostExit(code: number): void {
|
||||
// Dispose everything associated with the extension host
|
||||
this._stopExtensionHosts();
|
||||
this.stopExtensionHosts();
|
||||
|
||||
if (this._isExtensionDevTestFromCli) {
|
||||
// When CLI testing make sure to exit with proper exit code
|
||||
|
||||
@@ -47,6 +47,7 @@ import { isUUID } from 'vs/base/common/uuid';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import { StringDecoder } from 'string_decoder';
|
||||
import { IShellEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/shellEnvironmentService';
|
||||
|
||||
export interface ILocalProcessExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
@@ -104,7 +105,8 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IProductService private readonly _productService: IProductService
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@IShellEnvironmentService private readonly _shellEnvironmentService: IShellEnvironmentService
|
||||
) {
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
this._isExtensionDevHost = devOpts.isExtensionDevHost;
|
||||
@@ -125,7 +127,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
this._toDispose.add(this._onExit);
|
||||
this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e)));
|
||||
this._toDispose.add(this._lifecycleService.onShutdown(reason => this.terminate()));
|
||||
this._toDispose.add(this._lifecycleService.onDidShutdown(reason => this.terminate()));
|
||||
this._toDispose.add(this._extensionHostDebugService.onClose(event => {
|
||||
if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||
this._nativeHostService.closeWindow();
|
||||
@@ -157,9 +159,10 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
if (!this._messageProtocol) {
|
||||
this._messageProtocol = Promise.all([
|
||||
this._tryListenOnPipe(),
|
||||
this._tryFindDebugPort()
|
||||
]).then(([pipeName, portNumber]) => {
|
||||
const env = objects.mixin(objects.deepClone(process.env), {
|
||||
this._tryFindDebugPort(),
|
||||
this._shellEnvironmentService.getShellEnv()
|
||||
]).then(([pipeName, portNumber, processEnv]) => {
|
||||
const env = objects.mixin(processEnv, {
|
||||
VSCODE_AMD_ENTRYPOINT: 'vs/workbench/services/extensions/node/extensionHostProcess',
|
||||
VSCODE_PIPE_LOGGING: 'true',
|
||||
VSCODE_VERBOSE_LOGGING: true,
|
||||
@@ -206,6 +209,10 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
opts.execArgv.unshift('--prof');
|
||||
}
|
||||
|
||||
if (this._environmentService.args['max-memory']) {
|
||||
opts.execArgv.unshift(`--max-old-space-size=${this._environmentService.args['max-memory']}`);
|
||||
}
|
||||
|
||||
// On linux crash reporter needs to be started on child node processes explicitly
|
||||
if (platform.isLinux) {
|
||||
const crashReporterStartOptions: CrashReporterStartOptions = {
|
||||
|
||||
@@ -105,7 +105,7 @@ function _createExtHostProtocol(): Promise<PersistentProtocol> {
|
||||
let protocol: PersistentProtocol | null = null;
|
||||
|
||||
let timer = setTimeout(() => {
|
||||
reject(new Error('VSCODE_EXTHOST_IPC_SOCKET timeout'));
|
||||
onTerminate('VSCODE_EXTHOST_IPC_SOCKET timeout');
|
||||
}, 60000);
|
||||
|
||||
const reconnectionGraceTime = ProtocolConstants.ReconnectionGraceTime;
|
||||
|
||||
@@ -6,27 +6,15 @@
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as tls from 'tls';
|
||||
import * as nodeurl from 'url';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ProxyAgent } from 'vscode-proxy-agent';
|
||||
import { MainThreadTelemetryShape, IInitData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
interface ConnectionResult {
|
||||
proxy: string;
|
||||
connection: string;
|
||||
code: string;
|
||||
count: number;
|
||||
}
|
||||
import { LogLevel, createHttpPatch, ProxyResolveEvent, createProxyResolver, createTlsPatch, ProxySupportSetting } from 'vscode-proxy-agent';
|
||||
|
||||
export function connectProxyResolver(
|
||||
extHostWorkspace: IExtHostWorkspaceProvider,
|
||||
@@ -36,269 +24,59 @@ export function connectProxyResolver(
|
||||
mainThreadTelemetry: MainThreadTelemetryShape,
|
||||
initData: IInitData,
|
||||
) {
|
||||
const resolveProxy = setupProxyResolution(extHostWorkspace, configProvider, extHostLogService, mainThreadTelemetry, initData);
|
||||
const useHostProxy = initData.environment.useHostProxy;
|
||||
const doUseHostProxy = typeof useHostProxy === 'boolean' ? useHostProxy : !initData.remote.isRemote;
|
||||
const resolveProxy = createProxyResolver({
|
||||
resolveProxy: url => extHostWorkspace.resolveProxy(url),
|
||||
getHttpProxySetting: () => configProvider.getConfiguration('http').get('proxy'),
|
||||
log: (level, message, ...args) => {
|
||||
switch (level) {
|
||||
case LogLevel.Trace: extHostLogService.trace(message, ...args); break;
|
||||
case LogLevel.Debug: extHostLogService.debug(message, ...args); break;
|
||||
case LogLevel.Info: extHostLogService.info(message, ...args); break;
|
||||
case LogLevel.Warning: extHostLogService.warn(message, ...args); break;
|
||||
case LogLevel.Error: extHostLogService.error(message, ...args); break;
|
||||
case LogLevel.Critical: extHostLogService.critical(message, ...args); break;
|
||||
case LogLevel.Off: break;
|
||||
default: never(level, message, args); break;
|
||||
}
|
||||
function never(level: never, message: string, ...args: any[]) {
|
||||
extHostLogService.error('Unknown log level', level);
|
||||
extHostLogService.error(message, ...args);
|
||||
}
|
||||
},
|
||||
getLogLevel: () => extHostLogService.getLevel(),
|
||||
proxyResolveTelemetry: event => {
|
||||
type ResolveProxyClassification = {
|
||||
count: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
errorCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheSize: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheRolls: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
envCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
settingsCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
localhostCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
envNoProxyCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
results: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
};
|
||||
mainThreadTelemetry.$publicLog2<ProxyResolveEvent, ResolveProxyClassification>('resolveProxy', event);
|
||||
},
|
||||
useHostProxy: doUseHostProxy,
|
||||
env: process.env,
|
||||
});
|
||||
const lookup = createPatchedModules(configProvider, resolveProxy);
|
||||
return configureModuleLoading(extensionService, lookup);
|
||||
}
|
||||
|
||||
const maxCacheEntries = 5000; // Cache can grow twice that much due to 'oldCache'.
|
||||
|
||||
function setupProxyResolution(
|
||||
extHostWorkspace: IExtHostWorkspaceProvider,
|
||||
configProvider: ExtHostConfigProvider,
|
||||
extHostLogService: ILogService,
|
||||
mainThreadTelemetry: MainThreadTelemetryShape,
|
||||
initData: IInitData,
|
||||
) {
|
||||
const env = process.env;
|
||||
|
||||
let settingsProxy = proxyFromConfigURL(configProvider.getConfiguration('http')
|
||||
.get<string>('proxy'));
|
||||
configProvider.onDidChangeConfiguration(e => {
|
||||
settingsProxy = proxyFromConfigURL(configProvider.getConfiguration('http')
|
||||
.get<string>('proxy'));
|
||||
});
|
||||
let envProxy = proxyFromConfigURL(env.https_proxy || env.HTTPS_PROXY || env.http_proxy || env.HTTP_PROXY); // Not standardized.
|
||||
|
||||
let envNoProxy = noProxyFromEnv(env.no_proxy || env.NO_PROXY); // Not standardized.
|
||||
|
||||
let cacheRolls = 0;
|
||||
let oldCache = new Map<string, string>();
|
||||
let cache = new Map<string, string>();
|
||||
function getCacheKey(url: nodeurl.UrlWithStringQuery) {
|
||||
// Expecting proxies to usually be the same per scheme://host:port. Assuming that for performance.
|
||||
return nodeurl.format({ ...url, ...{ pathname: undefined, search: undefined, hash: undefined } });
|
||||
}
|
||||
function getCachedProxy(key: string) {
|
||||
let proxy = cache.get(key);
|
||||
if (proxy) {
|
||||
return proxy;
|
||||
}
|
||||
proxy = oldCache.get(key);
|
||||
if (proxy) {
|
||||
oldCache.delete(key);
|
||||
cacheProxy(key, proxy);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
function cacheProxy(key: string, proxy: string) {
|
||||
cache.set(key, proxy);
|
||||
if (cache.size >= maxCacheEntries) {
|
||||
oldCache = cache;
|
||||
cache = new Map();
|
||||
cacheRolls++;
|
||||
extHostLogService.trace('ProxyResolver#cacheProxy cacheRolls', cacheRolls);
|
||||
}
|
||||
}
|
||||
|
||||
let timeout: NodeJS.Timer | undefined;
|
||||
let count = 0;
|
||||
let duration = 0;
|
||||
let errorCount = 0;
|
||||
let cacheCount = 0;
|
||||
let envCount = 0;
|
||||
let settingsCount = 0;
|
||||
let localhostCount = 0;
|
||||
let envNoProxyCount = 0;
|
||||
let results: ConnectionResult[] = [];
|
||||
function logEvent() {
|
||||
timeout = undefined;
|
||||
type ResolveProxyClassification = {
|
||||
count: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
errorCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheSize: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
cacheRolls: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
envCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
settingsCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
localhostCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
envNoProxyCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true };
|
||||
results: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
};
|
||||
type ResolveProxyEvent = {
|
||||
count: number;
|
||||
duration: number;
|
||||
errorCount: number;
|
||||
cacheCount: number;
|
||||
cacheSize: number;
|
||||
cacheRolls: number;
|
||||
envCount: number;
|
||||
settingsCount: number;
|
||||
localhostCount: number;
|
||||
envNoProxyCount: number;
|
||||
results: ConnectionResult[];
|
||||
};
|
||||
mainThreadTelemetry.$publicLog2<ResolveProxyEvent, ResolveProxyClassification>('resolveProxy', { count, duration, errorCount, cacheCount, cacheSize: cache.size, cacheRolls, envCount, settingsCount, localhostCount, envNoProxyCount, results });
|
||||
count = duration = errorCount = cacheCount = envCount = settingsCount = localhostCount = envNoProxyCount = 0;
|
||||
results = [];
|
||||
}
|
||||
|
||||
function resolveProxy(flags: { useProxySettings: boolean, useSystemCertificates: boolean }, req: http.ClientRequest, opts: http.RequestOptions, url: string, callback: (proxy?: string) => void) {
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(logEvent, 10 * 60 * 1000);
|
||||
}
|
||||
|
||||
const useHostProxy = initData.environment.useHostProxy;
|
||||
const doUseHostProxy = typeof useHostProxy === 'boolean' ? useHostProxy : !initData.remote.isRemote;
|
||||
useSystemCertificates(extHostLogService, flags.useSystemCertificates, opts, () => {
|
||||
useProxySettings(doUseHostProxy, flags.useProxySettings, req, opts, url, callback);
|
||||
});
|
||||
}
|
||||
|
||||
function useProxySettings(useHostProxy: boolean, useProxySettings: boolean, req: http.ClientRequest, opts: http.RequestOptions, url: string, callback: (proxy?: string) => void) {
|
||||
|
||||
if (!useProxySettings) {
|
||||
callback('DIRECT');
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedUrl = nodeurl.parse(url); // Coming from Node's URL, sticking with that.
|
||||
|
||||
const hostname = parsedUrl.hostname;
|
||||
if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '::ffff:127.0.0.1') {
|
||||
localhostCount++;
|
||||
callback('DIRECT');
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy localhost', url, 'DIRECT');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof hostname === 'string' && envNoProxy(hostname, String(parsedUrl.port || (<any>opts.agent).defaultPort))) {
|
||||
envNoProxyCount++;
|
||||
callback('DIRECT');
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy envNoProxy', url, 'DIRECT');
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingsProxy) {
|
||||
settingsCount++;
|
||||
callback(settingsProxy);
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy settings', url, settingsProxy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (envProxy) {
|
||||
envCount++;
|
||||
callback(envProxy);
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy env', url, envProxy);
|
||||
return;
|
||||
}
|
||||
|
||||
const key = getCacheKey(parsedUrl);
|
||||
const proxy = getCachedProxy(key);
|
||||
if (proxy) {
|
||||
cacheCount++;
|
||||
collectResult(results, proxy, parsedUrl.protocol === 'https:' ? 'HTTPS' : 'HTTP', req);
|
||||
callback(proxy);
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy cached', url, proxy);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!useHostProxy) {
|
||||
callback('DIRECT');
|
||||
extHostLogService.trace('ProxyResolver#resolveProxy unconfigured', url, 'DIRECT');
|
||||
return;
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
extHostWorkspace.resolveProxy(url) // Use full URL to ensure it is an actually used one.
|
||||
.then(proxy => {
|
||||
if (proxy) {
|
||||
cacheProxy(key, proxy);
|
||||
collectResult(results, proxy, parsedUrl.protocol === 'https:' ? 'HTTPS' : 'HTTP', req);
|
||||
}
|
||||
callback(proxy);
|
||||
extHostLogService.debug('ProxyResolver#resolveProxy', url, proxy);
|
||||
}).then(() => {
|
||||
count++;
|
||||
duration = Date.now() - start + duration;
|
||||
}, err => {
|
||||
errorCount++;
|
||||
callback();
|
||||
extHostLogService.error('ProxyResolver#resolveProxy', toErrorMessage(err));
|
||||
});
|
||||
}
|
||||
|
||||
return resolveProxy;
|
||||
}
|
||||
|
||||
function collectResult(results: ConnectionResult[], resolveProxy: string, connection: string, req: http.ClientRequest) {
|
||||
const proxy = resolveProxy ? String(resolveProxy).trim().split(/\s+/, 1)[0] : 'EMPTY';
|
||||
req.on('response', res => {
|
||||
const code = `HTTP_${res.statusCode}`;
|
||||
const result = findOrCreateResult(results, proxy, connection, code);
|
||||
result.count++;
|
||||
});
|
||||
req.on('error', err => {
|
||||
const code = err && typeof (<any>err).code === 'string' && (<any>err).code || 'UNKNOWN_ERROR';
|
||||
const result = findOrCreateResult(results, proxy, connection, code);
|
||||
result.count++;
|
||||
});
|
||||
}
|
||||
|
||||
function findOrCreateResult(results: ConnectionResult[], proxy: string, connection: string, code: string): ConnectionResult {
|
||||
for (const result of results) {
|
||||
if (result.proxy === proxy && result.connection === connection && result.code === code) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const result = { proxy, connection, code, count: 0 };
|
||||
results.push(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function proxyFromConfigURL(configURL: string | undefined) {
|
||||
const url = (configURL || '').trim();
|
||||
const i = url.indexOf('://');
|
||||
if (i === -1) {
|
||||
return undefined;
|
||||
}
|
||||
const scheme = url.substr(0, i).toLowerCase();
|
||||
const proxy = url.substr(i + 3);
|
||||
if (scheme === 'http') {
|
||||
return 'PROXY ' + proxy;
|
||||
} else if (scheme === 'https') {
|
||||
return 'HTTPS ' + proxy;
|
||||
} else if (scheme === 'socks') {
|
||||
return 'SOCKS ' + proxy;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function noProxyFromEnv(envValue?: string) {
|
||||
const value = (envValue || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
|
||||
if (value === '*') {
|
||||
return () => true;
|
||||
}
|
||||
|
||||
const filters = value
|
||||
.split(',')
|
||||
.map(s => s.trim().split(':', 2))
|
||||
.map(([name, port]) => ({ name, port }))
|
||||
.filter(filter => !!filter.name)
|
||||
.map(({ name, port }) => {
|
||||
const domain = name[0] === '.' ? name : `.${name}`;
|
||||
return { domain, port };
|
||||
});
|
||||
if (!filters.length) {
|
||||
return () => false;
|
||||
}
|
||||
return (hostname: string, port: string) => filters.some(({ domain, port: filterPort }) => {
|
||||
return `.${hostname.toLowerCase()}`.endsWith(domain) && (!filterPort || port === filterPort);
|
||||
});
|
||||
}
|
||||
|
||||
function createPatchedModules(configProvider: ExtHostConfigProvider, resolveProxy: ReturnType<typeof setupProxyResolution>) {
|
||||
function createPatchedModules(configProvider: ExtHostConfigProvider, resolveProxy: ReturnType<typeof createProxyResolver>) {
|
||||
const proxySetting = {
|
||||
config: configProvider.getConfiguration('http')
|
||||
.get<string>('proxySupport') || 'off'
|
||||
.get<ProxySupportSetting>('proxySupport') || 'off'
|
||||
};
|
||||
configProvider.onDidChangeConfiguration(e => {
|
||||
proxySetting.config = configProvider.getConfiguration('http')
|
||||
.get<string>('proxySupport') || 'off';
|
||||
.get<ProxySupportSetting>('proxySupport') || 'off';
|
||||
});
|
||||
const certSetting = {
|
||||
config: !!configProvider.getConfiguration('http')
|
||||
@@ -311,111 +89,30 @@ function createPatchedModules(configProvider: ExtHostConfigProvider, resolveProx
|
||||
|
||||
return {
|
||||
http: {
|
||||
off: Object.assign({}, http, patches(http, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, http, patches(http, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, http, patches(http, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, http, patches(http, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(http, patches(http, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
off: Object.assign({}, http, createHttpPatch(http, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, http, createHttpPatch(http, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, http, createHttpPatch(http, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, http, createHttpPatch(http, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(http, createHttpPatch(http, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
} as Record<string, typeof http>,
|
||||
https: {
|
||||
off: Object.assign({}, https, patches(https, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, https, patches(https, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, https, patches(https, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, https, patches(https, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(https, patches(https, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
off: Object.assign({}, https, createHttpPatch(https, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, https, createHttpPatch(https, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, https, createHttpPatch(https, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, https, createHttpPatch(https, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(https, createHttpPatch(https, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
} as Record<string, typeof https>,
|
||||
tls: Object.assign(tls, tlsPatches(tls))
|
||||
tls: Object.assign(tls, createTlsPatch(tls))
|
||||
};
|
||||
}
|
||||
|
||||
function patches(originals: typeof http | typeof https, resolveProxy: ReturnType<typeof setupProxyResolution>, proxySetting: { config: string }, certSetting: { config: boolean }, onRequest: boolean) {
|
||||
return {
|
||||
get: patch(originals.get),
|
||||
request: patch(originals.request)
|
||||
};
|
||||
|
||||
function patch(original: typeof http.get) {
|
||||
function patched(url?: string | URL | null, options?: http.RequestOptions | null, callback?: (res: http.IncomingMessage) => void): http.ClientRequest {
|
||||
if (typeof url !== 'string' && !(url && (<any>url).searchParams)) {
|
||||
callback = <any>options;
|
||||
options = url;
|
||||
url = null;
|
||||
}
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
if (options.socketPath) {
|
||||
return original.apply(null, arguments as any);
|
||||
}
|
||||
|
||||
const originalAgent = options.agent;
|
||||
if (originalAgent === true) {
|
||||
throw new Error('Unexpected agent option: true');
|
||||
}
|
||||
const optionsPatched = originalAgent instanceof ProxyAgent;
|
||||
const config = onRequest && ((<any>options)._vscodeProxySupport || /* LS */ (<any>options)._vscodeSystemProxy) || proxySetting.config;
|
||||
const useProxySettings = !optionsPatched && (config === 'override' || config === 'on' && originalAgent === undefined);
|
||||
const useSystemCertificates = !optionsPatched && certSetting.config && originals === https && !(options as https.RequestOptions).ca;
|
||||
|
||||
if (useProxySettings || useSystemCertificates) {
|
||||
if (url) {
|
||||
const parsed = typeof url === 'string' ? new nodeurl.URL(url) : url;
|
||||
const urlOptions = {
|
||||
protocol: parsed.protocol,
|
||||
hostname: parsed.hostname.lastIndexOf('[', 0) === 0 ? parsed.hostname.slice(1, -1) : parsed.hostname,
|
||||
port: parsed.port,
|
||||
path: `${parsed.pathname}${parsed.search}`
|
||||
};
|
||||
if (parsed.username || parsed.password) {
|
||||
options.auth = `${parsed.username}:${parsed.password}`;
|
||||
}
|
||||
options = { ...urlOptions, ...options };
|
||||
} else {
|
||||
options = { ...options };
|
||||
}
|
||||
options.agent = new ProxyAgent({
|
||||
resolveProxy: resolveProxy.bind(undefined, { useProxySettings, useSystemCertificates }),
|
||||
defaultPort: originals === https ? 443 : 80,
|
||||
originalAgent
|
||||
});
|
||||
return original(options, callback);
|
||||
}
|
||||
|
||||
return original.apply(null, arguments as any);
|
||||
}
|
||||
return patched;
|
||||
}
|
||||
}
|
||||
|
||||
function tlsPatches(originals: typeof tls) {
|
||||
return {
|
||||
createSecureContext: patch(originals.createSecureContext)
|
||||
};
|
||||
|
||||
function patch(original: typeof tls.createSecureContext): typeof tls.createSecureContext {
|
||||
return function (details?: tls.SecureContextOptions): ReturnType<typeof tls.createSecureContext> {
|
||||
const context = original.apply(null, arguments as any);
|
||||
const certs = (details as any)._vscodeAdditionalCaCerts;
|
||||
if (certs) {
|
||||
for (const cert of certs) {
|
||||
context.context.addCACert(cert);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const modulesCache = new Map<IExtensionDescription | undefined, { http?: typeof http, https?: typeof https }>();
|
||||
function configureModuleLoading(extensionService: ExtHostExtensionService, lookup: ReturnType<typeof createPatchedModules>): Promise<void> {
|
||||
return extensionService.getExtensionPathIndex()
|
||||
.then(extensionPaths => {
|
||||
const node_module = <any>require.__$__nodeRequire('module');
|
||||
const original = node_module._load;
|
||||
node_module._load = function load(request: string, parent: any, isMain: any) {
|
||||
node_module._load = function load(request: string, parent: { filename: string; }, isMain: boolean) {
|
||||
if (request === 'tls') {
|
||||
return lookup.tls;
|
||||
}
|
||||
@@ -441,126 +138,3 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function useSystemCertificates(extHostLogService: ILogService, useSystemCertificates: boolean, opts: http.RequestOptions, callback: () => void) {
|
||||
if (useSystemCertificates) {
|
||||
getCaCertificates(extHostLogService)
|
||||
.then(caCertificates => {
|
||||
if (caCertificates) {
|
||||
if (caCertificates.append) {
|
||||
(opts as any)._vscodeAdditionalCaCerts = caCertificates.certs;
|
||||
} else {
|
||||
(opts as https.RequestOptions).ca = caCertificates.certs;
|
||||
}
|
||||
}
|
||||
callback();
|
||||
})
|
||||
.catch(err => {
|
||||
extHostLogService.error('ProxyResolver#useSystemCertificates', toErrorMessage(err));
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>;
|
||||
async function getCaCertificates(extHostLogService: ILogService) {
|
||||
if (!_caCertificates) {
|
||||
_caCertificates = readCaCertificates()
|
||||
.then(res => {
|
||||
extHostLogService.debug('ProxyResolver#getCaCertificates count', res && res.certs.length);
|
||||
return res && res.certs.length ? res : undefined;
|
||||
})
|
||||
.catch(err => {
|
||||
extHostLogService.error('ProxyResolver#getCaCertificates error', toErrorMessage(err));
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
return _caCertificates;
|
||||
}
|
||||
|
||||
async function readCaCertificates() {
|
||||
if (process.platform === 'win32') {
|
||||
return readWindowsCaCertificates();
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
return readMacCaCertificates();
|
||||
}
|
||||
if (process.platform === 'linux') {
|
||||
return readLinuxCaCertificates();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function readWindowsCaCertificates() {
|
||||
// @ts-ignore Windows only
|
||||
const winCA = await import('vscode-windows-ca-certs');
|
||||
|
||||
let ders: any[] = [];
|
||||
const store = new winCA.Crypt32();
|
||||
try {
|
||||
let der: any;
|
||||
while (der = store.next()) {
|
||||
ders.push(der);
|
||||
}
|
||||
} finally {
|
||||
store.done();
|
||||
}
|
||||
|
||||
const certs = new Set(ders.map(derToPem));
|
||||
return {
|
||||
certs: Array.from(certs),
|
||||
append: true
|
||||
};
|
||||
}
|
||||
|
||||
async function readMacCaCertificates() {
|
||||
const stdout = await new Promise<string>((resolve, reject) => {
|
||||
const child = cp.spawn('/usr/bin/security', ['find-certificate', '-a', '-p']);
|
||||
const stdout: string[] = [];
|
||||
child.stdout.setEncoding('utf8');
|
||||
child.stdout.on('data', str => stdout.push(str));
|
||||
child.on('error', reject);
|
||||
child.on('exit', code => code ? reject(code) : resolve(stdout.join('')));
|
||||
});
|
||||
const certs = new Set(stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g)
|
||||
.filter(pem => !!pem.length));
|
||||
return {
|
||||
certs: Array.from(certs),
|
||||
append: true
|
||||
};
|
||||
}
|
||||
|
||||
const linuxCaCertificatePaths = [
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
'/etc/ssl/certs/ca-bundle.crt',
|
||||
];
|
||||
|
||||
async function readLinuxCaCertificates() {
|
||||
for (const certPath of linuxCaCertificatePaths) {
|
||||
try {
|
||||
const content = await fs.promises.readFile(certPath, { encoding: 'utf8' });
|
||||
const certs = new Set(content.split(/(?=-----BEGIN CERTIFICATE-----)/g)
|
||||
.filter(pem => !!pem.length));
|
||||
return {
|
||||
certs: Array.from(certs),
|
||||
append: false
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function derToPem(blob: Buffer) {
|
||||
const lines = ['-----BEGIN CERTIFICATE-----'];
|
||||
const der = blob.toString('base64');
|
||||
for (let i = 0; i < der.length; i += 64) {
|
||||
lines.push(der.substr(i, 64));
|
||||
}
|
||||
lines.push('-----END CERTIFICATE-----', '');
|
||||
return lines.join(os.EOL);
|
||||
}
|
||||
|
||||
@@ -4,85 +4,86 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
|
||||
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
|
||||
suite('BrowserExtensionService', () => {
|
||||
test('pickRunningLocation', () => {
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation([], true, true), ExtensionRunningLocation.None);
|
||||
assert(true); // {{SQL CARBON EDIT}} Workaround for error loading test modules when there's no imports in the file
|
||||
/* {{SQL CARBON EDIT}} Disable broken tests for unused service
|
||||
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(['ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
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(['workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, true), ExtensionRunningLocation.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(['web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
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(['ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
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(['web', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
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(['ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, false, ExtensionRunningPreference.None), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true, ExtensionRunningPreference.None), ExtensionRunningLocation.Remote);
|
||||
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.Remote);
|
||||
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', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
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.Remote);
|
||||
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(['web', 'ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
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.Remote);
|
||||
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.Remote);
|
||||
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(['workspace', 'ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepStrictEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
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);
|
||||
*/
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { TestProductService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
|
||||
suite('ExtensionManifestPropertiesService - ExtensionKind', () => {
|
||||
|
||||
function check(manifest: Partial<IExtensionManifest>, expected: ExtensionKind[]): void {
|
||||
const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService());
|
||||
assert.deepStrictEqual(extensionManifestPropertiesService.deduceExtensionKind(<IExtensionManifest>manifest), expected);
|
||||
}
|
||||
|
||||
test('declarative with extension dependencies => workspace', () => {
|
||||
check({ extensionDependencies: ['ext1'] }, ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative extension pack => workspace', () => {
|
||||
check({ extensionPack: ['ext1', 'ext2'] }, ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative with unknown contribution point => workspace', () => {
|
||||
check({ contributes: <any>{ 'unknownPoint': { something: true } } }, ['workspace']);
|
||||
});
|
||||
|
||||
test('simple declarative => ui, workspace, web', () => {
|
||||
check({}, ['ui', 'workspace', 'web']);
|
||||
});
|
||||
|
||||
test('only browser => web', () => {
|
||||
check({ browser: 'main.browser.js' }, ['web']);
|
||||
});
|
||||
|
||||
test('only main => workspace', () => {
|
||||
check({ main: 'main.js' }, ['workspace']);
|
||||
});
|
||||
|
||||
test('main and browser => workspace, web', () => {
|
||||
check({ main: 'main.js', browser: 'main.browser.js' }, ['workspace', 'web']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Workspace Trust is disabled in web at the moment
|
||||
if (!isWeb) {
|
||||
suite('ExtensionManifestPropertiesService - ExtensionUntrustedWorkpaceSupportType', () => {
|
||||
let testObject: ExtensionManifestPropertiesService;
|
||||
let instantiationService: TestInstantiationService;
|
||||
let testConfigurationService: TestConfigurationService;
|
||||
|
||||
setup(async () => {
|
||||
instantiationService = new TestInstantiationService();
|
||||
|
||||
testConfigurationService = new TestConfigurationService();
|
||||
instantiationService.stub(IConfigurationService, testConfigurationService);
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { enabled: true } } });
|
||||
});
|
||||
|
||||
teardown(() => testObject.dispose());
|
||||
|
||||
function assertUntrustedWorkspaceSupport(extensionMaifest: IExtensionManifest, expected: ExtensionUntrustedWorkpaceSupportType): void {
|
||||
testObject = instantiationService.createInstance(ExtensionManifestPropertiesService);
|
||||
const untrustedWorkspaceSupport = testObject.getExtensionUntrustedWorkspaceSupportType(extensionMaifest);
|
||||
|
||||
assert.strictEqual(untrustedWorkspaceSupport, expected);
|
||||
}
|
||||
|
||||
function getExtensionManifest(properties: any = {}): IExtensionManifest {
|
||||
return Object.create({ name: 'a', publisher: 'pub', version: '1.0.0', ...properties }) as IExtensionManifest;
|
||||
}
|
||||
|
||||
test('test extension workspace trust request when main entry point is missing', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
const extensionMaifest = getExtensionManifest();
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when workspace trust is disabled', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { enabled: false } } });
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionUntrustedSupport: { 'pub.a': { supported: true } } } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override for the version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', { workspace: { trust: { extensionUntrustedSupport: { 'pub.a': { supported: true, version: '1.0.0' } } } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override for a different version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
await testConfigurationService.setUserConfiguration('security', {
|
||||
workspace: {
|
||||
trust: {
|
||||
enabled: true,
|
||||
extensionUntrustedSupport: { 'pub.a': { supported: true, version: '2.0.0' } }
|
||||
}
|
||||
}
|
||||
});
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when default exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: true } } });
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: 'limited' } } });
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when no value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { deduceExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IExtensionManifest, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
suite('ExtensionKind', () => {
|
||||
|
||||
function check(manifest: Partial<IExtensionManifest>, expected: ExtensionKind[]): void {
|
||||
assert.deepStrictEqual(deduceExtensionKind(<IExtensionManifest>manifest), expected);
|
||||
}
|
||||
|
||||
test('declarative with extension dependencies => workspace', () => {
|
||||
check({ extensionDependencies: ['ext1'] }, ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative extension pack => workspace', () => {
|
||||
check({ extensionPack: ['ext1', 'ext2'] }, ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative with unknown contribution point => workspace', () => {
|
||||
check({ contributes: <any>{ 'unknownPoint': { something: true } } }, ['workspace']);
|
||||
});
|
||||
|
||||
test('simple declarative => ui, workspace, web', () => {
|
||||
check({}, ['ui', 'workspace', 'web']);
|
||||
});
|
||||
|
||||
test('only browser => web', () => {
|
||||
check({ browser: 'main.browser.js' }, ['web']);
|
||||
});
|
||||
|
||||
test('only main => workspace', () => {
|
||||
check({ main: 'main.js' }, ['workspace']);
|
||||
});
|
||||
|
||||
test('main and browser => workspace, web', () => {
|
||||
check({ main: 'main.js', browser: 'main.browser.js' }, ['workspace', 'web']);
|
||||
});
|
||||
});
|
||||
@@ -1,88 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
|
||||
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
|
||||
suite('BrowserExtensionService', () => {
|
||||
test('pickRunningLocation', () => {
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], true, true), ExtensionRunningLocation.None);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
});
|
||||
});
|
||||
@@ -5,24 +5,69 @@
|
||||
|
||||
(function () {
|
||||
|
||||
let MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
let monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../../../';
|
||||
const MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
const monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../../../';
|
||||
|
||||
const trustedTypesPolicy = self.trustedTypes?.createPolicy('amdLoader', { createScriptURL: value => value });
|
||||
const trustedTypesPolicy = (
|
||||
typeof self.trustedTypes?.createPolicy === 'function'
|
||||
? self.trustedTypes?.createPolicy('amdLoader', {
|
||||
createScriptURL: value => value,
|
||||
createScript: (_, ...args: string[]) => {
|
||||
// workaround a chrome issue not allowing to create new functions
|
||||
// see https://github.com/w3c/webappsec-trusted-types/wiki/Trusted-Types-for-function-constructor
|
||||
const fnArgs = args.slice(0, -1).join(',');
|
||||
const fnBody = args.pop()!.toString();
|
||||
const body = `(function anonymous(${fnArgs}) {\n${fnBody}\n})`;
|
||||
return body;
|
||||
}
|
||||
})
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (typeof (<any>self).define !== 'function' || !(<any>self).define.amd) {
|
||||
let loaderSrc: string | TrustedScriptURL = monacoBaseUrl + 'vs/loader.js';
|
||||
if (trustedTypesPolicy) {
|
||||
loaderSrc = trustedTypesPolicy.createScriptURL(loaderSrc);
|
||||
}
|
||||
importScripts(loaderSrc as string);
|
||||
function loadAMDLoader() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (typeof (<any>self).define === 'function' && (<any>self).define.amd) {
|
||||
return resolve();
|
||||
}
|
||||
const loaderSrc: string | TrustedScriptURL = monacoBaseUrl + 'vs/loader.js';
|
||||
|
||||
const isCrossOrigin = (/^((http:)|(https:)|(file:))/.test(loaderSrc) && loaderSrc.substring(0, self.origin.length) !== self.origin);
|
||||
if (!isCrossOrigin) {
|
||||
// use `fetch` if possible because `importScripts`
|
||||
// is synchronous and can lead to deadlocks on Safari
|
||||
fetch(loaderSrc).then((response) => {
|
||||
if (response.status !== 200) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
return response.text();
|
||||
}).then((text) => {
|
||||
text = `${text}\n//# sourceURL=${loaderSrc}`;
|
||||
const func = (
|
||||
trustedTypesPolicy
|
||||
? self.eval(trustedTypesPolicy.createScript('', text) as unknown as string)
|
||||
: new Function(text)
|
||||
);
|
||||
func.call(self);
|
||||
resolve();
|
||||
}).then(undefined, reject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (trustedTypesPolicy) {
|
||||
importScripts(trustedTypesPolicy.createScriptURL(loaderSrc) as unknown as string);
|
||||
} else {
|
||||
importScripts(loaderSrc as string);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
require.config({
|
||||
baseUrl: monacoBaseUrl,
|
||||
catchError: true,
|
||||
trustedTypesPolicy
|
||||
});
|
||||
|
||||
require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
|
||||
loadAMDLoader().then(() => {
|
||||
require.config({
|
||||
baseUrl: monacoBaseUrl,
|
||||
catchError: true,
|
||||
trustedTypesPolicy
|
||||
});
|
||||
require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
|
||||
}).then(undefined, (err) => console.error(err));
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user