mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-14 03:58:33 -05:00
VS Code merge to df8fe74bd55313de0dd2303bc47a4aab0ca56b0e (#17979)
* Merge from vscode 504f934659740e9d41501cad9f162b54d7745ad9 * delete unused folders * distro * Bump build node version * update chokidar * FIx hygiene errors * distro * Fix extension lint issues * Remove strict-vscode * Add copyright header exemptions * Bump vscode-extension-telemetry to fix webpacking issue with zone.js * distro * Fix failing tests (revert marked.js back to current one until we decide to update) * Skip searchmodel test * Fix mac build * temp debug script loading * Try disabling coverage * log error too * Revert "log error too" This reverts commit af0183e5d4ab458fdf44b88fbfab9908d090526f. * Revert "temp debug script loading" This reverts commit 3d687d541c76db2c5b55626c78ae448d3c25089c. * Add comments explaining coverage disabling * Fix ansi_up loading issue * Merge latest from ads * Use newer option * Fix compile * add debug logging warn * Always log stack * log more * undo debug * Update to use correct base path (+cleanup) * distro * fix compile errors * Remove strict-vscode * Fix sql editors not showing * Show db dropdown input & fix styling * Fix more info in gallery * Fix gallery asset requests * Delete unused workflow * Fix tapable resolutions for smoke test compile error * Fix smoke compile * Disable crash reporting * Disable interactive 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 } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionService, IExtensionHost, toExtensionDescription, ExtensionRunningLocation } 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, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocationClassifier, ExtensionRunningPreference } 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';
|
||||
@@ -28,6 +28,7 @@ import { IExtensionManagementService } from 'vs/platform/extensionManagement/com
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
import { IAutomatedWindow } from 'vs/platform/log/browser/log';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
@@ -47,7 +48,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IExtensionManifestPropertiesService extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
@IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService,
|
||||
@@ -67,7 +68,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
extensionManifestPropertiesService
|
||||
extensionManifestPropertiesService,
|
||||
webExtensionsScannerService
|
||||
);
|
||||
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
@@ -91,9 +93,9 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
|
||||
}
|
||||
|
||||
const scannedExtension = await this._webExtensionsScannerService.scanAndTranslateSingleExtension(extension.location, extension.type);
|
||||
const scannedExtension = await this._webExtensionsScannerService.scanExistingExtension(extension.location, extension.type);
|
||||
if (scannedExtension) {
|
||||
return parseScannedExtension(scannedExtension);
|
||||
return toExtensionDescription(scannedExtension);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -166,7 +168,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider());
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, false, this._createLocalExtensionHostDataProvider());
|
||||
result.push(webWorkerExtHost);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
@@ -181,7 +183,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
protected async _scanAndHandleExtensions(): Promise<void> {
|
||||
// fetch the remote environment
|
||||
let [localExtensions, remoteEnv, remoteExtensions] = await Promise.all([
|
||||
this._webExtensionsScannerService.scanAndTranslateExtensions().then(extensions => extensions.map(parseScannedExtension)),
|
||||
this._scanWebExtensions(),
|
||||
this._remoteAgentService.getEnvironment(),
|
||||
this._remoteAgentService.scanExtensions()
|
||||
]);
|
||||
@@ -220,10 +222,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
// Dispose everything associated with the extension host
|
||||
this.stopExtensionHosts();
|
||||
|
||||
// We log the exit code to the console. Do NOT remove this
|
||||
// code as the automated integration tests in browser rely
|
||||
// on this message to exit properly.
|
||||
console.log(`vscode:exit ${code}`);
|
||||
const automatedWindow = window as unknown as IAutomatedWindow;
|
||||
if (typeof automatedWindow.codeAutomationExit === 'function') {
|
||||
automatedWindow.codeAutomationExit(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
}
|
||||
|
||||
// Extension is disabled. Enable the extension and reload the window to handle.
|
||||
else {
|
||||
else if (this.extensionEnablementService.canChangeEnablement(extension)) {
|
||||
const result = await this.dialogService.confirm({
|
||||
message: localize('enableAndHandle', "Extension '{0}' is disabled. Would you like to enable the extension and reload the window to open the URL?", extension.manifest.displayName || extension.manifest.name),
|
||||
detail: `${extension.manifest.displayName || extension.manifest.name} (${extensionIdentifier.id}) wants to open a URL:\n\n${uri.toString()}`,
|
||||
@@ -335,7 +335,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
}
|
||||
|
||||
private getConfirmedTrustedExtensionIdsFromConfiguration(): Array<string> {
|
||||
const trustedExtensionIds = this.configurationService.getValue<Array<string>>(USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY);
|
||||
const trustedExtensionIds = this.configurationService.getValue(USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY);
|
||||
|
||||
if (!Array.isArray(trustedExtensionIds)) {
|
||||
return [];
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { getWorkerBootstrapUrl } from 'vs/base/worker/defaultWorkerFactory';
|
||||
import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { toDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
@@ -28,7 +28,6 @@ import { localize } from 'vs/nls';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { canceled, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
import { NewWorkerMessage, TerminateWorkerMessage } from 'vs/workbench/services/extensions/common/polyfillNestedWorker.protocol';
|
||||
|
||||
@@ -41,8 +40,6 @@ export interface IWebWorkerExtensionHostDataProvider {
|
||||
getInitData(): Promise<IWebWorkerExtensionHostInitData>;
|
||||
}
|
||||
|
||||
const ttPolicy = window.trustedTypes?.createPolicy('webWorkerExtensionHost', { createScriptURL: value => value });
|
||||
|
||||
const ttPolicyNestedWorker = window.trustedTypes?.createPolicy('webNestedWorkerExtensionHost', {
|
||||
createScriptURL(value) {
|
||||
if (value.startsWith('blob:')) {
|
||||
@@ -56,6 +53,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalWebWorker;
|
||||
public readonly remoteAuthority = null;
|
||||
public readonly lazyStart: boolean;
|
||||
|
||||
private readonly _onDidExit = this._register(new Emitter<[number, string | null]>());
|
||||
public readonly onExit: Event<[number, string | null]> = this._onDidExit.event;
|
||||
@@ -68,6 +66,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
private readonly _extensionHostLogFile: URI;
|
||||
|
||||
constructor(
|
||||
lazyStart: boolean,
|
||||
private readonly _initDataProvider: IWebWorkerExtensionHostDataProvider,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@@ -78,6 +77,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
@ILayoutService private readonly _layoutService: ILayoutService,
|
||||
) {
|
||||
super();
|
||||
this.lazyStart = lazyStart;
|
||||
this._isTerminating = false;
|
||||
this._protocolPromise = null;
|
||||
this._protocol = null;
|
||||
@@ -86,11 +86,35 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
}
|
||||
|
||||
private _webWorkerExtensionHostIframeSrc(): string | null {
|
||||
const suffix = this._environmentService.debugExtensionHost && this._environmentService.debugRenderer ? '?debugged=1' : '?';
|
||||
if (this._environmentService.options && this._environmentService.options.webWorkerExtensionHostIframeSrc) {
|
||||
return this._environmentService.options.webWorkerExtensionHostIframeSrc;
|
||||
return this._environmentService.options.webWorkerExtensionHostIframeSrc + suffix;
|
||||
}
|
||||
|
||||
const forceHTTPS = (location.protocol === 'https:');
|
||||
|
||||
if (this._environmentService.options && this._environmentService.options.__uniqueWebWorkerExtensionHostOrigin) {
|
||||
const webEndpointUrlTemplate = this._productService.webEndpointUrlTemplate;
|
||||
const commit = this._productService.commit;
|
||||
const quality = this._productService.quality;
|
||||
if (webEndpointUrlTemplate && commit && quality) {
|
||||
const baseUrl = (
|
||||
webEndpointUrlTemplate
|
||||
.replace('{{uuid}}', generateUuid())
|
||||
.replace('{{commit}}', commit)
|
||||
.replace('{{quality}}', quality)
|
||||
);
|
||||
const base = (
|
||||
forceHTTPS
|
||||
? `${baseUrl}/out/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html`
|
||||
: `${baseUrl}/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
|
||||
);
|
||||
|
||||
return base + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._productService.webEndpointUrl) {
|
||||
const forceHTTPS = (location.protocol === 'https:');
|
||||
let baseUrl = this._productService.webEndpointUrl;
|
||||
if (this._productService.quality) {
|
||||
baseUrl += `/${this._productService.quality}`;
|
||||
@@ -98,11 +122,13 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
if (this._productService.commit) {
|
||||
baseUrl += `/${this._productService.commit}`;
|
||||
}
|
||||
return (
|
||||
const base = (
|
||||
forceHTTPS
|
||||
? `${baseUrl}/out/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html`
|
||||
: `${baseUrl}/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
|
||||
);
|
||||
|
||||
return base + suffix;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -134,7 +160,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
iframe.style.display = 'none';
|
||||
|
||||
const vscodeWebWorkerExtHostId = generateUuid();
|
||||
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}?vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
|
||||
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}&vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
|
||||
|
||||
const barrier = new Barrier();
|
||||
let port!: MessagePort;
|
||||
@@ -219,51 +245,58 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
|
||||
private async _startOutsideIframe(): Promise<IMessagePassingProtocol> {
|
||||
const emitter = new Emitter<VSBuffer>();
|
||||
|
||||
const url = getWorkerBootstrapUrl(FileAccess.asBrowserUri('../worker/extensionHostWorkerMain.js', require).toString(true), 'WorkerExtensionHost');
|
||||
const worker = new Worker(ttPolicy?.createScriptURL(url) as unknown as string ?? url, { name: 'WorkerExtensionHost' });
|
||||
|
||||
const barrier = new Barrier();
|
||||
let port!: MessagePort;
|
||||
|
||||
const nestedWorker = new Map<string, Worker>();
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
const name = this._environmentService.debugRenderer && this._environmentService.debugExtensionHost ? 'DebugWorkerExtensionHost' : 'WorkerExtensionHost';
|
||||
const worker = new DefaultWorkerFactory(name).create(
|
||||
'vs/workbench/services/extensions/worker/extensionHostWorker',
|
||||
(data: MessagePort | NewWorkerMessage | TerminateWorkerMessage | any) => {
|
||||
|
||||
const data: MessagePort | NewWorkerMessage | TerminateWorkerMessage = event.data;
|
||||
if (data instanceof MessagePort) {
|
||||
// receiving a message port which is used to communicate
|
||||
// with the web worker extension host
|
||||
if (barrier.isOpen()) {
|
||||
console.warn('UNEXPECTED message', data);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'received a message port AFTER opening the barrier']);
|
||||
return;
|
||||
}
|
||||
port = data;
|
||||
barrier.open();
|
||||
|
||||
if (data instanceof MessagePort) {
|
||||
// receiving a message port which is used to communicate
|
||||
// with the web worker extension host
|
||||
if (barrier.isOpen()) {
|
||||
console.warn('UNEXPECTED message', event);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'received a message port AFTER opening the barrier']);
|
||||
return;
|
||||
|
||||
} else if (data?.type === '_newWorker') {
|
||||
// receiving a message to create a new nested/child worker
|
||||
const worker = new Worker((ttPolicyNestedWorker?.createScriptURL(data.url) ?? data.url) as string, data.options);
|
||||
worker.postMessage(data.port, [data.port]);
|
||||
worker.onerror = console.error.bind(console);
|
||||
nestedWorker.set(data.id, worker);
|
||||
|
||||
} else if (data?.type === '_terminateWorker') {
|
||||
// receiving a message to terminate nested/child worker
|
||||
if (nestedWorker.has(data.id)) {
|
||||
nestedWorker.get(data.id)!.terminate();
|
||||
nestedWorker.delete(data.id);
|
||||
}
|
||||
|
||||
} else {
|
||||
// all other messages are an error
|
||||
console.warn('UNEXPECTED message', data);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'UNEXPECTED message']);
|
||||
}
|
||||
port = data;
|
||||
barrier.open();
|
||||
},
|
||||
(event: any) => {
|
||||
console.error(event.message, event.error);
|
||||
|
||||
|
||||
} else if (data?.type === '_newWorker') {
|
||||
// receiving a message to create a new nested/child worker
|
||||
const worker = new Worker((ttPolicyNestedWorker?.createScriptURL(data.url) ?? data.url) as string, data.options);
|
||||
worker.postMessage(data.port, [data.port]);
|
||||
worker.onerror = console.error.bind(console);
|
||||
nestedWorker.set(data.id, worker);
|
||||
|
||||
} else if (data?.type === '_terminateWorker') {
|
||||
// receiving a message to terminate nested/child worker
|
||||
if (nestedWorker.has(data.id)) {
|
||||
nestedWorker.get(data.id)!.terminate();
|
||||
nestedWorker.delete(data.id);
|
||||
if (!barrier.isOpen()) {
|
||||
// Only terminate the web worker extension host when an error occurs during handshake
|
||||
// and setup. All other errors can be normal uncaught exceptions
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, event.message || event.error]);
|
||||
}
|
||||
|
||||
} else {
|
||||
// all other messages are an error
|
||||
console.warn('UNEXPECTED message', event);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'UNEXPECTED message']);
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
// await MessagePort and use it to directly communicate
|
||||
// with the worker extension host
|
||||
@@ -280,14 +313,10 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
emitter.fire(VSBuffer.wrap(new Uint8Array(data, 0, data.byteLength)));
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
console.error(event.message, event.error);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, event.message || event.error]);
|
||||
};
|
||||
|
||||
// keep for cleanup
|
||||
this._register(emitter);
|
||||
this._register(toDisposable(() => worker.terminate()));
|
||||
this._register(worker);
|
||||
|
||||
const protocol: IMessagePassingProtocol = {
|
||||
onMessage: emitter.event,
|
||||
@@ -355,6 +384,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug: this._environmentService.debugRenderer,
|
||||
appName: this._productService.nameLong,
|
||||
embedderIdentifier: this._productService.embedderIdentifier || 'web',
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
|
||||
@@ -11,17 +11,16 @@ import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'
|
||||
import * as perf from 'vs/base/common/performance';
|
||||
import { isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { IWebExtensionsScannerService, IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind, toExtensionDescription, ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind, IExtensionContributions } from 'vs/platform/extensions/common/extensions';
|
||||
import { createExtensionHostManager, IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtensionDescription, 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';
|
||||
@@ -33,21 +32,12 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
|
||||
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
|
||||
export function parseScannedExtension(extension: ITranslatedScannedExtension): IExtensionDescription {
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: extension.isUnderDevelopment,
|
||||
extensionLocation: extension.location,
|
||||
...extension.packageJSON,
|
||||
};
|
||||
}
|
||||
|
||||
class DeltaExtensionsQueueItem {
|
||||
constructor(
|
||||
public readonly toAdd: IExtension[],
|
||||
@@ -55,13 +45,6 @@ class DeltaExtensionsQueueItem {
|
||||
) { }
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningPreference {
|
||||
None,
|
||||
Local,
|
||||
@@ -167,7 +150,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
protected _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
|
||||
// --- Members used per extension host process
|
||||
protected _extensionHostManagers: ExtensionHostManager[];
|
||||
protected _extensionHostManagers: IExtensionHostManager[];
|
||||
protected _extensionHostActiveExtensions: Map<string, ExtensionIdentifier>;
|
||||
private _extensionHostActivationTimes: Map<string, ActivationTimes>;
|
||||
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
|
||||
@@ -185,6 +168,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IConfigurationService protected readonly _configurationService: IConfigurationService,
|
||||
@IExtensionManifestPropertiesService protected readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
@IWebExtensionsScannerService protected readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -230,13 +214,16 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
|
||||
if (event.local) {
|
||||
if (this._safeInvokeIsEnabled(event.local)) {
|
||||
// an extension has been installed
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
|
||||
this._register(this._extensionManagementService.onDidInstallExtensions((result) => {
|
||||
const extensions: IExtension[] = [];
|
||||
for (const { local } of result) {
|
||||
if (local && this._safeInvokeIsEnabled(local)) {
|
||||
extensions.push(local);
|
||||
}
|
||||
}
|
||||
if (extensions.length) {
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(extensions, []));
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
|
||||
@@ -255,7 +242,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
return this._extensionManifestPropertiesService.getExtensionKind(extensionDescription);
|
||||
}
|
||||
|
||||
protected _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
|
||||
protected _getExtensionHostManager(kind: ExtensionHostKind): IExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
return extensionHostManager;
|
||||
@@ -535,7 +522,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onExtensionHostExit(exitCode);
|
||||
}
|
||||
|
||||
private findTestExtensionHost(testLocation: URI): ExtensionHostManager | undefined | null {
|
||||
private findTestExtensionHost(testLocation: URI): IExtensionHostManager | undefined | null {
|
||||
let extensionHostKind: ExtensionHostKind | undefined;
|
||||
|
||||
for (const extension of this._registry.getAllExtensionDescriptions()) {
|
||||
@@ -599,14 +586,14 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
private _startExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): void {
|
||||
const extensionHosts = this._createExtensionHosts(isInitialStart);
|
||||
extensionHosts.forEach((extensionHost) => {
|
||||
const processManager = this._instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
|
||||
const processManager: IExtensionHostManager = createExtensionHostManager(this._instantiationService, extensionHost, isInitialStart, initialActivationEvents);
|
||||
processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal));
|
||||
processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); });
|
||||
this._extensionHostManagers.push(processManager);
|
||||
});
|
||||
}
|
||||
|
||||
private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
private _onExtensionHostCrashOrExit(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
|
||||
|
||||
// Unexpected termination
|
||||
if (!this._isExtensionDevHost) {
|
||||
@@ -617,7 +604,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onExtensionHostExit(code);
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
protected _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
|
||||
console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal);
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
|
||||
this.stopExtensionHosts();
|
||||
@@ -737,6 +724,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
messages: this._extensionsMessages.get(extensionKey) || [],
|
||||
activationTimes: this._extensionHostActivationTimes.get(extensionKey),
|
||||
runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [],
|
||||
runningLocation: this._runningLocation.get(extensionKey) || ExtensionRunningLocation.None,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -771,7 +759,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._checkEnableProposedApi(extensions);
|
||||
|
||||
// keep only enabled extensions
|
||||
return extensions.filter(extension => this._isEnabled(extension, ignoreWorkspaceTrust));
|
||||
return this._filterEnabledExtensions(extensions, ignoreWorkspaceTrust);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -779,30 +767,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
* @argument ignoreWorkspaceTrust Do not take workspace trust into account.
|
||||
*/
|
||||
protected _isEnabled(extension: IExtensionDescription, ignoreWorkspaceTrust: boolean): boolean {
|
||||
if (extension.isUnderDevelopment) {
|
||||
// Never disable extensions under development
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) {
|
||||
// Check if this is the better merge extension which was migrated to a built-in extension
|
||||
return false;
|
||||
}
|
||||
|
||||
const ext = toExtension(extension);
|
||||
|
||||
const isEnabled = this._safeInvokeIsEnabled(ext);
|
||||
if (isEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ignoreWorkspaceTrust && this._safeInvokeIsDisabledByWorkspaceTrust(ext)) {
|
||||
// This extension is disabled, but the reason for it being disabled
|
||||
// is workspace trust, so we will consider it enabled
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this._filterEnabledExtensions([extension], ignoreWorkspaceTrust).includes(extension);
|
||||
}
|
||||
|
||||
protected _safeInvokeIsEnabled(extension: IExtension): boolean {
|
||||
@@ -813,12 +778,27 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
}
|
||||
}
|
||||
|
||||
protected _safeInvokeIsDisabledByWorkspaceTrust(extension: IExtension): boolean {
|
||||
try {
|
||||
return this._extensionEnablementService.isDisabledByWorkspaceTrust(extension);
|
||||
} catch (err) {
|
||||
return false;
|
||||
private _filterEnabledExtensions(extensions: IExtensionDescription[], ignoreWorkspaceTrust: boolean): IExtensionDescription[] {
|
||||
const enabledExtensions: IExtensionDescription[] = [], extensionsToCheck: IExtensionDescription[] = [], mappedExtensions: IExtension[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (extension.isUnderDevelopment) {
|
||||
// Never disable extensions under development
|
||||
enabledExtensions.push(extension);
|
||||
}
|
||||
else {
|
||||
extensionsToCheck.push(extension);
|
||||
mappedExtensions.push(toExtension(extension));
|
||||
}
|
||||
}
|
||||
|
||||
const enablementStates = this._extensionEnablementService.getEnablementStates(mappedExtensions, ignoreWorkspaceTrust ? { trusted: true } : undefined);
|
||||
for (let index = 0; index < enablementStates.length; index++) {
|
||||
if (this._extensionEnablementService.isEnabledEnablementState(enablementStates[index])) {
|
||||
enabledExtensions.push(extensionsToCheck[index]);
|
||||
}
|
||||
}
|
||||
|
||||
return enabledExtensions;
|
||||
}
|
||||
|
||||
protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void {
|
||||
@@ -916,6 +896,16 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
//#region Called by extension host
|
||||
|
||||
protected createLogger(): Logger {
|
||||
return new Logger((severity, source, message) => {
|
||||
if (this._isDev && source) {
|
||||
this._logOrShowMessage(severity, `[${source}]: ${message}`);
|
||||
} else {
|
||||
this._logOrShowMessage(severity, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected _logOrShowMessage(severity: Severity, msg: string): void {
|
||||
if (this._isDev) {
|
||||
this._showMessageToUser(severity, msg);
|
||||
@@ -946,7 +936,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
public _onDidActivateExtensionError(extensionId: ExtensionIdentifier, error: Error): void {
|
||||
type ExtensionActivationErrorClassification = {
|
||||
extensionId: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
error: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' };
|
||||
error: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' };
|
||||
};
|
||||
type ExtensionActivationErrorEvent = {
|
||||
extensionId: string;
|
||||
@@ -967,6 +957,21 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
this._onDidChangeExtensionsStatus.fire([extensionId]);
|
||||
}
|
||||
|
||||
protected async _scanWebExtensions(): Promise<IExtensionDescription[]> {
|
||||
const log = this.createLogger();
|
||||
const system: IExtensionDescription[] = [], user: IExtensionDescription[] = [], development: IExtensionDescription[] = [];
|
||||
try {
|
||||
await Promise.all([
|
||||
this._webExtensionsScannerService.scanSystemExtensions().then(extensions => system.push(...extensions.map(e => toExtensionDescription(e)))),
|
||||
this._webExtensionsScannerService.scanUserExtensions().then(extensions => user.push(...extensions.map(e => toExtensionDescription(e)))),
|
||||
this._webExtensionsScannerService.scanExtensionsUnderDevelopment().then(extensions => development.push(...extensions.map(e => toExtensionDescription(e, true))))
|
||||
]);
|
||||
} catch (error) {
|
||||
log.error('', error);
|
||||
}
|
||||
return dedupExtensions(system, user, development, log);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
|
||||
|
||||
@@ -23,14 +23,40 @@ 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';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
const LOG_USE_COLORS = true;
|
||||
|
||||
export class ExtensionHostManager extends Disposable {
|
||||
export interface IExtensionHostManager {
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly onDidExit: Event<[number, string | null]>;
|
||||
readonly onDidChangeResponsiveState: Event<ResponsiveState>;
|
||||
dispose(): void;
|
||||
ready(): Promise<void>;
|
||||
deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void>;
|
||||
activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
|
||||
activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
|
||||
getInspectPort(tryEnableInspector: boolean): Promise<number>;
|
||||
resolveAuthority(remoteAuthority: string): Promise<ResolverResult>;
|
||||
getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI>;
|
||||
start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
extensionTestsExecute(): Promise<number>;
|
||||
extensionTestsSendExit(exitCode: number): Promise<void>;
|
||||
setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
|
||||
}
|
||||
|
||||
export function createExtensionHostManager(instantiationService: IInstantiationService, extensionHost: IExtensionHost, isInitialStart: boolean, initialActivationEvents: string[]): IExtensionHostManager {
|
||||
if (extensionHost.lazyStart && isInitialStart && initialActivationEvents.length === 0) {
|
||||
return instantiationService.createInstance(LazyStartExtensionHostManager, extensionHost);
|
||||
}
|
||||
return instantiationService.createInstance(ExtensionHostManager, extensionHost, initialActivationEvents);
|
||||
}
|
||||
|
||||
class ExtensionHostManager extends Disposable implements IExtensionHostManager {
|
||||
|
||||
public readonly kind: ExtensionHostKind;
|
||||
public readonly onDidExit: Event<[number, string | null]>;
|
||||
@@ -219,7 +245,8 @@ export class ExtensionHostManager extends Disposable {
|
||||
MainContext.MainThreadNotebookDocuments,
|
||||
MainContext.MainThreadNotebookEditors,
|
||||
MainContext.MainThreadNotebookKernels,
|
||||
MainContext.MainThreadNotebookRenderers
|
||||
MainContext.MainThreadNotebookRenderers,
|
||||
MainContext.MainThreadInteractive
|
||||
];
|
||||
const expected: ProxyIdentifier<any>[] = Object.keys(MainContext).map((key) => (<any>MainContext)[key]).filter(v => !filtered.some(x => x === v));
|
||||
this._rpcProtocol.assertRegistered(expected);
|
||||
@@ -356,6 +383,127 @@ export class ExtensionHostManager extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until `start()` and only if it has extensions proceeds to really start.
|
||||
*/
|
||||
class LazyStartExtensionHostManager extends Disposable implements IExtensionHostManager {
|
||||
public readonly kind: ExtensionHostKind;
|
||||
public readonly onDidExit: Event<[number, string | null]>;
|
||||
private readonly _onDidChangeResponsiveState: Emitter<ResponsiveState> = this._register(new Emitter<ResponsiveState>());
|
||||
public readonly onDidChangeResponsiveState: Event<ResponsiveState> = this._onDidChangeResponsiveState.event;
|
||||
|
||||
private readonly _extensionHost: IExtensionHost;
|
||||
private _startCalled: Barrier;
|
||||
private _actual: ExtensionHostManager | null;
|
||||
|
||||
constructor(
|
||||
extensionHost: IExtensionHost,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
this._extensionHost = extensionHost;
|
||||
this.kind = extensionHost.kind;
|
||||
this.onDidExit = extensionHost.onExit;
|
||||
this._startCalled = new Barrier();
|
||||
this._actual = null;
|
||||
}
|
||||
|
||||
private _createActual(reason: string): ExtensionHostManager {
|
||||
this._logService.info(`Creating lazy extension host: ${reason}`);
|
||||
this._actual = this._register(this._instantiationService.createInstance(ExtensionHostManager, this._extensionHost, []));
|
||||
this._register(this._actual.onDidChangeResponsiveState((e) => this._onDidChangeResponsiveState.fire(e)));
|
||||
return this._actual;
|
||||
}
|
||||
|
||||
private async _getOrCreateActualAndStart(reason: string): Promise<ExtensionHostManager> {
|
||||
if (this._actual) {
|
||||
// already created/started
|
||||
return this._actual;
|
||||
}
|
||||
const actual = this._createActual(reason);
|
||||
await actual.start([]);
|
||||
return actual;
|
||||
}
|
||||
|
||||
public async ready(): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
await this._actual.ready();
|
||||
}
|
||||
}
|
||||
public async deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
const extensionHostAlreadyStarted = Boolean(this._actual);
|
||||
const shouldStartExtensionHost = (toAdd.length > 0);
|
||||
if (extensionHostAlreadyStarted || shouldStartExtensionHost) {
|
||||
const actual = await this._getOrCreateActualAndStart(`contains ${toAdd.length} new extension(s) (installed or enabled)`);
|
||||
return actual.deltaExtensions(toAdd, toRemove);
|
||||
}
|
||||
}
|
||||
public async activate(extension: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.activate(extension, reason);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public async activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.activateByEvent(activationEvent, activationKind);
|
||||
}
|
||||
}
|
||||
public async getInspectPort(tryEnableInspector: boolean): Promise<number> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.getInspectPort(tryEnableInspector);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public async resolveAuthority(remoteAuthority: string): Promise<ResolverResult> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.resolveAuthority(remoteAuthority);
|
||||
}
|
||||
throw new Error(`Cannot resolve authority`);
|
||||
}
|
||||
public async getCanonicalURI(remoteAuthority: string, uri: URI): Promise<URI> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.getCanonicalURI(remoteAuthority, uri);
|
||||
}
|
||||
throw new Error(`Cannot resolve canonical URI`);
|
||||
}
|
||||
public async start(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
if (enabledExtensionIds.length > 0) {
|
||||
// there are actual extensions, so let's launch the extension host
|
||||
const actual = this._createActual(`contains ${enabledExtensionIds.length} extension(s).`);
|
||||
const result = actual.start(enabledExtensionIds);
|
||||
this._startCalled.open();
|
||||
return result;
|
||||
}
|
||||
// there are no actual extensions
|
||||
this._startCalled.open();
|
||||
}
|
||||
public async extensionTestsExecute(): Promise<number> {
|
||||
await this._startCalled.wait();
|
||||
const actual = await this._getOrCreateActualAndStart(`execute tests.`);
|
||||
return actual.extensionTestsExecute();
|
||||
}
|
||||
public async extensionTestsSendExit(exitCode: number): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
const actual = await this._getOrCreateActualAndStart(`execute tests.`);
|
||||
return actual.extensionTestsSendExit(exitCode);
|
||||
}
|
||||
public async setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void> {
|
||||
await this._startCalled.wait();
|
||||
if (this._actual) {
|
||||
return this._actual.setRemoteEnvironment(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const colorTables = [
|
||||
['#2977B1', '#FC802D', '#34A13A', '#D3282F', '#9366BA'],
|
||||
['#8B564C', '#E177C0', '#7F7F7F', '#BBBE3D', '#2EBECD']
|
||||
@@ -461,7 +609,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
|
||||
const measurements = await Promise.all(getLatencyTestProviders().map(provider => provider.measure()));
|
||||
editorService.openEditor({ contents: measurements.map(MeasureExtHostLatencyAction._print).join('\n\n'), options: { pinned: true } });
|
||||
editorService.openEditor({ resource: undefined, contents: measurements.map(MeasureExtHostLatencyAction._print).join('\n\n'), options: { pinned: true } });
|
||||
}
|
||||
|
||||
private static _print(m: ExtHostLatencyResult | null): string {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkpaceSupportType, ExtensionVirtualWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier, ExtensionUntrustedWorkspaceSupportType, ExtensionVirtualWorkspaceSupportType, IExtensionIdentifier, ALL_EXTENSION_KINDS } 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';
|
||||
@@ -15,7 +15,8 @@ import { ExtensionUntrustedWorkspaceSupport } from 'vs/base/common/product';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { WORKSPACE_TRUST_EXTENSION_SUPPORT } from 'vs/workbench/services/workspaces/common/workspaceTrust';
|
||||
import { isBoolean } from 'vs/base/common/types';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export const IExtensionManifestPropertiesService = createDecorator<IExtensionManifestPropertiesService>('extensionManifestPropertiesService');
|
||||
|
||||
@@ -31,39 +32,41 @@ export interface IExtensionManifestPropertiesService {
|
||||
canExecuteOnWeb(manifest: IExtensionManifest): boolean;
|
||||
|
||||
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[];
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType;
|
||||
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType;
|
||||
getUserConfiguredExtensionKind(extensionIdentifier: IExtensionIdentifier): ExtensionKind[] | undefined;
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType;
|
||||
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkspaceSupportType;
|
||||
}
|
||||
|
||||
export class ExtensionManifestPropertiesService extends Disposable implements IExtensionManifestPropertiesService {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private _uiExtensionPoints: Set<string> | null = null;
|
||||
private _extensionPointExtensionKindsMap: Map<string, ExtensionKind[]> | 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 _configuredExtensionWorkspaceTrustRequestMap: Map<string, { supported: ExtensionUntrustedWorkspaceSupportType, version?: string }>;
|
||||
private readonly _productExtensionWorkspaceTrustRequestMap: Map<string, ExtensionUntrustedWorkspaceSupport>;
|
||||
|
||||
constructor(
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IWorkspaceTrustManagementService private readonly workspaceTrustManagementService: IWorkspaceTrustManagementService
|
||||
@IWorkspaceTrustEnablementService private readonly workspaceTrustEnablementService: IWorkspaceTrustEnablementService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
) {
|
||||
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 || {};
|
||||
this._configuredExtensionWorkspaceTrustRequestMap = new Map<string, { supported: ExtensionUntrustedWorkspaceSupportType, version?: string }>();
|
||||
const configuredExtensionWorkspaceTrustRequests = configurationService.inspect<{ [key: string]: { supported: ExtensionUntrustedWorkspaceSupportType, 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)
|
||||
// Workspace trust request type (products.json)
|
||||
this._productExtensionWorkspaceTrustRequestMap = new Map<string, ExtensionUntrustedWorkspaceSupport>();
|
||||
if (productService.extensionUntrustedWorkspaceSupport) {
|
||||
for (const id of Object.keys(productService.extensionUntrustedWorkspaceSupport)) {
|
||||
@@ -103,30 +106,51 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
}
|
||||
|
||||
getExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
// check in config
|
||||
let result = this.getConfiguredExtensionKind(manifest);
|
||||
if (typeof result !== 'undefined') {
|
||||
return this.toArray(result);
|
||||
}
|
||||
const deducedExtensionKind = this.deduceExtensionKind(manifest);
|
||||
const configuredExtensionKind = this.getConfiguredExtensionKind(manifest);
|
||||
|
||||
if (configuredExtensionKind) {
|
||||
const result: ExtensionKind[] = [];
|
||||
for (const extensionKind of configuredExtensionKind) {
|
||||
if (extensionKind !== '-web') {
|
||||
result.push(extensionKind);
|
||||
}
|
||||
}
|
||||
|
||||
// If opted out from web without specifying other extension kinds then default to ui, workspace
|
||||
if (configuredExtensionKind.includes('-web') && !result.length) {
|
||||
result.push('ui');
|
||||
result.push('workspace');
|
||||
}
|
||||
|
||||
// Add web kind if not opted out from web and can run in web
|
||||
if (!configuredExtensionKind.includes('-web') && !configuredExtensionKind.includes('web') && deducedExtensionKind.includes('web')) {
|
||||
result.push('web');
|
||||
}
|
||||
|
||||
// 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);
|
||||
return deducedExtensionKind;
|
||||
}
|
||||
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType {
|
||||
getUserConfiguredExtensionKind(extensionIdentifier: IExtensionIdentifier): 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 userConfiguredExtensionKind = this._configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionIdentifier.id));
|
||||
return userConfiguredExtensionKind ? this.toArray(userConfiguredExtensionKind) : undefined;
|
||||
}
|
||||
|
||||
getExtensionUntrustedWorkspaceSupportType(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType {
|
||||
// Workspace trust feature is disabled, or extension has no entry point
|
||||
if (!this.workspaceTrustManagementService.workspaceTrustEnabled || !manifest.main) {
|
||||
if (!this.workspaceTrustEnablementService.isWorkspaceTrustEnabled() || !manifest.main) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,12 +161,12 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
const productWorkspaceTrustRequest = this.getProductExtensionWorkspaceTrustRequest(manifest);
|
||||
|
||||
// Use settings.json override value if it exists
|
||||
if (configuredWorkspaceTrustRequest) {
|
||||
if (configuredWorkspaceTrustRequest !== undefined) {
|
||||
return configuredWorkspaceTrustRequest;
|
||||
}
|
||||
|
||||
// Use product.json override value if it exists
|
||||
if (productWorkspaceTrustRequest?.override) {
|
||||
if (productWorkspaceTrustRequest?.override !== undefined) {
|
||||
return productWorkspaceTrustRequest.override;
|
||||
}
|
||||
|
||||
@@ -152,14 +176,14 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
}
|
||||
|
||||
// Use product.json default value if it exists
|
||||
if (productWorkspaceTrustRequest?.default) {
|
||||
if (productWorkspaceTrustRequest?.default !== undefined) {
|
||||
return productWorkspaceTrustRequest.default;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkpaceSupportType {
|
||||
getExtensionVirtualWorkspaceSupportType(manifest: IExtensionManifest): ExtensionVirtualWorkspaceSupportType {
|
||||
// check user configured
|
||||
const userConfiguredVirtualWorkspaceSupport = this.getConfiguredVirtualWorkspaceSupport(manifest);
|
||||
if (userConfiguredVirtualWorkspaceSupport !== undefined) {
|
||||
@@ -193,7 +217,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
return true;
|
||||
}
|
||||
|
||||
deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
private deduceExtensionKind(manifest: IExtensionManifest): ExtensionKind[] {
|
||||
// Not an UI extension if it has main
|
||||
if (manifest.main) {
|
||||
if (manifest.browser) {
|
||||
@@ -206,32 +230,72 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
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'];
|
||||
let result = [...ALL_EXTENSION_KINDS];
|
||||
|
||||
// Extension pack defaults to workspace extensionKind
|
||||
if (isNonEmptyArray(manifest.extensionPack) || isNonEmptyArray(manifest.extensionDependencies)) {
|
||||
result = ['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'];
|
||||
const supportedExtensionKinds = this.getSupportedExtensionKindsForExtensionPoint(contribution);
|
||||
if (supportedExtensionKinds.length) {
|
||||
result = result.filter(extensionKind => supportedExtensionKinds.includes(extensionKind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['ui', 'workspace', 'web'];
|
||||
if (!result.length) {
|
||||
this.logService.warn('Cannot deduce extensionKind for extension', getGalleryExtensionId(manifest.publisher, manifest.name));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
private getSupportedExtensionKindsForExtensionPoint(extensionPoint: string): ExtensionKind[] {
|
||||
if (this._extensionPointExtensionKindsMap === null) {
|
||||
const extensionPointExtensionKindsMap = new Map<string, ExtensionKind[]>();
|
||||
ExtensionsRegistry.getExtensionPoints().forEach(e => extensionPointExtensionKindsMap.set(e.name, e.defaultExtensionKind || [] /* supports all */));
|
||||
this._extensionPointExtensionKindsMap = extensionPointExtensionKindsMap;
|
||||
}
|
||||
return this._uiExtensionPoints.has(extensionPoint);
|
||||
|
||||
let extensionPointExtensionKind = this._extensionPointExtensionKindsMap.get(extensionPoint);
|
||||
if (extensionPointExtensionKind) {
|
||||
return extensionPointExtensionKind;
|
||||
}
|
||||
|
||||
extensionPointExtensionKind = this.productService.extensionPointExtensionKind ? this.productService.extensionPointExtensionKind[extensionPoint] : undefined;
|
||||
if (extensionPointExtensionKind) {
|
||||
return extensionPointExtensionKind;
|
||||
}
|
||||
|
||||
return ['workspace', 'web'] /* Unknown extension point => workspace, web */;
|
||||
}
|
||||
|
||||
private getConfiguredExtensionKind(manifest: IExtensionManifest): (ExtensionKind | '-web')[] | null {
|
||||
const extensionIdentifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||
|
||||
// check in config
|
||||
let result: ExtensionKind | ExtensionKind[] | undefined = this.getUserConfiguredExtensionKind(extensionIdentifier);
|
||||
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') {
|
||||
result = this.toArray(result);
|
||||
return result.filter(r => ALL_EXTENSION_KINDS.includes(r));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private getProductExtensionKind(manifest: IExtensionManifest): ExtensionKind[] | undefined {
|
||||
@@ -249,20 +313,6 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
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 }>();
|
||||
@@ -294,7 +344,7 @@ export class ExtensionManifestPropertiesService extends Disposable implements IE
|
||||
return this._configuredVirtualWorkspaceSupportMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkpaceSupportType | undefined {
|
||||
private getConfiguredExtensionWorkspaceTrustRequest(manifest: IExtensionManifest): ExtensionUntrustedWorkspaceSupportType | undefined {
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
const extensionWorkspaceTrustRequest = this._configuredExtensionWorkspaceTrustRequestMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export const nullExtensionDescription = Object.freeze(<IExtensionDescription>{
|
||||
isBuiltin: false,
|
||||
});
|
||||
|
||||
export type WebWorkerExtHostConfigValue = boolean | 'auto';
|
||||
export const webWorkerExtHostConfig = 'extensions.webWorker';
|
||||
|
||||
export const IExtensionService = createDecorator<IExtensionService>('extensionService');
|
||||
@@ -35,10 +36,18 @@ export interface IMessage {
|
||||
extensionPointId: string;
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export interface IExtensionsStatus {
|
||||
messages: IMessage[];
|
||||
activationTimes: ActivationTimes | undefined;
|
||||
runtimeErrors: Error[];
|
||||
runningLocation: ExtensionRunningLocation;
|
||||
}
|
||||
|
||||
export class MissingExtensionDependency {
|
||||
@@ -94,6 +103,7 @@ export const enum ExtensionHostKind {
|
||||
export interface IExtensionHost {
|
||||
readonly kind: ExtensionHostKind;
|
||||
readonly remoteAuthority: string | null;
|
||||
readonly lazyStart: boolean;
|
||||
readonly onExit: Event<[number, string | null]>;
|
||||
|
||||
start(): Promise<IMessagePassingProtocol> | null;
|
||||
@@ -288,12 +298,12 @@ export function toExtension(extensionDescription: IExtensionDescription): IExten
|
||||
};
|
||||
}
|
||||
|
||||
export function toExtensionDescription(extension: IExtension): IExtensionDescription {
|
||||
export function toExtensionDescription(extension: IExtension, isUnderDevelopment?: boolean): IExtensionDescription {
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(extension.identifier.id),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUserBuiltin: extension.type === ExtensionType.User && extension.isBuiltin,
|
||||
isUnderDevelopment: false,
|
||||
isUnderDevelopment: !!isUnderDevelopment,
|
||||
extensionLocation: extension.location,
|
||||
...extension.manifest,
|
||||
uuid: extension.identifier.uuid
|
||||
|
||||
@@ -11,10 +11,9 @@ import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/co
|
||||
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IMessage } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, EXTENSION_CATEGORIES, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
const schemaRegistry = Registry.as<IJSONContributionRegistry>(Extensions.JSONContribution);
|
||||
export type ExtensionKind = 'workspace' | 'ui' | undefined;
|
||||
|
||||
export class ExtensionMessageCollector {
|
||||
|
||||
@@ -63,9 +62,9 @@ export interface IExtensionPointUser<T> {
|
||||
export type IExtensionPointHandler<T> = (extensions: readonly IExtensionPointUser<T>[], delta: ExtensionPointUserDelta<T>) => void;
|
||||
|
||||
export interface IExtensionPoint<T> {
|
||||
name: string;
|
||||
readonly name: string;
|
||||
setHandler(handler: IExtensionPointHandler<T>): void;
|
||||
defaultExtensionKind: ExtensionKind;
|
||||
readonly defaultExtensionKind: ExtensionKind[] | undefined;
|
||||
}
|
||||
|
||||
export class ExtensionPointUserDelta<T> {
|
||||
@@ -104,13 +103,13 @@ export class ExtensionPointUserDelta<T> {
|
||||
export class ExtensionPoint<T> implements IExtensionPoint<T> {
|
||||
|
||||
public readonly name: string;
|
||||
public readonly defaultExtensionKind: ExtensionKind;
|
||||
public readonly defaultExtensionKind: ExtensionKind[] | undefined;
|
||||
|
||||
private _handler: IExtensionPointHandler<T> | null;
|
||||
private _users: IExtensionPointUser<T>[] | null;
|
||||
private _delta: ExtensionPointUserDelta<T> | null;
|
||||
|
||||
constructor(name: string, defaultExtensionKind: ExtensionKind) {
|
||||
constructor(name: string, defaultExtensionKind: ExtensionKind[] | undefined) {
|
||||
this.name = name;
|
||||
this.defaultExtensionKind = defaultExtensionKind;
|
||||
this._handler = null;
|
||||
@@ -312,7 +311,7 @@ export const schema: IJSONSchema = {
|
||||
},
|
||||
{
|
||||
label: 'onNotebook',
|
||||
body: 'onNotebook:${10:viewType}',
|
||||
body: 'onNotebook:${1:type}',
|
||||
description: nls.localize('vscode.extension.activationEvents.onNotebook', 'An activation event emitted whenever the specified notebook document is opened.'),
|
||||
},
|
||||
{
|
||||
@@ -327,9 +326,14 @@ export const schema: IJSONSchema = {
|
||||
},
|
||||
{
|
||||
label: 'onTerminalProfile',
|
||||
body: 'onTerminalProfile:${1:terminalType}',
|
||||
body: 'onTerminalProfile:${1:terminalId}',
|
||||
description: nls.localize('vscode.extension.activationEvents.onTerminalProfile', 'An activation event emitted when a specific terminal profile is launched.'),
|
||||
},
|
||||
{
|
||||
label: 'onWalkthrough',
|
||||
body: 'onWalkthrough:${1:walkthroughID}',
|
||||
description: nls.localize('vscode.extension.activationEvents.onWalkthrough', 'An activation event emitted when a specified walkthrough is opened.'),
|
||||
},
|
||||
{
|
||||
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.'),
|
||||
@@ -511,7 +515,7 @@ export interface IExtensionPointDescriptor {
|
||||
extensionPoint: string;
|
||||
deps?: IExtensionPoint<any>[];
|
||||
jsonSchema: IJSONSchema;
|
||||
defaultExtensionKind?: ExtensionKind;
|
||||
defaultExtensionKind?: ExtensionKind[];
|
||||
}
|
||||
|
||||
export class ExtensionsRegistryImpl {
|
||||
|
||||
@@ -3,149 +3,34 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionIdentifier } 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 { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILog } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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 = getConfiguredExtensionKind(manifest, this.configurationService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
export function dedupExtensions(system: IExtensionDescription[], user: IExtensionDescription[], development: IExtensionDescription[], log: ILog): IExtensionDescription[] {
|
||||
let result = new Map<string, IExtensionDescription>();
|
||||
system.forEach((systemExtension) => {
|
||||
const extensionKey = ExtensionIdentifier.toKey(systemExtension.identifier);
|
||||
const extension = result.get(extensionKey);
|
||||
if (extension) {
|
||||
log.warn(systemExtension.extensionLocation.fsPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, systemExtension.extensionLocation.fsPath));
|
||||
}
|
||||
|
||||
// check product.json
|
||||
result = getProductExtensionKind(manifest, this.productService);
|
||||
if (typeof result !== 'undefined') {
|
||||
return result;
|
||||
result.set(extensionKey, systemExtension);
|
||||
});
|
||||
user.forEach((userExtension) => {
|
||||
const extensionKey = ExtensionIdentifier.toKey(userExtension.identifier);
|
||||
const extension = result.get(extensionKey);
|
||||
if (extension) {
|
||||
log.warn(userExtension.extensionLocation.fsPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, userExtension.extensionLocation.fsPath));
|
||||
}
|
||||
|
||||
// check the manifest itself
|
||||
result = manifest.extensionKind;
|
||||
if (typeof result !== 'undefined') {
|
||||
return toArray(result);
|
||||
}
|
||||
|
||||
return deduceExtensionKind(manifest);
|
||||
}
|
||||
result.set(extensionKey, userExtension);
|
||||
});
|
||||
development.forEach(developedExtension => {
|
||||
log.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
|
||||
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
|
||||
result.set(extensionKey, developedExtension);
|
||||
});
|
||||
let r: IExtensionDescription[] = [];
|
||||
result.forEach((value) => r.push(value));
|
||||
return r;
|
||||
}
|
||||
|
||||
export function 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 (!isUIExtensionPoint(contribution)) {
|
||||
return ['workspace'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ['ui', 'workspace', 'web'];
|
||||
}
|
||||
|
||||
let _uiExtensionPoints: Set<string> | null = null;
|
||||
function isUIExtensionPoint(extensionPoint: string): boolean {
|
||||
if (_uiExtensionPoints === null) {
|
||||
const uiExtensionPoints = new Set<string>();
|
||||
ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').forEach(e => {
|
||||
uiExtensionPoints.add(e.name);
|
||||
});
|
||||
_uiExtensionPoints = uiExtensionPoints;
|
||||
}
|
||||
return _uiExtensionPoints.has(extensionPoint);
|
||||
}
|
||||
|
||||
let _productExtensionKindsMap: Map<string, ExtensionKind[]> | null = null;
|
||||
function getProductExtensionKind(manifest: IExtensionManifest, productService: IProductService): ExtensionKind[] | undefined {
|
||||
if (_productExtensionKindsMap === null) {
|
||||
const productExtensionKindsMap = new Map<string, ExtensionKind[]>();
|
||||
if (productService.extensionKind) {
|
||||
for (const id of Object.keys(productService.extensionKind)) {
|
||||
productExtensionKindsMap.set(ExtensionIdentifier.toKey(id), productService.extensionKind[id]);
|
||||
}
|
||||
}
|
||||
_productExtensionKindsMap = productExtensionKindsMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return _productExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
let _configuredExtensionKindsMap: Map<string, ExtensionKind | ExtensionKind[]> | null = null;
|
||||
function getConfiguredExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): ExtensionKind | ExtensionKind[] | undefined {
|
||||
if (_configuredExtensionKindsMap === null) {
|
||||
const configuredExtensionKindsMap = new Map<string, ExtensionKind | ExtensionKind[]>();
|
||||
const configuredExtensionKinds = configurationService.getValue<{ [key: string]: ExtensionKind | ExtensionKind[] }>('remote.extensionKind') || {};
|
||||
for (const id of Object.keys(configuredExtensionKinds)) {
|
||||
configuredExtensionKindsMap.set(ExtensionIdentifier.toKey(id), configuredExtensionKinds[id]);
|
||||
}
|
||||
_configuredExtensionKindsMap = configuredExtensionKindsMap;
|
||||
}
|
||||
|
||||
const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name);
|
||||
return _configuredExtensionKindsMap.get(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
function toArray(extensionKind: ExtensionKind | ExtensionKind[]): ExtensionKind[] {
|
||||
if (Array.isArray(extensionKind)) {
|
||||
return extensionKind;
|
||||
}
|
||||
return extensionKind === 'ui' ? ['ui', 'workspace'] : [extensionKind];
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface IRPCProtocol {
|
||||
|
||||
export class ProxyIdentifier<T> {
|
||||
public static count = 0;
|
||||
_proxyIdentifierBrand: void;
|
||||
_proxyIdentifierBrand: void = undefined;
|
||||
|
||||
public readonly isMain: boolean;
|
||||
public readonly sid: string;
|
||||
@@ -57,3 +57,12 @@ export function createExtHostContextProxyIdentifier<T>(identifier: string): Prox
|
||||
export function getStringIdentifierForProxy(nid: number): string {
|
||||
return identifiers[nid].sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the object as containing buffers that should be serialized more efficently.
|
||||
*/
|
||||
export class SerializableObjectWithBuffers<T> {
|
||||
constructor(
|
||||
public readonly value: T
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.Remote;
|
||||
public readonly remoteAuthority: string;
|
||||
public readonly lazyStart = false;
|
||||
|
||||
private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>());
|
||||
public readonly onExit: Event<[number, string | null]> = this._onExit.event;
|
||||
@@ -231,6 +232,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
isExtensionDevelopmentDebug,
|
||||
appRoot: remoteInitData.appRoot,
|
||||
appName: this._productService.nameLong,
|
||||
embedderIdentifier: this._productService.embedderIdentifier || 'desktop',
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { MarshalledId, MarshalledObject } from 'vs/base/common/marshalling';
|
||||
import { IURITransformer, transformIncomingURIs } from 'vs/base/common/uriIpc';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { LazyPromise } from 'vs/workbench/services/extensions/common/lazyPromise';
|
||||
import { IRPCProtocol, ProxyIdentifier, getStringIdentifierForProxy } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { getStringIdentifierForProxy, IRPCProtocol, ProxyIdentifier, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
export interface JSONStringifyReplacer {
|
||||
(key: string, value: any): any;
|
||||
@@ -27,6 +28,55 @@ function safeStringify(obj: any, replacer: JSONStringifyReplacer | null): string
|
||||
}
|
||||
}
|
||||
|
||||
const refSymbolName = '$$ref$$';
|
||||
const undefinedRef = { [refSymbolName]: -1 } as const;
|
||||
|
||||
class StringifiedJsonWithBufferRefs {
|
||||
constructor(
|
||||
public readonly jsonString: string,
|
||||
public readonly referencedBuffers: readonly VSBuffer[],
|
||||
) { }
|
||||
}
|
||||
|
||||
export function stringifyJsonWithBufferRefs<T>(obj: T, replacer: JSONStringifyReplacer | null = null, useSafeStringify = false): StringifiedJsonWithBufferRefs {
|
||||
const foundBuffers: VSBuffer[] = [];
|
||||
const serialized = (useSafeStringify ? safeStringify : JSON.stringify)(obj, (key, value) => {
|
||||
if (typeof value === 'undefined') {
|
||||
return undefinedRef; // JSON.stringify normally converts 'undefined' to 'null'
|
||||
} else if (typeof value === 'object') {
|
||||
if (value instanceof VSBuffer) {
|
||||
const bufferIndex = foundBuffers.push(value) - 1;
|
||||
return { [refSymbolName]: bufferIndex };
|
||||
}
|
||||
if (replacer) {
|
||||
return replacer(key, value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
return {
|
||||
jsonString: serialized,
|
||||
referencedBuffers: foundBuffers
|
||||
};
|
||||
}
|
||||
|
||||
export function parseJsonAndRestoreBufferRefs(jsonString: string, buffers: readonly VSBuffer[], uriTransformer: IURITransformer | null): any {
|
||||
return JSON.parse(jsonString, (_key, value) => {
|
||||
if (value) {
|
||||
const ref = value[refSymbolName];
|
||||
if (typeof ref === 'number') {
|
||||
return buffers[ref];
|
||||
}
|
||||
|
||||
if (uriTransformer && (<MarshalledObject>value).$mid === MarshalledId.Uri) {
|
||||
return uriTransformer.transformIncoming(value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function stringify(obj: any, replacer: JSONStringifyReplacer | null): string {
|
||||
return JSON.stringify(obj, <(key: string, value: any) => any>replacer);
|
||||
}
|
||||
@@ -36,7 +86,7 @@ function createURIReplacer(transformer: IURITransformer | null): JSONStringifyRe
|
||||
return null;
|
||||
}
|
||||
return (key: string, value: any): any => {
|
||||
if (value && value.$mid === 1) {
|
||||
if (value && value.$mid === MarshalledId.Uri) {
|
||||
return transformer.transformOutgoing(value);
|
||||
}
|
||||
return value;
|
||||
@@ -277,6 +327,11 @@ export class RPCProtocol extends Disposable implements IRPCProtocol {
|
||||
this._receiveReply(msgLength, req, value);
|
||||
break;
|
||||
}
|
||||
case MessageType.ReplyOKJSONWithBuffers: {
|
||||
const value = MessageIO.deserializeReplyOKJSONWithBuffers(buff, this._uriTransformer);
|
||||
this._receiveReply(msgLength, req, value);
|
||||
break;
|
||||
}
|
||||
case MessageType.ReplyOKVSBuffer: {
|
||||
let value = MessageIO.deserializeReplyOKVSBuffer(buff);
|
||||
this._receiveReply(msgLength, req, value);
|
||||
@@ -557,19 +612,25 @@ class MessageBuffer {
|
||||
return buff;
|
||||
}
|
||||
|
||||
public static sizeMixedArray(arr: VSBuffer[], arrType: ArgType[]): number {
|
||||
public static sizeMixedArray(arr: readonly MixedArg[]): number {
|
||||
let size = 0;
|
||||
size += 1; // arr length
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
const el = arr[i];
|
||||
const elType = arrType[i];
|
||||
size += 1; // arg type
|
||||
switch (elType) {
|
||||
switch (el.type) {
|
||||
case ArgType.String:
|
||||
size += this.sizeLongString(el);
|
||||
size += this.sizeLongString(el.value);
|
||||
break;
|
||||
case ArgType.VSBuffer:
|
||||
size += this.sizeVSBuffer(el);
|
||||
size += this.sizeVSBuffer(el.value);
|
||||
break;
|
||||
case ArgType.SerializedObjectWithBuffers:
|
||||
size += this.sizeUInt8(); // buffer count
|
||||
size += this.sizeLongString(el.value);
|
||||
for (let i = 0; i < el.buffers.length; ++i) {
|
||||
size += this.sizeVSBuffer(el.buffers[i]);
|
||||
}
|
||||
break;
|
||||
case ArgType.Undefined:
|
||||
// empty...
|
||||
@@ -579,19 +640,26 @@ class MessageBuffer {
|
||||
return size;
|
||||
}
|
||||
|
||||
public writeMixedArray(arr: VSBuffer[], arrType: ArgType[]): void {
|
||||
public writeMixedArray(arr: readonly MixedArg[]): void {
|
||||
this._buff.writeUInt8(arr.length, this._offset); this._offset += 1;
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
const el = arr[i];
|
||||
const elType = arrType[i];
|
||||
switch (elType) {
|
||||
switch (el.type) {
|
||||
case ArgType.String:
|
||||
this.writeUInt8(ArgType.String);
|
||||
this.writeLongString(el);
|
||||
this.writeLongString(el.value);
|
||||
break;
|
||||
case ArgType.VSBuffer:
|
||||
this.writeUInt8(ArgType.VSBuffer);
|
||||
this.writeVSBuffer(el);
|
||||
this.writeVSBuffer(el.value);
|
||||
break;
|
||||
case ArgType.SerializedObjectWithBuffers:
|
||||
this.writeUInt8(ArgType.SerializedObjectWithBuffers);
|
||||
this.writeUInt8(el.buffers.length);
|
||||
this.writeLongString(el.value);
|
||||
for (let i = 0; i < el.buffers.length; ++i) {
|
||||
this.writeBuffer(el.buffers[i]);
|
||||
}
|
||||
break;
|
||||
case ArgType.Undefined:
|
||||
this.writeUInt8(ArgType.Undefined);
|
||||
@@ -600,9 +668,9 @@ class MessageBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public readMixedArray(): Array<string | VSBuffer | undefined> {
|
||||
public readMixedArray(): Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> {
|
||||
const arrLen = this._buff.readUInt8(this._offset); this._offset += 1;
|
||||
let arr: Array<string | VSBuffer | undefined> = new Array(arrLen);
|
||||
let arr: Array<string | VSBuffer | SerializableObjectWithBuffers<any> | undefined> = new Array(arrLen);
|
||||
for (let i = 0; i < arrLen; i++) {
|
||||
const argType = <ArgType>this.readUInt8();
|
||||
switch (argType) {
|
||||
@@ -612,6 +680,15 @@ class MessageBuffer {
|
||||
case ArgType.VSBuffer:
|
||||
arr[i] = this.readVSBuffer();
|
||||
break;
|
||||
case ArgType.SerializedObjectWithBuffers:
|
||||
const bufferCount = this.readUInt8();
|
||||
const jsonString = this.readLongString();
|
||||
const buffers: VSBuffer[] = [];
|
||||
for (let i = 0; i < bufferCount; ++i) {
|
||||
buffers.push(this.readVSBuffer());
|
||||
}
|
||||
arr[i] = new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(jsonString, buffers, null));
|
||||
break;
|
||||
case ArgType.Undefined:
|
||||
arr[i] = undefined;
|
||||
break;
|
||||
@@ -621,15 +698,26 @@ class MessageBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
type SerializedRequestArguments = { type: 'mixed'; args: VSBuffer[]; argsType: ArgType[]; } | { type: 'simple'; args: string; };
|
||||
const enum SerializedRequestArgumentType {
|
||||
Simple,
|
||||
Mixed,
|
||||
}
|
||||
|
||||
type SerializedRequestArguments =
|
||||
| { readonly type: SerializedRequestArgumentType.Simple; args: string; }
|
||||
| { readonly type: SerializedRequestArgumentType.Mixed; args: MixedArg[] };
|
||||
|
||||
|
||||
class MessageIO {
|
||||
|
||||
private static _arrayContainsBufferOrUndefined(arr: any[]): boolean {
|
||||
private static _useMixedArgSerialization(arr: any[]): boolean {
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
if (arr[i] instanceof VSBuffer) {
|
||||
return true;
|
||||
}
|
||||
if (arr[i] instanceof SerializableObjectWithBuffers) {
|
||||
return true;
|
||||
}
|
||||
if (typeof arr[i] === 'undefined') {
|
||||
return true;
|
||||
}
|
||||
@@ -638,39 +726,39 @@ class MessageIO {
|
||||
}
|
||||
|
||||
public static serializeRequestArguments(args: any[], replacer: JSONStringifyReplacer | null): SerializedRequestArguments {
|
||||
if (this._arrayContainsBufferOrUndefined(args)) {
|
||||
let massagedArgs: VSBuffer[] = [];
|
||||
let massagedArgsType: ArgType[] = [];
|
||||
if (this._useMixedArgSerialization(args)) {
|
||||
const massagedArgs: MixedArg[] = [];
|
||||
for (let i = 0, len = args.length; i < len; i++) {
|
||||
const arg = args[i];
|
||||
if (arg instanceof VSBuffer) {
|
||||
massagedArgs[i] = arg;
|
||||
massagedArgsType[i] = ArgType.VSBuffer;
|
||||
massagedArgs[i] = { type: ArgType.VSBuffer, value: arg };
|
||||
} else if (typeof arg === 'undefined') {
|
||||
massagedArgs[i] = VSBuffer.alloc(0);
|
||||
massagedArgsType[i] = ArgType.Undefined;
|
||||
massagedArgs[i] = { type: ArgType.Undefined };
|
||||
} else if (arg instanceof SerializableObjectWithBuffers) {
|
||||
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(arg.value, replacer);
|
||||
massagedArgs[i] = { type: ArgType.SerializedObjectWithBuffers, value: VSBuffer.fromString(jsonString), buffers: referencedBuffers };
|
||||
} else {
|
||||
massagedArgs[i] = VSBuffer.fromString(stringify(arg, replacer));
|
||||
massagedArgsType[i] = ArgType.String;
|
||||
massagedArgs[i] = { type: ArgType.String, value: VSBuffer.fromString(stringify(arg, replacer)) };
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: 'mixed',
|
||||
type: SerializedRequestArgumentType.Mixed,
|
||||
args: massagedArgs,
|
||||
argsType: massagedArgsType
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: 'simple',
|
||||
type: SerializedRequestArgumentType.Simple,
|
||||
args: stringify(args, replacer)
|
||||
};
|
||||
}
|
||||
|
||||
public static serializeRequest(req: number, rpcId: number, method: string, serializedArgs: SerializedRequestArguments, usesCancellationToken: boolean): VSBuffer {
|
||||
if (serializedArgs.type === 'mixed') {
|
||||
return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, serializedArgs.argsType, usesCancellationToken);
|
||||
switch (serializedArgs.type) {
|
||||
case SerializedRequestArgumentType.Simple:
|
||||
return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
|
||||
case SerializedRequestArgumentType.Mixed:
|
||||
return this._requestMixedArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
|
||||
}
|
||||
return this._requestJSONArgs(req, rpcId, method, serializedArgs.args, usesCancellationToken);
|
||||
}
|
||||
|
||||
private static _requestJSONArgs(req: number, rpcId: number, method: string, args: string, usesCancellationToken: boolean): VSBuffer {
|
||||
@@ -700,18 +788,18 @@ class MessageIO {
|
||||
};
|
||||
}
|
||||
|
||||
private static _requestMixedArgs(req: number, rpcId: number, method: string, args: VSBuffer[], argsType: ArgType[], usesCancellationToken: boolean): VSBuffer {
|
||||
private static _requestMixedArgs(req: number, rpcId: number, method: string, args: readonly MixedArg[], usesCancellationToken: boolean): VSBuffer {
|
||||
const methodBuff = VSBuffer.fromString(method);
|
||||
|
||||
let len = 0;
|
||||
len += MessageBuffer.sizeUInt8();
|
||||
len += MessageBuffer.sizeShortString(methodBuff);
|
||||
len += MessageBuffer.sizeMixedArray(args, argsType);
|
||||
len += MessageBuffer.sizeMixedArray(args);
|
||||
|
||||
let result = MessageBuffer.alloc(usesCancellationToken ? MessageType.RequestMixedArgsWithCancellation : MessageType.RequestMixedArgs, req, len);
|
||||
result.writeUInt8(rpcId);
|
||||
result.writeShortString(methodBuff);
|
||||
result.writeMixedArray(args, argsType);
|
||||
result.writeMixedArray(args);
|
||||
return result.buffer;
|
||||
}
|
||||
|
||||
@@ -746,11 +834,14 @@ class MessageIO {
|
||||
public static serializeReplyOK(req: number, res: any, replacer: JSONStringifyReplacer | null): VSBuffer {
|
||||
if (typeof res === 'undefined') {
|
||||
return this._serializeReplyOKEmpty(req);
|
||||
}
|
||||
if (res instanceof VSBuffer) {
|
||||
} else if (res instanceof VSBuffer) {
|
||||
return this._serializeReplyOKVSBuffer(req, res);
|
||||
} else if (res instanceof SerializableObjectWithBuffers) {
|
||||
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(res.value, replacer, true);
|
||||
return this._serializeReplyOKJSONWithBuffers(req, jsonString, referencedBuffers);
|
||||
} else {
|
||||
return this._serializeReplyOKJSON(req, safeStringify(res, replacer));
|
||||
}
|
||||
return this._serializeReplyOKJSON(req, safeStringify(res, replacer));
|
||||
}
|
||||
|
||||
private static _serializeReplyOKEmpty(req: number): VSBuffer {
|
||||
@@ -781,11 +872,43 @@ class MessageIO {
|
||||
return result.buffer;
|
||||
}
|
||||
|
||||
private static _serializeReplyOKJSONWithBuffers(req: number, res: string, buffers: readonly VSBuffer[]): VSBuffer {
|
||||
const resBuff = VSBuffer.fromString(res);
|
||||
|
||||
let len = 0;
|
||||
len += MessageBuffer.sizeUInt8(); // buffer count
|
||||
len += MessageBuffer.sizeLongString(resBuff);
|
||||
for (const buffer of buffers) {
|
||||
len += MessageBuffer.sizeVSBuffer(buffer);
|
||||
}
|
||||
|
||||
let result = MessageBuffer.alloc(MessageType.ReplyOKJSONWithBuffers, req, len);
|
||||
result.writeUInt8(buffers.length);
|
||||
result.writeLongString(resBuff);
|
||||
for (const buffer of buffers) {
|
||||
result.writeBuffer(buffer);
|
||||
}
|
||||
|
||||
return result.buffer;
|
||||
}
|
||||
|
||||
public static deserializeReplyOKJSON(buff: MessageBuffer): any {
|
||||
const res = buff.readLongString();
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
public static deserializeReplyOKJSONWithBuffers(buff: MessageBuffer, uriTransformer: IURITransformer | null): SerializableObjectWithBuffers<any> {
|
||||
const bufferCount = buff.readUInt8();
|
||||
const res = buff.readLongString();
|
||||
|
||||
const buffers: VSBuffer[] = [];
|
||||
for (let i = 0; i < bufferCount; ++i) {
|
||||
buffers.push(buff.readVSBuffer());
|
||||
}
|
||||
|
||||
return new SerializableObjectWithBuffers(parseJsonAndRestoreBufferRefs(res, buffers, uriTransformer));
|
||||
}
|
||||
|
||||
public static serializeReplyErr(req: number, err: any): VSBuffer {
|
||||
if (err) {
|
||||
return this._serializeReplyErrEror(req, err);
|
||||
@@ -824,12 +947,22 @@ const enum MessageType {
|
||||
ReplyOKEmpty = 7,
|
||||
ReplyOKVSBuffer = 8,
|
||||
ReplyOKJSON = 9,
|
||||
ReplyErrError = 10,
|
||||
ReplyErrEmpty = 11,
|
||||
ReplyOKJSONWithBuffers = 10,
|
||||
ReplyErrError = 11,
|
||||
ReplyErrEmpty = 12,
|
||||
}
|
||||
|
||||
const enum ArgType {
|
||||
String = 1,
|
||||
VSBuffer = 2,
|
||||
Undefined = 3
|
||||
SerializedObjectWithBuffers = 3,
|
||||
Undefined = 4,
|
||||
}
|
||||
|
||||
|
||||
type MixedArg =
|
||||
| { readonly type: ArgType.String, readonly value: VSBuffer }
|
||||
| { readonly type: ArgType.VSBuffer, readonly value: VSBuffer }
|
||||
| { readonly type: ArgType.SerializedObjectWithBuffers, readonly value: VSBuffer, readonly buffers: readonly VSBuffer[] }
|
||||
| { readonly type: ArgType.Undefined }
|
||||
;
|
||||
|
||||
@@ -14,12 +14,13 @@ import { URI } from 'vs/base/common/uri';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IWorkbenchExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, IRelaxedExtensionDescription } from 'vs/workbench/services/extensions/node/extensionPoints';
|
||||
import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
|
||||
interface IExtensionCacheData {
|
||||
input: ExtensionScannerInput;
|
||||
@@ -79,32 +80,7 @@ export class CachedExtensionScanner {
|
||||
try {
|
||||
const translations = await this.translationConfig;
|
||||
const { system, user, development } = await CachedExtensionScanner._scanInstalledExtensions(this._hostService, this._notificationService, this._environmentService, this._extensionEnablementService, this._productService, log, translations);
|
||||
|
||||
let result = new Map<string, IExtensionDescription>();
|
||||
system.forEach((systemExtension) => {
|
||||
const extensionKey = ExtensionIdentifier.toKey(systemExtension.identifier);
|
||||
const extension = result.get(extensionKey);
|
||||
if (extension) {
|
||||
log.warn(systemExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, systemExtension.extensionLocation.fsPath));
|
||||
}
|
||||
result.set(extensionKey, systemExtension);
|
||||
});
|
||||
user.forEach((userExtension) => {
|
||||
const extensionKey = ExtensionIdentifier.toKey(userExtension.identifier);
|
||||
const extension = result.get(extensionKey);
|
||||
if (extension) {
|
||||
log.warn(userExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, userExtension.extensionLocation.fsPath));
|
||||
}
|
||||
result.set(extensionKey, userExtension);
|
||||
});
|
||||
development.forEach(developedExtension => {
|
||||
log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath));
|
||||
const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier);
|
||||
result.set(extensionKey, developedExtension);
|
||||
});
|
||||
let r: IExtensionDescription[] = [];
|
||||
result.forEach((value) => r.push(value));
|
||||
|
||||
const r = dedupExtensions(system, user, development, log);
|
||||
this._scannedExtensionsResolve(r);
|
||||
} catch (err) {
|
||||
this._scannedExtensionsReject(err);
|
||||
|
||||
@@ -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, ExtensionRunningPreference, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocationClassifier, ExtensionRunningPreference } 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';
|
||||
@@ -21,13 +21,12 @@ import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecyc
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig, ExtensionRunningLocation, WebWorkerExtHostConfigValue } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
@@ -48,6 +47,7 @@ import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/w
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
private readonly _enableLocalWebWorker: boolean;
|
||||
private readonly _lazyLocalWebWorker: boolean;
|
||||
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
|
||||
private readonly _extensionScanner: CachedExtensionScanner;
|
||||
|
||||
@@ -65,7 +65,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@IWebExtensionsScannerService webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@INativeHostService private readonly _nativeHostService: INativeHostService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
|
||||
@@ -89,10 +89,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
extensionManifestPropertiesService
|
||||
extensionManifestPropertiesService,
|
||||
webExtensionsScannerService
|
||||
);
|
||||
|
||||
this._enableLocalWebWorker = this._isLocalWebWorkerEnabled();
|
||||
[this._enableLocalWebWorker, this._lazyLocalWebWorker] = this._isLocalWebWorkerEnabled();
|
||||
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
|
||||
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
|
||||
|
||||
@@ -110,14 +111,26 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
});
|
||||
}
|
||||
|
||||
private _isLocalWebWorkerEnabled() {
|
||||
if (this._configurationService.getValue<boolean>(webWorkerExtHostConfig)) {
|
||||
return true;
|
||||
}
|
||||
private _isLocalWebWorkerEnabled(): [boolean, boolean] {
|
||||
let isEnabled: boolean;
|
||||
let isLazy: boolean;
|
||||
if (this._environmentService.isExtensionDevelopment && this._environmentService.extensionDevelopmentKind?.some(k => k === 'web')) {
|
||||
return true;
|
||||
isEnabled = true;
|
||||
isLazy = false;
|
||||
} else {
|
||||
const config = this._configurationService.getValue<WebWorkerExtHostConfigValue>(webWorkerExtHostConfig);
|
||||
if (config === true) {
|
||||
isEnabled = true;
|
||||
isLazy = false;
|
||||
} else if (config === 'auto') {
|
||||
isEnabled = true;
|
||||
isLazy = true;
|
||||
} else {
|
||||
isEnabled = false;
|
||||
isLazy = false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return [isEnabled, isLazy];
|
||||
}
|
||||
|
||||
protected _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
|
||||
@@ -131,7 +144,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
|
||||
return flatten(await Promise.all([
|
||||
this._extensionScanner.scannedExtensions,
|
||||
this._webExtensionsScannerService.scanAndTranslateExtensions().then(extensions => extensions.map(parseScannedExtension))
|
||||
this._scanWebExtensions(),
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -220,7 +233,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
result.push(localProcessExtHost);
|
||||
|
||||
if (this._enableLocalWebWorker) {
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
|
||||
const webWorkerExtHost = this._instantiationService.createInstance(WebWorkerExtensionHost, this._lazyLocalWebWorker, this._createLocalExtensionHostDataProvider(isInitialStart, ExtensionRunningLocation.LocalWebWorker));
|
||||
result.push(webWorkerExtHost);
|
||||
}
|
||||
|
||||
@@ -233,7 +246,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
protected override _onExtensionHostCrashed(extensionHost: IExtensionHostManager, code: number, signal: string | null): void {
|
||||
const activatedExtensions = Array.from(this._extensionHostActiveExtensions.values());
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
|
||||
@@ -307,16 +320,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
// --- impl
|
||||
|
||||
private createLogger(): Logger {
|
||||
return new Logger((severity, source, message) => {
|
||||
if (this._isDev && source) {
|
||||
this._logOrShowMessage(severity, `[${source}]: ${message}`);
|
||||
} else {
|
||||
this._logOrShowMessage(severity, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async _resolveAuthorityAgain(): Promise<void> {
|
||||
const remoteAuthority = this._environmentService.remoteAuthority;
|
||||
if (!remoteAuthority) {
|
||||
|
||||
@@ -67,6 +67,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
public readonly kind = ExtensionHostKind.LocalProcess;
|
||||
public readonly remoteAuthority = null;
|
||||
public readonly lazyStart = false;
|
||||
|
||||
private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>();
|
||||
public readonly onExit: Event<[number, string]> = this._onExit.event;
|
||||
@@ -238,7 +239,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
}
|
||||
|
||||
// Run Extension Host as fork of current process
|
||||
this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost'], opts);
|
||||
this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost', '--skipWorkspaceStorageLock'], opts);
|
||||
|
||||
// Catch all output coming from the extension host process
|
||||
type Output = { data: string, format: string[] };
|
||||
@@ -471,6 +472,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
isExtensionDevelopmentDebug: this._isExtensionDevDebug,
|
||||
appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined,
|
||||
appName: this._productService.nameLong,
|
||||
embedderIdentifier: this._productService.embedderIdentifier || 'desktop',
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nativeWatchdog from 'native-watchdog';
|
||||
import * as net from 'net';
|
||||
import * as minimist from 'minimist';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { PersistentProtocol, ProtocolConstants, BufferedEmitter } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
@@ -22,12 +22,14 @@ import { Promises } from 'vs/base/node/pfs';
|
||||
import { realpath } from 'vs/base/node/extpath';
|
||||
import { IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { boolean } from 'vs/editor/common/config/editorOptions';
|
||||
|
||||
import 'vs/workbench/api/common/extHost.common.services';
|
||||
import 'vs/workbench/api/node/extHost.node.services';
|
||||
|
||||
interface ParsedExtHostArgs {
|
||||
uriTransformerPath?: string;
|
||||
skipWorkspaceStorageLock?: boolean;
|
||||
useHostProxy?: string;
|
||||
}
|
||||
|
||||
@@ -46,6 +48,9 @@ const args = minimist(process.argv.slice(2), {
|
||||
string: [
|
||||
'uriTransformerPath',
|
||||
'useHostProxy'
|
||||
],
|
||||
boolean: [
|
||||
'skipWorkspaceStorageLock'
|
||||
]
|
||||
}) as ParsedExtHostArgs;
|
||||
|
||||
@@ -245,11 +250,13 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
|
||||
if (idx >= 0) {
|
||||
promise.catch(e => {
|
||||
unhandledPromises.splice(idx, 1);
|
||||
console.warn(`rejected promise not handled within 1 second: ${e}`);
|
||||
if (e && e.stack) {
|
||||
console.warn(`stack trace: ${e.stack}`);
|
||||
if (!isPromiseCanceledError(e)) {
|
||||
console.warn(`rejected promise not handled within 1 second: ${e}`);
|
||||
if (e && e.stack) {
|
||||
console.warn(`stack trace: ${e.stack}`);
|
||||
}
|
||||
onUnexpectedError(reason);
|
||||
}
|
||||
onUnexpectedError(reason);
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
@@ -321,6 +328,7 @@ export async function startExtensionHostProcess(): Promise<void> {
|
||||
// setup things
|
||||
patchProcess(!!initData.environment.extensionTestsLocationURI); // to support other test frameworks like Jasmin that use process.exit (https://github.com/microsoft/vscode/issues/37708)
|
||||
initData.environment.useHostProxy = args.useHostProxy !== undefined ? args.useHostProxy !== 'false' : undefined;
|
||||
initData.environment.skipWorkspaceStorageLock = boolean(args.skipWorkspaceStorageLock, false);
|
||||
|
||||
// host abstraction
|
||||
const hostUtils = new class NodeHost implements IHostUtils {
|
||||
|
||||
@@ -91,6 +91,21 @@ class ExtensionManifestParser extends ExtensionManifestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
interface MessageBag {
|
||||
[key: string]: string | { message: string; comment: string[] };
|
||||
}
|
||||
|
||||
interface TranslationBundle {
|
||||
contents: {
|
||||
package: MessageBag;
|
||||
};
|
||||
}
|
||||
|
||||
interface LocalizedMessages {
|
||||
values: MessageBag | undefined;
|
||||
default: string | null;
|
||||
}
|
||||
|
||||
class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
||||
|
||||
private readonly _nlsConfig: NlsConfiguration;
|
||||
@@ -101,21 +116,6 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
||||
}
|
||||
|
||||
public replaceNLS(extensionDescription: IExtensionDescription): Promise<IExtensionDescription> {
|
||||
interface MessageBag {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
interface TranslationBundle {
|
||||
contents: {
|
||||
package: MessageBag;
|
||||
};
|
||||
}
|
||||
|
||||
interface LocalizedMessages {
|
||||
values: MessageBag | undefined;
|
||||
default: string | null;
|
||||
}
|
||||
|
||||
const reportErrors = (localized: string | null, errors: json.ParseError[]): void => {
|
||||
errors.forEach((error) => {
|
||||
this._log.error(this._absoluteFolderPath, nls.localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized, getParseErrorMessage(error.error)));
|
||||
@@ -250,21 +250,22 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
||||
* This routine makes the following assumptions:
|
||||
* The root element is an object literal
|
||||
*/
|
||||
private static _replaceNLStrings<T extends object>(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void {
|
||||
private static _replaceNLStrings<T extends object>(nlsConfig: NlsConfiguration, literal: T, messages: MessageBag, originalMessages: MessageBag | null, log: ILog, messageScope: string): void {
|
||||
function processEntry(obj: any, key: string | number, command?: boolean) {
|
||||
let value = obj[key];
|
||||
const value = obj[key];
|
||||
if (types.isString(value)) {
|
||||
let str = <string>value;
|
||||
let length = str.length;
|
||||
const str = <string>value;
|
||||
const length = str.length;
|
||||
if (length > 1 && str[0] === '%' && str[length - 1] === '%') {
|
||||
let messageKey = str.substr(1, length - 2);
|
||||
let message = messages[messageKey];
|
||||
const messageKey = str.substr(1, length - 2);
|
||||
let translated = messages[messageKey];
|
||||
// If the messages come from a language pack they might miss some keys
|
||||
// Fill them from the original messages.
|
||||
if (message === undefined && originalMessages) {
|
||||
message = originalMessages[messageKey];
|
||||
if (translated === undefined && originalMessages) {
|
||||
translated = originalMessages[messageKey];
|
||||
}
|
||||
if (message) {
|
||||
let message: string | undefined = typeof translated === 'string' ? translated : (typeof translated?.message === 'string' ? translated.message : undefined);
|
||||
if (message !== undefined) {
|
||||
if (nlsConfig.pseudo) {
|
||||
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
|
||||
message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
|
||||
import { ExtensionRunningPreference } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
suite('BrowserExtensionService', () => {
|
||||
test('pickRunningLocation', () => {
|
||||
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
|
||||
test.skip('pickRunningLocation', () => { // {{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);
|
||||
@@ -84,6 +85,5 @@ suite('BrowserExtensionService', () => {
|
||||
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);
|
||||
*/
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IExtensionManifest, ExtensionKind, ExtensionUntrustedWorkpaceSupportType } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionManifest, ExtensionUntrustedWorkspaceSupportType } 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';
|
||||
@@ -12,49 +12,77 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { TestWorkspaceTrustManagementService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
|
||||
import { IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { TestWorkspaceTrustEnablementService } from 'vs/workbench/services/workspaces/test/common/testWorkspaceTrustService';
|
||||
import { IWorkspaceTrustEnablementService } from 'vs/platform/workspace/common/workspaceTrust';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtensionManifestPropertiesService - ExtensionKind', () => {
|
||||
|
||||
function check(manifest: Partial<IExtensionManifest>, expected: ExtensionKind[]): void {
|
||||
const extensionManifestPropertiesService = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustManagementService());
|
||||
assert.deepStrictEqual(extensionManifestPropertiesService.deduceExtensionKind(<IExtensionManifest>manifest), expected);
|
||||
}
|
||||
let testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService(), new TestWorkspaceTrustEnablementService(), new NullLogService());
|
||||
|
||||
test('declarative with extension dependencies => workspace', () => {
|
||||
check({ extensionDependencies: ['ext1'] }, ['workspace']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionDependencies: ['ext1'] }), ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative extension pack => workspace', () => {
|
||||
check({ extensionPack: ['ext1', 'ext2'] }, ['workspace']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'] }), ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative with unknown contribution point => workspace', () => {
|
||||
check({ contributes: <any>{ 'unknownPoint': { something: true } } }, ['workspace']);
|
||||
test('declarative extension pack and extension dependencies => workspace', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'], extensionDependencies: ['ext1', 'ext2'] }), ['workspace']);
|
||||
});
|
||||
|
||||
test('declarative with unknown contribution point => workspace, web', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ contributes: <any>{ 'unknownPoint': { something: true } } }), ['workspace', 'web']);
|
||||
});
|
||||
|
||||
test('declarative extension pack with unknown contribution point => workspace', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionPack: ['ext1', 'ext2'], contributes: <any>{ 'unknownPoint': { something: true } } }), ['workspace']);
|
||||
});
|
||||
|
||||
test('simple declarative => ui, workspace, web', () => {
|
||||
check({}, ['ui', 'workspace', 'web']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{}), ['ui', 'workspace', 'web']);
|
||||
});
|
||||
|
||||
test('only browser => web', () => {
|
||||
check({ browser: 'main.browser.js' }, ['web']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js' }), ['web']);
|
||||
});
|
||||
|
||||
test('only main => workspace', () => {
|
||||
check({ main: 'main.js' }, ['workspace']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js' }), ['workspace']);
|
||||
});
|
||||
|
||||
test('main and browser => workspace, web', () => {
|
||||
check({ main: 'main.js', browser: 'main.browser.js' }, ['workspace', 'web']);
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js', browser: 'main.browser.js' }), ['workspace', 'web']);
|
||||
});
|
||||
|
||||
test('browser entry point with workspace extensionKind => workspace, web', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ main: 'main.js', browser: 'main.browser.js', extensionKind: ['workspace'] }), ['workspace', 'web']);
|
||||
});
|
||||
|
||||
test('simple descriptive with workspace, ui extensionKind => workspace, ui, web', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ extensionKind: ['workspace', 'ui'] }), ['workspace', 'ui', 'web']);
|
||||
});
|
||||
|
||||
test('opt out from web through settings even if it can run in web', () => {
|
||||
testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService());
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['ui', 'workspace']);
|
||||
});
|
||||
|
||||
test('opt out from web and include only workspace through settings even if it can run in web', () => {
|
||||
testObject = new ExtensionManifestPropertiesService(TestProductService, new TestConfigurationService({ remote: { extensionKind: { 'pub.a': ['-web', 'workspace'] } } }), new TestWorkspaceTrustEnablementService(), new NullLogService());
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<IExtensionManifest>{ browser: 'main.browser.js', publisher: 'pub', name: 'a' }), ['workspace']);
|
||||
});
|
||||
|
||||
test('extension cannot opt out from web', () => {
|
||||
assert.deepStrictEqual(testObject.getExtensionKind(<any>{ browser: 'main.browser.js', extensionKind: ['-web'] }), ['web']);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Workspace Trust is disabled in web at the moment
|
||||
if (!isWeb) {
|
||||
suite('ExtensionManifestPropertiesService - ExtensionUntrustedWorkpaceSupportType', () => {
|
||||
suite('ExtensionManifestPropertiesService - ExtensionUntrustedWorkspaceSupportType', () => {
|
||||
let testObject: ExtensionManifestPropertiesService;
|
||||
let instantiationService: TestInstantiationService;
|
||||
let testConfigurationService: TestConfigurationService;
|
||||
@@ -64,12 +92,11 @@ if (!isWeb) {
|
||||
|
||||
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 {
|
||||
function assertUntrustedWorkspaceSupport(extensionMaifest: IExtensionManifest, expected: ExtensionUntrustedWorkspaceSupportType): void {
|
||||
testObject = instantiationService.createInstance(ExtensionManifestPropertiesService);
|
||||
const untrustedWorkspaceSupport = testObject.getExtensionUntrustedWorkspaceSupportType(extensionMaifest);
|
||||
|
||||
@@ -82,7 +109,7 @@ if (!isWeb) {
|
||||
|
||||
test('test extension workspace trust request when main entry point is missing', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest();
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
@@ -90,58 +117,92 @@ if (!isWeb) {
|
||||
|
||||
test('test extension workspace trust request when workspace trust is disabled', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService(false));
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService(false));
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in settings.json', async () => {
|
||||
test('test extension workspace trust request when "true" override exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { '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 () => {
|
||||
test('test extension workspace trust request when override (false) exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: false } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override (true) for the version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { '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 (false) for the version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { 'pub.a': { supported: false, version: '1.0.0' } } });
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override for a different version exists in settings.json', async () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
await testConfigurationService.setUserConfiguration('extensions', { supportUntrustedWorkspaces: { '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', () => {
|
||||
test('test extension workspace trust request when default (true) exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: true } } });
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, true);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override exists in product.json', () => {
|
||||
test('test extension workspace trust request when default (false) exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { default: false } } });
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override (limited) exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: 'limited' } } });
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when override (false) exists in product.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{ extensionUntrustedWorkspaceSupport: { 'pub.a': { override: false } } });
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: true } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
});
|
||||
|
||||
test('test extension workspace trust request when value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js', capabilities: { untrustedWorkspaces: { supported: 'limited' } } });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, 'limited');
|
||||
@@ -149,7 +210,7 @@ if (!isWeb) {
|
||||
|
||||
test('test extension workspace trust request when no value exists in package.json', () => {
|
||||
instantiationService.stub(IProductService, <Partial<IProductService>>{});
|
||||
instantiationService.stub(IWorkspaceTrustManagementService, new TestWorkspaceTrustManagementService());
|
||||
instantiationService.stub(IWorkspaceTrustEnablementService, new TestWorkspaceTrustEnablementService());
|
||||
|
||||
const extensionMaifest = getExtensionManifest({ main: './out/extension.js' });
|
||||
assertUntrustedWorkspaceSupport(extensionMaifest, false);
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { ProxyIdentifier, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
@@ -211,4 +211,31 @@ suite('RPCProtocol', () => {
|
||||
bProxy.$m(badObject, '2');
|
||||
});
|
||||
});
|
||||
|
||||
test('SerializableObjectWithBuffers is correctly transfered', function (done) {
|
||||
delegate = (a1: SerializableObjectWithBuffers<{ string: string, buff: VSBuffer }>, a2: number) => {
|
||||
return new SerializableObjectWithBuffers({ string: a1.value.string + ' world', buff: a1.value.buff });
|
||||
};
|
||||
|
||||
const b = VSBuffer.alloc(4);
|
||||
b.buffer[0] = 1;
|
||||
b.buffer[1] = 2;
|
||||
b.buffer[2] = 3;
|
||||
b.buffer[3] = 4;
|
||||
|
||||
bProxy.$m(new SerializableObjectWithBuffers({ string: 'hello', buff: b }), undefined).then((res: SerializableObjectWithBuffers<any>) => {
|
||||
assert.ok(res instanceof SerializableObjectWithBuffers);
|
||||
assert.strictEqual(res.value.string, 'hello world');
|
||||
|
||||
assert.ok(res.value.buff instanceof VSBuffer);
|
||||
|
||||
const bufferValues = Array.from(res.value.buff.buffer);
|
||||
|
||||
assert.strictEqual(bufferValues[0], 1);
|
||||
assert.strictEqual(bufferValues[1], 2);
|
||||
assert.strictEqual(bufferValues[2], 3);
|
||||
assert.strictEqual(bufferValues[3], 4);
|
||||
done(null);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,8 @@ import * as performance from 'vs/base/common/performance';
|
||||
|
||||
import 'vs/workbench/api/common/extHost.common.services';
|
||||
import 'vs/workbench/api/worker/extHost.worker.services';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
//#region --- Define, capture, and override some globals
|
||||
|
||||
@@ -29,6 +31,7 @@ declare namespace self {
|
||||
let dispatchEvent: any;
|
||||
let indexedDB: { open: any, [k: string]: any };
|
||||
let caches: { open: any, [k: string]: any };
|
||||
let importScripts: any;
|
||||
}
|
||||
|
||||
const nativeClose = self.close.bind(self);
|
||||
@@ -37,6 +40,8 @@ self.close = () => console.trace(`'close' has been blocked`);
|
||||
const nativePostMessage = postMessage.bind(self);
|
||||
self.postMessage = () => console.trace(`'postMessage' has been blocked`);
|
||||
|
||||
self.importScripts = () => { throw new Error(`'importScripts' has been blocked`); };
|
||||
|
||||
// const nativeAddEventListener = addEventListener.bind(self);
|
||||
self.addEventListener = () => console.trace(`'addEventListener' has been blocked`);
|
||||
|
||||
@@ -55,7 +60,15 @@ if ((<any>self).Worker) {
|
||||
// make sure new Worker(...) always uses blob: (to maintain current origin)
|
||||
const _Worker = (<any>self).Worker;
|
||||
Worker = <any>function (stringUrl: string | URL, options?: WorkerOptions) {
|
||||
const js = `importScripts('${stringUrl}');`;
|
||||
if (/^file:/i.test(stringUrl.toString())) {
|
||||
stringUrl = FileAccess.asBrowserUri(URI.parse(stringUrl.toString())).toString(true);
|
||||
}
|
||||
const js = `(function() {
|
||||
const ttPolicy = self.trustedTypes ? self.trustedTypes.createPolicy('extensionHostWorker', { createScriptURL: (value) => value }) : undefined;
|
||||
const stringUrl = '${stringUrl}';
|
||||
importScripts(ttPolicy ? ttPolicy.createScriptURL(stringUrl) : stringUrl);
|
||||
})();
|
||||
`;
|
||||
options = options || {};
|
||||
options.name = options.name || path.basename(stringUrl.toString());
|
||||
const blob = new Blob([js], { type: 'application/javascript' });
|
||||
@@ -150,7 +163,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
|
||||
|
||||
let onTerminate = (reason: string) => nativeClose();
|
||||
|
||||
(function create(): void {
|
||||
export function create(): void {
|
||||
const res = new ExtensionWorker();
|
||||
performance.mark(`code/extHost/willConnectToRenderer`);
|
||||
connectToRenderer(res.protocol).then(data => {
|
||||
@@ -164,4 +177,4 @@ let onTerminate = (reason: string) => nativeClose();
|
||||
|
||||
onTerminate = (reason: string) => extHostMain.terminate(reason);
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
(function () {
|
||||
|
||||
const MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
const monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../../../';
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
})();
|
||||
@@ -1,13 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-LU+tuagpyx5mKuYgHsSvz9593ZGS6yeLPRvzq1lKXlY=' http: https:; connect-src http: https: ws: wss:" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=' http: https:; connect-src http: https: ws: wss:" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {
|
||||
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
|
||||
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
|
||||
const searchParams = new URL(document.location).searchParams;
|
||||
const vscodeWebWorkerExtHostId = searchParams.get('vscodeWebWorkerExtHostId') || '';
|
||||
const name = searchParams.get('debugged') ? 'WorkerExtensionHost' : 'DebugWorkerExtensionHost';
|
||||
|
||||
function sendError(error) {
|
||||
window.parent.postMessage({
|
||||
@@ -21,7 +22,8 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
|
||||
const worker = new Worker('../../../../base/worker/workerMain.js', { name });
|
||||
worker.postMessage('vs/workbench/services/extensions/worker/extensionHostWorker');
|
||||
const nestedWorkers = new Map();
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-LU+tuagpyx5mKuYgHsSvz9593ZGS6yeLPRvzq1lKXlY=' https:; connect-src https: wss:" />
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data: blob:; script-src 'unsafe-eval' 'sha256-cb2sg39EJV8ABaSNFfWu/ou8o1xVXYK7jp90oZ9vpcg=' https:; connect-src https: wss:" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {
|
||||
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
|
||||
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
|
||||
const searchParams = new URL(document.location).searchParams;
|
||||
const vscodeWebWorkerExtHostId = searchParams.get('vscodeWebWorkerExtHostId') || '';
|
||||
const name = searchParams.get('debugged') ? 'WorkerExtensionHost' : 'DebugWorkerExtensionHost';
|
||||
|
||||
function sendError(error) {
|
||||
window.parent.postMessage({
|
||||
@@ -21,7 +22,8 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
|
||||
const worker = new Worker('../../../../base/worker/workerMain.js', { name });
|
||||
worker.postMessage('vs/workbench/services/extensions/worker/extensionHostWorker');
|
||||
const nestedWorkers = new Map();
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
|
||||
Reference in New Issue
Block a user