mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79 (#14050)
* Merge from vscode 2c306f762bf9c3db82dc06c7afaa56ef46d72f79 * Fix breaks * Extension management fixes * Fix breaks in windows bundling * Fix/skip failing tests * Update distro * Add clear to nuget.config * Add hygiene task * Bump distro * Fix hygiene issue * Add build to hygiene exclusion * Update distro * Update hygiene * Hygiene exclusions * Update tsconfig * Bump distro for server breaks * Update build config * Update darwin path * Add done calls to notebook tests * Skip failing tests * Disable smoke tests
This commit is contained in:
@@ -9,29 +9,30 @@ 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, ExtensionHostKind } 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, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { RemoteExtensionHost, IRemoteExtensionHostDataProvider, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionKind, IExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { FetchFileSystemProvider } from 'vs/workbench/services/extensions/browser/webWorkerFileSystemProvider';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IUserDataInitializationService } from 'vs/workbench/services/userData/browser/userDataInit';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
private _disposables = new DisposableStore();
|
||||
private _remoteInitData: IRemoteExtensionHostInitData | null = null;
|
||||
private _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -41,14 +42,20 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IProductService productService: IProductService,
|
||||
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IConfigurationService private readonly _configService: IConfigurationService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IUserDataInitializationService private readonly _userDataInitializationService: IUserDataInitializationService,
|
||||
) {
|
||||
super(
|
||||
new ExtensionRunningLocationClassifier(
|
||||
productService,
|
||||
configurationService,
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely) => ExtensionService.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely)
|
||||
),
|
||||
instantiationService,
|
||||
notificationService,
|
||||
environmentService,
|
||||
@@ -56,15 +63,15 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
extensionEnablementService,
|
||||
fileService,
|
||||
productService,
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
);
|
||||
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
// Initialize extensions first and do it only after workbench is ready
|
||||
this._lifecycleService.when(LifecyclePhase.Ready).then(async () => {
|
||||
await this._userDataInitializationService.initializeExtensions(this._instantiationService);
|
||||
this._initialize();
|
||||
});
|
||||
// Initialize only after workbench is ready
|
||||
this._lifecycleService.when(LifecyclePhase.Ready).then(() => this._initialize());
|
||||
|
||||
this._initFetchFileSystem();
|
||||
}
|
||||
@@ -74,6 +81,33 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
protected _onExtensionHostCrashed(extensionHost: ExtensionHostManager, code: number, signal: string | null): void {
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalWebWorker) {
|
||||
if (code === ExtensionHostExitCode.StartTimeout10s) {
|
||||
this._notificationService.prompt(
|
||||
Severity.Error,
|
||||
nls.localize('extensionService.startTimeout', "The Web Worker Extension Host did not start in 10s."),
|
||||
[]
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
|
||||
if (extension.location.scheme === Schemas.vscodeRemote) {
|
||||
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
|
||||
}
|
||||
|
||||
const scannedExtension = await this._webExtensionsScannerService.scanAndTranslateSingleExtension(extension.location, extension.type);
|
||||
if (scannedExtension) {
|
||||
return parseScannedExtension(scannedExtension);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private _initFetchFileSystem(): void {
|
||||
const provider = new FetchFileSystemProvider();
|
||||
this._disposables.add(this._fileService.registerProvider(Schemas.http, provider));
|
||||
@@ -103,6 +137,25 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
};
|
||||
}
|
||||
|
||||
public static pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean): ExtensionRunningLocation {
|
||||
let canRunRemotely = false;
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledRemotely) {
|
||||
// ui extensions run remotely if possible (but only as a last resort)
|
||||
canRunRemotely = true;
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
return (canRunRemotely ? ExtensionRunningLocation.Remote : ExtensionRunningLocation.None);
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(_isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
@@ -129,7 +182,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
remoteExtensions = this._checkEnabledAndProposedAPI(remoteExtensions);
|
||||
|
||||
const remoteAgentConnection = this._remoteAgentService.getConnection();
|
||||
this._runningLocation = _determineRunningLocation(this._productService, this._configService, localExtensions, remoteExtensions, Boolean(remoteEnv && remoteAgentConnection));
|
||||
this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions);
|
||||
|
||||
localExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalWebWorker);
|
||||
remoteExtensions = filterByRunningLocation(remoteExtensions, this._runningLocation, ExtensionRunningLocation.Remote);
|
||||
@@ -164,53 +217,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
}
|
||||
|
||||
const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export function determineRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], allExtensionKinds: Map<string, ExtensionKind[]>, hasRemote: boolean): Map<string, ExtensionRunningLocation> {
|
||||
const localExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const remoteExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const extensionKinds = allExtensionKinds.get(ExtensionIdentifier.toKey(extension.identifier)) || [];
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledRemotely) {
|
||||
// ui extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
return ExtensionRunningLocation.None;
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
return runningLocation;
|
||||
}
|
||||
|
||||
function _determineRunningLocation(productService: IProductService, configurationService: IConfigurationService, localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], hasRemote: boolean): Map<string, ExtensionRunningLocation> {
|
||||
const allExtensionKinds = new Map<string, ExtensionKind[]>();
|
||||
localExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, productService, configurationService)));
|
||||
remoteExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, productService, configurationService)));
|
||||
return determineRunningLocation(localExtensions, remoteExtensions, allExtensionKinds, hasRemote);
|
||||
}
|
||||
|
||||
function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === desiredRunningLocation);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { IWorkbenchExtensionEnablementService, EnablementState } from 'vs/workbe
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IURLHandler, IURLService, IOpenURLOptions } from 'vs/platform/url/common/url';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -21,28 +21,30 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
|
||||
|
||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||
const THIRTY_SECONDS = 30 * 1000;
|
||||
const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle';
|
||||
const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds';
|
||||
const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions';
|
||||
const USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds';
|
||||
const USER_TRUSTED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions';
|
||||
|
||||
function isExtensionId(value: string): boolean {
|
||||
return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value);
|
||||
}
|
||||
|
||||
class ConfirmedExtensionIdStorage {
|
||||
class UserTrustedExtensionIdStorage {
|
||||
|
||||
get extensions(): string[] {
|
||||
const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]');
|
||||
const userTrustedExtensionIdsJson = this.storageService.get(USER_TRUSTED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]');
|
||||
|
||||
try {
|
||||
return JSON.parse(confirmedExtensionIdsJson);
|
||||
return JSON.parse(userTrustedExtensionIdsJson);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
@@ -59,7 +61,7 @@ class ConfirmedExtensionIdStorage {
|
||||
}
|
||||
|
||||
set(ids: string[]): void {
|
||||
this.storageService.store(CONFIRMED_EXTENSIONS_STORAGE_KEY, JSON.stringify(ids), StorageScope.GLOBAL);
|
||||
this.storageService.store(USER_TRUSTED_EXTENSIONS_STORAGE_KEY, JSON.stringify(ids), StorageScope.GLOBAL, StorageTarget.MACHINE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +88,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
|
||||
private extensionHandlers = new Map<string, IURLHandler>();
|
||||
private uriBuffer = new Map<string, { timestamp: number, uri: URI }[]>();
|
||||
private storage: ConfirmedExtensionIdStorage;
|
||||
private userTrustedExtensionsStorage: UserTrustedExtensionIdStorage;
|
||||
private disposable: IDisposable;
|
||||
|
||||
constructor(
|
||||
@@ -100,9 +102,10 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IProgressService private readonly progressService: IProgressService
|
||||
@IProgressService private readonly progressService: IProgressService,
|
||||
@IExtensionUrlTrustService private readonly extensionUrlTrustService: IExtensionUrlTrustService
|
||||
) {
|
||||
this.storage = new ConfirmedExtensionIdStorage(storageService);
|
||||
this.userTrustedExtensionsStorage = new UserTrustedExtensionIdStorage(storageService);
|
||||
|
||||
const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS);
|
||||
const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE);
|
||||
@@ -117,7 +120,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
);
|
||||
|
||||
const cache = ExtensionUrlBootstrapHandler.cache;
|
||||
setTimeout(() => cache.forEach(uri => this.handleURL(uri)));
|
||||
setTimeout(() => cache.forEach(([uri, option]) => this.handleURL(uri, option)));
|
||||
}
|
||||
|
||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||
@@ -134,14 +137,11 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
let showConfirm: boolean;
|
||||
if (options && options.trusted) {
|
||||
showConfirm = false;
|
||||
} else {
|
||||
showConfirm = !this.isConfirmed(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
const trusted = options?.trusted
|
||||
|| (options?.originalUrl ? await this.extensionUrlTrustService.isExtensionUrlTrusted(extensionId, options.originalUrl) : false)
|
||||
|| this.didUserTrustExtension(ExtensionIdentifier.toKey(extensionId));
|
||||
|
||||
if (showConfirm) {
|
||||
if (!trusted) {
|
||||
let uriString = uri.toString(false);
|
||||
|
||||
// {{SQL CARBON EDIT}} - Begin
|
||||
@@ -171,7 +171,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
}
|
||||
|
||||
if (result.checkboxChecked) {
|
||||
this.storage.add(ExtensionIdentifier.toKey(extensionId));
|
||||
this.userTrustedExtensionsStorage.add(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
}
|
||||
|
||||
private async reloadAndHandle(url: URI): Promise<void> {
|
||||
this.storageService.store(URL_TO_HANDLE, JSON.stringify(url.toJSON()), StorageScope.WORKSPACE);
|
||||
this.storageService.store(URL_TO_HANDLE, JSON.stringify(url.toJSON()), StorageScope.WORKSPACE, StorageTarget.MACHINE);
|
||||
await this.hostService.reload();
|
||||
}
|
||||
|
||||
@@ -320,22 +320,22 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler {
|
||||
this.uriBuffer = uriBuffer;
|
||||
}
|
||||
|
||||
private isConfirmed(id: string): boolean {
|
||||
if (this.storage.has(id)) {
|
||||
private didUserTrustExtension(id: string): boolean {
|
||||
if (this.userTrustedExtensionsStorage.has(id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.getConfirmedExtensionIdsFromConfiguration().indexOf(id) > -1;
|
||||
return this.getConfirmedTrustedExtensionIdsFromConfiguration().indexOf(id) > -1;
|
||||
}
|
||||
|
||||
private getConfirmedExtensionIdsFromConfiguration(): Array<string> {
|
||||
const confirmedExtensionIds = this.configurationService.getValue<Array<string>>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY);
|
||||
private getConfirmedTrustedExtensionIdsFromConfiguration(): Array<string> {
|
||||
const trustedExtensionIds = this.configurationService.getValue<Array<string>>(USER_TRUSTED_EXTENSIONS_CONFIGURATION_KEY);
|
||||
|
||||
if (!Array.isArray(confirmedExtensionIds)) {
|
||||
if (!Array.isArray(trustedExtensionIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return confirmedExtensionIds;
|
||||
return trustedExtensionIds;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -353,10 +353,10 @@ registerSingleton(IExtensionUrlHandler, ExtensionUrlHandler);
|
||||
*/
|
||||
class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandler {
|
||||
|
||||
private static _cache: URI[] = [];
|
||||
private static _cache: [URI, IOpenURLOptions | undefined][] = [];
|
||||
private static disposable: IDisposable;
|
||||
|
||||
static get cache(): URI[] {
|
||||
static get cache(): [URI, IOpenURLOptions | undefined][] {
|
||||
ExtensionUrlBootstrapHandler.disposable.dispose();
|
||||
|
||||
const result = ExtensionUrlBootstrapHandler._cache;
|
||||
@@ -368,12 +368,12 @@ class ExtensionUrlBootstrapHandler implements IWorkbenchContribution, IURLHandle
|
||||
ExtensionUrlBootstrapHandler.disposable = urlService.registerHandler(this);
|
||||
}
|
||||
|
||||
async handleURL(uri: URI): Promise<boolean> {
|
||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||
if (!isExtensionId(uri.authority)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtensionUrlBootstrapHandler._cache.push(uri);
|
||||
ExtensionUrlBootstrapHandler._cache.push([uri, options]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -388,19 +388,21 @@ class ManageAuthorizedExtensionURIsAction extends Action2 {
|
||||
id: 'workbench.extensions.action.manageAuthorizedExtensionURIs',
|
||||
title: { value: localize('manage', "Manage Authorized Extension URIs..."), original: 'Manage Authorized Extension URIs...' },
|
||||
category: { value: localize('extensions', "Extensions"), original: 'Extensions' },
|
||||
f1: true
|
||||
menu: {
|
||||
id: MenuId.CommandPalette,
|
||||
when: IsWebContext.toNegated()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const storageService = accessor.get(IStorageService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
|
||||
const storage = new ConfirmedExtensionIdStorage(storageService);
|
||||
|
||||
const storage = new UserTrustedExtensionIdStorage(storageService);
|
||||
const items = storage.extensions.map(label => ({ label, picked: true } as IQuickPickItem));
|
||||
|
||||
if (items.length === 0) {
|
||||
await quickInputService.pick([{ label: localize('no', 'There are currently no authorized extension URIs.') }]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ 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';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { createMessageOfType, MessageType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { createMessageOfType, MessageType, isMessageOfType, ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
@@ -27,8 +27,9 @@ import { IOutputChannelRegistry, Extensions } from 'vs/workbench/services/output
|
||||
import { localize } from 'vs/nls';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { canceled, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { WEB_WORKER_IFRAME } from 'vs/workbench/services/extensions/common/webWorkerIframe';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
|
||||
|
||||
export interface IWebWorkerExtensionHostInitData {
|
||||
readonly autoStart: boolean;
|
||||
@@ -62,19 +63,56 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@ILayoutService private readonly _layoutService: ILayoutService,
|
||||
) {
|
||||
super();
|
||||
this._isTerminating = false;
|
||||
this._protocolPromise = null;
|
||||
this._protocol = null;
|
||||
this._extensionHostLogsLocation = URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme });
|
||||
this._extensionHostLogsLocation = joinPath(this._environmentService.extHostLogsPath, 'webWorker');
|
||||
this._extensionHostLogFile = joinPath(this._extensionHostLogsLocation, `${ExtensionHostLogFileName}.log`);
|
||||
}
|
||||
|
||||
private _wrapInIframe(): boolean {
|
||||
if (this._environmentService.options && typeof this._environmentService.options._wrapWebWorkerExtHostInIframe === 'boolean') {
|
||||
return this._environmentService.options._wrapWebWorkerExtHostInIframe;
|
||||
}
|
||||
// wrap in <iframe> by default
|
||||
return true;
|
||||
}
|
||||
|
||||
private _webWorkerExtensionHostIframeSrc(): string | null {
|
||||
if (this._environmentService.options && this._environmentService.options.webWorkerExtensionHostIframeSrc) {
|
||||
return this._environmentService.options.webWorkerExtensionHostIframeSrc;
|
||||
}
|
||||
if (this._productService.webEndpointUrl) {
|
||||
const forceHTTPS = (location.protocol === 'https:');
|
||||
let baseUrl = this._productService.webEndpointUrl;
|
||||
if (this._productService.quality) {
|
||||
baseUrl += `/${this._productService.quality}`;
|
||||
}
|
||||
if (this._productService.commit) {
|
||||
baseUrl += `/${this._productService.commit}`;
|
||||
}
|
||||
return (
|
||||
forceHTTPS
|
||||
? `${baseUrl}/out/vs/workbench/services/extensions/worker/httpsWebWorkerExtensionHostIframe.html`
|
||||
: `${baseUrl}/out/vs/workbench/services/extensions/worker/httpWebWorkerExtensionHostIframe.html`
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async start(): Promise<IMessagePassingProtocol> {
|
||||
if (!this._protocolPromise) {
|
||||
if (platform.isWeb && this._environmentService.options && this._environmentService.options._wrapWebWorkerExtHostInIframe) {
|
||||
this._protocolPromise = this._startInsideIframe();
|
||||
if (platform.isWeb) {
|
||||
const webWorkerExtensionHostIframeSrc = this._webWorkerExtensionHostIframeSrc();
|
||||
if (webWorkerExtensionHostIframeSrc && this._wrapInIframe()) {
|
||||
this._protocolPromise = this._startInsideIframe(webWorkerExtensionHostIframeSrc);
|
||||
} else {
|
||||
console.warn(`The web worker extension host is started without an iframe sandbox!`);
|
||||
this._protocolPromise = this._startOutsideIframe();
|
||||
}
|
||||
} else {
|
||||
this._protocolPromise = this._startOutsideIframe();
|
||||
}
|
||||
@@ -83,37 +121,41 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
return this._protocolPromise;
|
||||
}
|
||||
|
||||
private async _startInsideIframe(): Promise<IMessagePassingProtocol> {
|
||||
private async _startInsideIframe(webWorkerExtensionHostIframeSrc: string): Promise<IMessagePassingProtocol> {
|
||||
const emitter = this._register(new Emitter<VSBuffer>());
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('class', 'web-worker-ext-host-iframe');
|
||||
iframe.setAttribute('sandbox', 'allow-scripts');
|
||||
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
|
||||
iframe.style.display = 'none';
|
||||
|
||||
const vscodeWebWorkerExtHostId = generateUuid();
|
||||
const workerUrl = require.toUrl('../worker/extensionHostWorkerMain.js');
|
||||
const workerSrc = getWorkerBootstrapUrl(workerUrl, 'WorkerExtensionHost', true);
|
||||
const escapeAttribute = (value: string): string => {
|
||||
return value.replace(/"/g, '"');
|
||||
};
|
||||
const isBuilt = this._environmentService.isBuilt;
|
||||
const html = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-eval' '${WEB_WORKER_IFRAME.sha}' ${isBuilt ? 'https:' : 'http: https:'}; worker-src data:; connect-src ${isBuilt ? 'https:' : 'http: https:'}" />
|
||||
<meta id="vscode-worker-src" data-value="${escapeAttribute(workerSrc)}" />
|
||||
<meta id="vscode-web-worker-ext-host-id" data-value="${escapeAttribute(vscodeWebWorkerExtHostId)}" />
|
||||
</head>
|
||||
<body>
|
||||
<script>${WEB_WORKER_IFRAME.js}</script>
|
||||
</body>
|
||||
</html>`;
|
||||
const iframeContent = `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
|
||||
iframe.setAttribute('src', iframeContent);
|
||||
iframe.setAttribute('src', `${webWorkerExtensionHostIframeSrc}?vscodeWebWorkerExtHostId=${vscodeWebWorkerExtHostId}`);
|
||||
|
||||
const barrier = new Barrier();
|
||||
let port!: MessagePort;
|
||||
let barrierError: Error | null = null;
|
||||
let barrierHasError = false;
|
||||
let startTimeout: any = null;
|
||||
|
||||
const rejectBarrier = (exitCode: number, error: Error) => {
|
||||
barrierError = error;
|
||||
barrierHasError = true;
|
||||
onUnexpectedError(barrierError);
|
||||
clearTimeout(startTimeout);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, barrierError.message]);
|
||||
barrier.open();
|
||||
};
|
||||
|
||||
const resolveBarrier = (messagePort: MessagePort) => {
|
||||
port = messagePort;
|
||||
clearTimeout(startTimeout);
|
||||
barrier.open();
|
||||
};
|
||||
|
||||
startTimeout = setTimeout(() => {
|
||||
rejectBarrier(ExtensionHostExitCode.StartTimeout10s, new Error('The Web Worker Extension Host did not start in 10s'));
|
||||
}, 10000);
|
||||
|
||||
this._register(dom.addDisposableListener(window, 'message', (event) => {
|
||||
if (event.source !== iframe.contentWindow) {
|
||||
@@ -128,27 +170,28 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
err.message = message;
|
||||
err.name = name;
|
||||
err.stack = stack;
|
||||
onUnexpectedError(err);
|
||||
this._onDidExit.fire([18, err.message]);
|
||||
return;
|
||||
return rejectBarrier(ExtensionHostExitCode.UnexpectedError, err);
|
||||
}
|
||||
const { data } = event.data;
|
||||
if (barrier.isOpen() || !(data instanceof MessagePort)) {
|
||||
console.warn('UNEXPECTED message', event);
|
||||
this._onDidExit.fire([81, 'UNEXPECTED message']);
|
||||
return;
|
||||
const err = new Error('UNEXPECTED message');
|
||||
return rejectBarrier(ExtensionHostExitCode.UnexpectedError, err);
|
||||
}
|
||||
port = data;
|
||||
barrier.open();
|
||||
resolveBarrier(data);
|
||||
}));
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
this._layoutService.container.appendChild(iframe);
|
||||
this._register(toDisposable(() => iframe.remove()));
|
||||
|
||||
// await MessagePort and use it to directly communicate
|
||||
// with the worker extension host
|
||||
await barrier.wait();
|
||||
|
||||
if (barrierHasError) {
|
||||
throw barrierError;
|
||||
}
|
||||
|
||||
port.onmessage = (event) => {
|
||||
const { data } = event;
|
||||
if (!(data instanceof ArrayBuffer)) {
|
||||
@@ -173,7 +216,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
private async _startOutsideIframe(): Promise<IMessagePassingProtocol> {
|
||||
const emitter = new Emitter<VSBuffer>();
|
||||
|
||||
const url = getWorkerBootstrapUrl(require.toUrl('../worker/extensionHostWorkerMain.js'), 'WorkerExtensionHost');
|
||||
const url = getWorkerBootstrapUrl(FileAccess.asBrowserUri('../worker/extensionHostWorkerMain.js', require).toString(true), 'WorkerExtensionHost');
|
||||
const worker = new Worker(url, { name: 'WorkerExtensionHost' });
|
||||
|
||||
const barrier = new Barrier();
|
||||
@@ -183,7 +226,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
const { data } = event;
|
||||
if (barrier.isOpen() || !(data instanceof MessagePort)) {
|
||||
console.warn('UNEXPECTED message', event);
|
||||
this._onDidExit.fire([81, 'UNEXPECTED message']);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, 'UNEXPECTED message']);
|
||||
return;
|
||||
}
|
||||
port = data;
|
||||
@@ -207,7 +250,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
|
||||
worker.onerror = (event) => {
|
||||
console.error(event.message, event.error);
|
||||
this._onDidExit.fire([81, event.message || event.error]);
|
||||
this._onDidExit.fire([ExtensionHostExitCode.UnexpectedError, event.message || event.error]);
|
||||
};
|
||||
|
||||
// keep for cleanup
|
||||
@@ -278,7 +321,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
vscodeVersion: this._productService.vscodeVersion, // {{SQL CARBON EDIT}} add vscode version
|
||||
parentPid: -1,
|
||||
environment: {
|
||||
isExtensionDevelopmentDebug: false, //todo@jrieken web
|
||||
isExtensionDevelopmentDebug: this._environmentService.debugRenderer,
|
||||
appName: this._productService.nameLong,
|
||||
appUriScheme: this._productService.urlProtocol,
|
||||
appLanguage: platform.language,
|
||||
@@ -303,7 +346,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
|
||||
logFile: this._extensionHostLogFile,
|
||||
autoStart: initData.autoStart,
|
||||
remote: {
|
||||
authority: this._environmentService.configuration.remoteAuthority,
|
||||
authority: this._environmentService.remoteAuthority,
|
||||
connectionData: null,
|
||||
isRemote: false
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -15,16 +16,22 @@ import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionM
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension, IExtensionHost, ActivationKind, ExtensionHostKind } 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 } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription, ExtensionType, ITranslatedScannedExtension, IExtension, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
|
||||
@@ -33,12 +40,27 @@ export function parseScannedExtension(extension: ITranslatedScannedExtension): I
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(`${extension.packageJSON.publisher}.${extension.packageJSON.name}`),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
extensionLocation: extension.location,
|
||||
...extension.packageJSON,
|
||||
};
|
||||
}
|
||||
|
||||
class DeltaExtensionsQueueItem {
|
||||
constructor(
|
||||
public readonly toAdd: IExtension[],
|
||||
public readonly toRemove: string[]
|
||||
) { }
|
||||
}
|
||||
|
||||
export const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export abstract class AbstractExtensionService extends Disposable implements IExtensionService {
|
||||
|
||||
public _serviceBrand: undefined;
|
||||
@@ -66,6 +88,9 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
private readonly _proposedApiController: ProposedApiController;
|
||||
private readonly _isExtensionDevHost: boolean;
|
||||
protected readonly _isExtensionDevTestFromCli: boolean;
|
||||
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
|
||||
private _inHandleDeltaExtensions: boolean;
|
||||
protected _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
|
||||
// --- Members used per extension host process
|
||||
protected _extensionHostManagers: ExtensionHostManager[];
|
||||
@@ -74,13 +99,17 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
private _extensionHostExtensionRuntimeErrors: Map<string, Error[]>;
|
||||
|
||||
constructor(
|
||||
protected readonly _runningLocationClassifier: ExtensionRunningLocationClassifier,
|
||||
@IInstantiationService protected readonly _instantiationService: IInstantiationService,
|
||||
@INotificationService protected readonly _notificationService: INotificationService,
|
||||
@IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@ITelemetryService protected readonly _telemetryService: ITelemetryService,
|
||||
@IWorkbenchExtensionEnablementService protected readonly _extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IFileService protected readonly _fileService: IFileService,
|
||||
@IProductService protected readonly _productService: IProductService
|
||||
@IProductService protected readonly _productService: IProductService,
|
||||
@IExtensionManagementService protected readonly _extensionManagementService: IExtensionManagementService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IConfigurationService protected readonly _configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -103,8 +132,280 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
const devOpts = parseExtensionDevOptions(this._environmentService);
|
||||
this._isExtensionDevHost = devOpts.isExtensionDevHost;
|
||||
this._isExtensionDevTestFromCli = devOpts.isExtensionDevTestFromCli;
|
||||
|
||||
this._deltaExtensionsQueue = [];
|
||||
this._inHandleDeltaExtensions = false;
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
this._register(this._extensionEnablementService.onEnablementChanged((extensions) => {
|
||||
let toAdd: IExtension[] = [];
|
||||
let toRemove: string[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (this._safeInvokeIsEnabled(extension)) {
|
||||
// an extension has been enabled
|
||||
toAdd.push(extension);
|
||||
} else {
|
||||
// an extension has been disabled
|
||||
toRemove.push(extension.identifier.id);
|
||||
}
|
||||
}
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
|
||||
if (event.local) {
|
||||
if (this._safeInvokeIsEnabled(event.local)) {
|
||||
// an extension has been installed
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
|
||||
if (!event.error) {
|
||||
// an extension has been uninstalled
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id]));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
return extensionHostManager;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//#region deltaExtensions
|
||||
|
||||
private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise<void> {
|
||||
this._deltaExtensionsQueue.push(item);
|
||||
if (this._inHandleDeltaExtensions) {
|
||||
// Let the current item finish, the new one will be picked up
|
||||
return;
|
||||
}
|
||||
|
||||
while (this._deltaExtensionsQueue.length > 0) {
|
||||
const item = this._deltaExtensionsQueue.shift()!;
|
||||
try {
|
||||
this._inHandleDeltaExtensions = true;
|
||||
await this._deltaExtensions(item.toAdd, item.toRemove);
|
||||
} finally {
|
||||
this._inHandleDeltaExtensions = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
|
||||
let toAdd: IExtensionDescription[] = [];
|
||||
for (let i = 0, len = _toAdd.length; i < len; i++) {
|
||||
const extension = _toAdd[i];
|
||||
|
||||
if (!this._canAddExtension(extension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const extensionDescription = await this._scanSingleExtension(extension);
|
||||
if (!extensionDescription) {
|
||||
// could not scan extension...
|
||||
continue;
|
||||
}
|
||||
|
||||
toAdd.push(extensionDescription);
|
||||
}
|
||||
|
||||
let toRemove: IExtensionDescription[] = [];
|
||||
for (let i = 0, len = _toRemove.length; i < len; i++) {
|
||||
const extensionId = _toRemove[i];
|
||||
const extensionDescription = this._registry.getExtensionDescription(extensionId);
|
||||
if (!extensionDescription) {
|
||||
// ignore disabling/uninstalling an extension which is not running
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.canRemoveExtension(extensionDescription)) {
|
||||
// uses non-dynamic extension point or is activated
|
||||
continue;
|
||||
}
|
||||
|
||||
toRemove.push(extensionDescription);
|
||||
}
|
||||
|
||||
if (toAdd.length === 0 && toRemove.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the local registry
|
||||
const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
|
||||
this._onDidChangeExtensions.fire(undefined);
|
||||
|
||||
toRemove = toRemove.concat(result.removedDueToLooping);
|
||||
if (result.removedDueToLooping.length > 0) {
|
||||
this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', ')));
|
||||
}
|
||||
|
||||
// enable or disable proposed API per extension
|
||||
this._checkEnableProposedApi(toAdd);
|
||||
|
||||
// Update extension points
|
||||
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
|
||||
|
||||
// Update the extension host
|
||||
await this._updateExtensionsOnExtHosts(toAdd, toRemove.map(e => e.identifier));
|
||||
|
||||
for (let i = 0; i < toAdd.length; i++) {
|
||||
this._activateAddedExtensionIfNeeded(toAdd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private async _updateExtensionsOnExtHosts(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
const groupedToRemove: ExtensionIdentifier[][] = [];
|
||||
const groupRemove = (extensionHostKind: ExtensionHostKind, extensionRunningLocation: ExtensionRunningLocation) => {
|
||||
groupedToRemove[extensionHostKind] = filterByRunningLocation(toRemove, extId => extId, this._runningLocation, extensionRunningLocation);
|
||||
};
|
||||
groupRemove(ExtensionHostKind.LocalProcess, ExtensionRunningLocation.LocalProcess);
|
||||
groupRemove(ExtensionHostKind.LocalWebWorker, ExtensionRunningLocation.LocalWebWorker);
|
||||
groupRemove(ExtensionHostKind.Remote, ExtensionRunningLocation.Remote);
|
||||
for (const extensionId of toRemove) {
|
||||
this._runningLocation.delete(ExtensionIdentifier.toKey(extensionId));
|
||||
}
|
||||
|
||||
const groupedToAdd: IExtensionDescription[][] = [];
|
||||
const groupAdd = (extensionHostKind: ExtensionHostKind, extensionRunningLocation: ExtensionRunningLocation) => {
|
||||
groupedToAdd[extensionHostKind] = filterByRunningLocation(toAdd, ext => ext.identifier, this._runningLocation, extensionRunningLocation);
|
||||
};
|
||||
for (const extension of toAdd) {
|
||||
const extensionKind = getExtensionKind(extension, this._productService, this._configurationService);
|
||||
const isRemote = extension.extensionLocation.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote);
|
||||
this._runningLocation.set(ExtensionIdentifier.toKey(extension.identifier), runningLocation);
|
||||
}
|
||||
groupAdd(ExtensionHostKind.LocalProcess, ExtensionRunningLocation.LocalProcess);
|
||||
groupAdd(ExtensionHostKind.LocalWebWorker, ExtensionRunningLocation.LocalWebWorker);
|
||||
groupAdd(ExtensionHostKind.Remote, ExtensionRunningLocation.Remote);
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
for (const extensionHostKind of [ExtensionHostKind.LocalProcess, ExtensionHostKind.LocalWebWorker, ExtensionHostKind.Remote]) {
|
||||
const toAdd = groupedToAdd[extensionHostKind];
|
||||
const toRemove = groupedToRemove[extensionHostKind];
|
||||
if (toAdd.length > 0 || toRemove.length > 0) {
|
||||
const extensionHostManager = this._getExtensionHostManager(extensionHostKind);
|
||||
if (extensionHostManager) {
|
||||
promises.push(extensionHostManager.deltaExtensions(toAdd, toRemove));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
|
||||
return this._canAddExtension(toExtension(extensionDescription));
|
||||
}
|
||||
|
||||
private _canAddExtension(extension: IExtension): boolean {
|
||||
const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id);
|
||||
if (extensionDescription) {
|
||||
// this extension is already running (most likely at a different version)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if extension is renamed
|
||||
if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extensionKind = getExtensionKind(extension.manifest, this._productService, this._configurationService);
|
||||
const isRemote = extension.location.scheme === Schemas.vscodeRemote;
|
||||
const runningLocation = this._runningLocationClassifier.pickRunningLocation(extensionKind, !isRemote, isRemote);
|
||||
if (runningLocation === ExtensionRunningLocation.None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public canRemoveExtension(extension: IExtensionDescription): boolean {
|
||||
const extensionDescription = this._registry.getExtensionDescription(extension.identifier);
|
||||
if (!extensionDescription) {
|
||||
// ignore removing an extension which is not running
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this._extensionHostActiveExtensions.has(ExtensionIdentifier.toKey(extensionDescription.identifier))) {
|
||||
// Extension is running, cannot remove it safely
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _activateAddedExtensionIfNeeded(extensionDescription: IExtensionDescription): Promise<void> {
|
||||
let shouldActivate = false;
|
||||
let shouldActivateReason: string | null = null;
|
||||
let hasWorkspaceContains = false;
|
||||
if (Array.isArray(extensionDescription.activationEvents)) {
|
||||
for (let activationEvent of extensionDescription.activationEvents) {
|
||||
// TODO@joao: there's no easy way to contribute this
|
||||
if (activationEvent === 'onUri') {
|
||||
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
|
||||
}
|
||||
|
||||
if (this._allRequestedActivateEvents.has(activationEvent)) {
|
||||
// This activation event was fired before the extension was added
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (activationEvent === '*') {
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (/^workspaceContains/.test(activationEvent)) {
|
||||
hasWorkspaceContains = true;
|
||||
}
|
||||
|
||||
if (activationEvent === 'onStartupFinished') {
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldActivate) {
|
||||
await Promise.all(
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
|
||||
).then(() => { });
|
||||
} else if (hasWorkspaceContains) {
|
||||
const workspace = await this._contextService.getCompleteWorkspace();
|
||||
const forceUsingSearch = !!this._environmentService.remoteAuthority;
|
||||
const host: IWorkspaceContainsActivationHost = {
|
||||
folders: workspace.folders.map(folder => folder.uri),
|
||||
forceUsingSearch: forceUsingSearch,
|
||||
exists: (uri) => this._fileService.exists(uri),
|
||||
checkExists: (folders, includes, token) => this._instantiationService.invokeFunction((accessor) => checkGlobFileExists(accessor, folders, includes, token))
|
||||
};
|
||||
|
||||
const result = await checkActivateWorkspaceContainsExtension(host, extensionDescription);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: result.activationEvent }))
|
||||
).then(() => { });
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
protected async _initialize(): Promise<void> {
|
||||
perf.mark('willLoadExtensions');
|
||||
this._startExtensionHosts(true, []);
|
||||
@@ -169,14 +470,6 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
//#region IExtensionService
|
||||
|
||||
public canAddExtension(extension: IExtensionDescription): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public canRemoveExtension(extension: IExtensionDescription): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
public restartExtensionHost(): void {
|
||||
this._stopExtensionHosts();
|
||||
this._startExtensionHosts(false, Array.from(this._allRequestedActivateEvents.keys()));
|
||||
@@ -325,7 +618,15 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._extensionEnablementService.isEnabled(toExtension(extension));
|
||||
return this._safeInvokeIsEnabled(toExtension(extension));
|
||||
}
|
||||
|
||||
protected _safeInvokeIsEnabled(extension: IExtension): boolean {
|
||||
try {
|
||||
return this._extensionEnablementService.isEnabled(extension);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void {
|
||||
@@ -463,9 +764,43 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
|
||||
protected abstract _createExtensionHosts(isInitialStart: boolean): IExtensionHost[];
|
||||
protected abstract _scanAndHandleExtensions(): Promise<void>;
|
||||
protected abstract _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null>;
|
||||
public abstract _onExtensionHostExit(code: number): void;
|
||||
}
|
||||
|
||||
export class ExtensionRunningLocationClassifier {
|
||||
constructor(
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
public readonly pickRunningLocation: (extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean) => ExtensionRunningLocation,
|
||||
) {
|
||||
}
|
||||
|
||||
public determineRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[]): Map<string, ExtensionRunningLocation> {
|
||||
const allExtensionKinds = new Map<string, ExtensionKind[]>();
|
||||
localExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, this._productService, this._configurationService)));
|
||||
remoteExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, this._productService, this._configurationService)));
|
||||
|
||||
const localExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const remoteExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const extensionKinds = allExtensionKinds.get(ExtensionIdentifier.toKey(extension.identifier)) || [];
|
||||
return this.pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely);
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
return runningLocation;
|
||||
}
|
||||
}
|
||||
|
||||
class ProposedApiController {
|
||||
|
||||
private readonly enableProposedApiFor: string[];
|
||||
@@ -473,16 +808,16 @@ class ProposedApiController {
|
||||
private readonly productAllowProposedApi: Set<string>;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IProductService productService: IProductService
|
||||
) {
|
||||
// Make enabled proposed API be lowercase for case insensitive comparison
|
||||
this.enableProposedApiFor = (environmentService.extensionEnabledProposedApi || []).map(id => id.toLowerCase());
|
||||
this.enableProposedApiFor = (_environmentService.extensionEnabledProposedApi || []).map(id => id.toLowerCase());
|
||||
|
||||
this.enableProposedApiForAll =
|
||||
!environmentService.isBuilt || // always allow proposed API when running out of sources
|
||||
(!!environmentService.extensionDevelopmentLocationURI && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
|
||||
(this.enableProposedApiFor.length === 0 && Array.isArray(environmentService.extensionEnabledProposedApi)); // always allow proposed API if --enable-proposed-api is provided without extension ID
|
||||
!_environmentService.isBuilt || // always allow proposed API when running out of sources
|
||||
(!!_environmentService.extensionDevelopmentLocationURI && productService.quality !== 'stable') || // do not allow proposed API against stable builds when developing an extension
|
||||
(this.enableProposedApiFor.length === 0 && Array.isArray(_environmentService.extensionEnabledProposedApi)); // always allow proposed API if --enable-proposed-api is provided without extension ID
|
||||
|
||||
this.productAllowProposedApi = new Set<string>();
|
||||
if (isNonEmptyArray(productService.extensionAllowedProposedApi)) {
|
||||
@@ -504,7 +839,7 @@ class ProposedApiController {
|
||||
extension.enableProposedApi = false;
|
||||
console.error(`Extension '${extension.identifier.value} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`);
|
||||
|
||||
} else {
|
||||
} else if (this._environmentService.isBuilt) {
|
||||
// proposed api is available when developing or when an extension was explicitly
|
||||
// spelled out via a command line argument
|
||||
console.warn(`Extension '${extension.identifier.value}' uses PROPOSED API which is subject to change and removal without notice.`);
|
||||
@@ -516,3 +851,7 @@ class ProposedApiController {
|
||||
return this.productAllowProposedApi.has(ExtensionIdentifier.toKey(id));
|
||||
}
|
||||
}
|
||||
|
||||
function filterByRunningLocation<T>(extensions: T[], extId: (item: T) => ExtensionIdentifier, runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): T[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(extId(ext))) === desiredRunningLocation);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IExtHostRpcService, ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IURITransformerService, URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
|
||||
import { IExtHostExtensionService, IHostUtils } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
|
||||
export interface IExitFn {
|
||||
(code?: number): any;
|
||||
@@ -59,15 +60,16 @@ export class ExtensionHostMain {
|
||||
|
||||
const instaService: IInstantiationService = new InstantiationService(services, true);
|
||||
|
||||
// todo@joh
|
||||
// ugly self - inject
|
||||
const terminalService = instaService.invokeFunction(accessor => accessor.get(IExtHostTerminalService));
|
||||
this._disposables.add(terminalService);
|
||||
|
||||
const logService = instaService.invokeFunction(accessor => accessor.get(ILogService));
|
||||
this._disposables.add(logService);
|
||||
|
||||
logService.info('extension host started');
|
||||
logService.trace('initData', initData);
|
||||
|
||||
// todo@joh
|
||||
// ugly self - inject
|
||||
// must call initialize *after* creating the extension service
|
||||
// because `initialize` itself creates instances that depend on it
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -23,6 +22,7 @@ import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
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';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
@@ -267,7 +267,8 @@ export class ExtensionHostManager extends Disposable {
|
||||
authority: {
|
||||
authority: remoteAuthority,
|
||||
host: pieces[0],
|
||||
port: parseInt(pieces[1], 10)
|
||||
port: parseInt(pieces[1], 10),
|
||||
connectionToken: undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -345,7 +346,7 @@ class RPCLogger implements IRPCProtocolLogger {
|
||||
|
||||
const colorTable = colorTables[initiator];
|
||||
const color = LOG_USE_COLORS ? colorTable[req % colorTable.length] : '#000000';
|
||||
let args = [`%c[${direction}]%c[${strings.pad(totalLength, 7, ' ')}]%c[len: ${strings.pad(msgLength, 5, ' ')}]%c${strings.pad(req, 5, ' ')} - ${str}`, 'color: darkgreen', 'color: grey', 'color: grey', `color: ${color}`];
|
||||
let args = [`%c[${direction}]%c[${String(totalLength).padStart(7)}]%c[len: ${String(msgLength).padStart(5)}]%c${String(req).padStart(5)} - ${str}`, 'color: darkgreen', 'color: grey', 'color: grey', `color: ${color}`];
|
||||
if (/\($/.test(str)) {
|
||||
args = args.concat(data);
|
||||
args.push(')');
|
||||
@@ -405,7 +406,7 @@ registerAction2(class MeasureExtHostLatencyAction extends Action2 {
|
||||
value: nls.localize('measureExtHostLatency', "Measure Extension Host Latency"),
|
||||
original: 'Measure Extension Host Latency'
|
||||
},
|
||||
category: { value: nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"), original: 'Developer' },
|
||||
category: CATEGORIES.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
export const enum ExtensionHostExitCode {
|
||||
// nodejs uses codes 1-13 and exit codes >128 are signal exits
|
||||
VersionMismatch = 55,
|
||||
StartTimeout10s = 56,
|
||||
UnexpectedError = 81,
|
||||
}
|
||||
|
||||
export interface IExtHostReadyMessage {
|
||||
type: 'VSCODE_EXTHOST_IPC_READY';
|
||||
}
|
||||
|
||||
@@ -273,6 +273,7 @@ export function throwProposedApiError(extension: IExtensionDescription): never {
|
||||
export function toExtension(extensionDescription: IExtensionDescription): IExtension {
|
||||
return {
|
||||
type: extensionDescription.isBuiltin ? ExtensionType.System : ExtensionType.User,
|
||||
isBuiltin: extensionDescription.isBuiltin || extensionDescription.isUserBuiltin,
|
||||
identifier: { id: getGalleryExtensionId(extensionDescription.publisher, extensionDescription.name), uuid: extensionDescription.uuid },
|
||||
manifest: extensionDescription,
|
||||
location: extensionDescription.extensionLocation,
|
||||
@@ -283,6 +284,7 @@ export function toExtensionDescription(extension: IExtension): IExtensionDescrip
|
||||
return {
|
||||
identifier: new ExtensionIdentifier(extension.identifier.id),
|
||||
isBuiltin: extension.type === ExtensionType.System,
|
||||
isUserBuiltin: extension.type === ExtensionType.User && extension.isBuiltin,
|
||||
isUnderDevelopment: false,
|
||||
extensionLocation: extension.location,
|
||||
...extension.manifest,
|
||||
|
||||
@@ -19,9 +19,9 @@ import { IRemoteAuthorityResolverService, IRemoteConnectionData } from 'vs/platf
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
@@ -92,7 +92,7 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
addressProvider: {
|
||||
getAddress: async () => {
|
||||
const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority);
|
||||
return { host: authority.host, port: authority.port };
|
||||
return { host: authority.host, port: authority.port, connectionToken: authority.connectionToken };
|
||||
}
|
||||
},
|
||||
signService: this._signService,
|
||||
@@ -205,8 +205,15 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
||||
const [telemetryInfo, remoteInitData] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]);
|
||||
|
||||
// Collect all identifiers for extension ids which can be considered "resolved"
|
||||
const remoteExtensions = new Set<string>();
|
||||
remoteInitData.extensions.forEach((extension) => remoteExtensions.add(ExtensionIdentifier.toKey(extension.identifier.value)));
|
||||
|
||||
const resolvedExtensions = remoteInitData.allExtensions.filter(extension => !extension.main && !extension.browser).map(extension => extension.identifier);
|
||||
const hostExtensions = remoteInitData.allExtensions.filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier);
|
||||
const hostExtensions = (
|
||||
remoteInitData.allExtensions
|
||||
.filter(extension => !remoteExtensions.has(ExtensionIdentifier.toKey(extension.identifier.value)))
|
||||
.filter(extension => (extension.main || extension.browser) && extension.api === 'none').map(extension => extension.identifier)
|
||||
);
|
||||
const workspace = this._contextService.getWorkspace();
|
||||
return {
|
||||
commit: this._productService.commit,
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const WEB_WORKER_IFRAME = {
|
||||
sha: 'sha256-r24mDVsMuFEo8ChaY9ppVJKbY3CUM4I12Aw/yscWZbg=',
|
||||
js: `
|
||||
(function() {
|
||||
const workerSrc = document.getElementById('vscode-worker-src').getAttribute('data-value');
|
||||
const worker = new Worker(workerSrc, { name: 'WorkerExtensionHost' });
|
||||
const vscodeWebWorkerExtHostId = document.getElementById('vscode-web-worker-ext-host-id').getAttribute('data-value');
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
const { data } = event;
|
||||
if (!(data instanceof MessagePort)) {
|
||||
console.warn('Unknown data received', event);
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
error: {
|
||||
name: 'Error',
|
||||
message: 'Unknown data received',
|
||||
stack: []
|
||||
}
|
||||
}, '*');
|
||||
return;
|
||||
}
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
data: data
|
||||
}, '*', [data]);
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
console.error(event.message, event.error);
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
error: {
|
||||
name: event.error ? event.error.name : '',
|
||||
message: event.error ? event.error.message : '',
|
||||
stack: event.error ? event.error.stack : []
|
||||
}
|
||||
}, '*');
|
||||
};
|
||||
})();
|
||||
`
|
||||
};
|
||||
@@ -4,17 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as os from 'os';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { FileAccess, Schemas } from 'vs/base/common/network';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { joinPath, originalFSPath } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
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';
|
||||
@@ -32,7 +29,7 @@ interface IExtensionCacheData {
|
||||
let _SystemExtensionsRoot: string | null = null;
|
||||
function getSystemExtensionsRoot(): string {
|
||||
if (!_SystemExtensionsRoot) {
|
||||
_SystemExtensionsRoot = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', 'extensions'));
|
||||
_SystemExtensionsRoot = path.normalize(path.join(FileAccess.asFileUri('', require).fsPath, '..', 'extensions'));
|
||||
}
|
||||
return _SystemExtensionsRoot;
|
||||
}
|
||||
@@ -40,7 +37,7 @@ function getSystemExtensionsRoot(): string {
|
||||
let _ExtraDevSystemExtensionsRoot: string | null = null;
|
||||
function getExtraDevSystemExtensionsRoot(): string {
|
||||
if (!_ExtraDevSystemExtensionsRoot) {
|
||||
_ExtraDevSystemExtensionsRoot = path.normalize(path.join(getPathFromAmdModule(require, ''), '..', '.build', 'builtInExtensions'));
|
||||
_ExtraDevSystemExtensionsRoot = path.normalize(path.join(FileAccess.asFileUri('', require).fsPath, '..', '.build', 'builtInExtensions'));
|
||||
}
|
||||
return _ExtraDevSystemExtensionsRoot;
|
||||
}
|
||||
@@ -54,7 +51,7 @@ export class CachedExtensionScanner {
|
||||
|
||||
constructor(
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
|
||||
@INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
|
||||
@IWorkbenchExtensionEnablementService private readonly _extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IProductService private readonly _productService: IProductService
|
||||
@@ -264,7 +261,7 @@ export class CachedExtensionScanner {
|
||||
if (devMode) {
|
||||
const builtInExtensions = Promise.resolve<IBuiltInExtension[]>(productService.builtInExtensions || []);
|
||||
|
||||
const controlFilePath = path.join(os.homedir(), '.vscode-oss-dev', 'extensions', 'control.json');
|
||||
const controlFilePath = joinPath(environmentService.userHome, '.vscode-oss-dev', 'extensions', 'control.json').fsPath;
|
||||
const controlFile = pfs.readFile(controlFilePath, 'utf8')
|
||||
.then<IBuiltInExtensionControl>(raw => JSON.parse(raw), () => ({} as any));
|
||||
|
||||
@@ -276,18 +273,14 @@ export class CachedExtensionScanner {
|
||||
finalBuiltinExtensions = ExtensionScanner.mergeBuiltinExtensions(builtinExtensions, extraBuiltinExtensions);
|
||||
}
|
||||
|
||||
const userExtensions = (
|
||||
extensionEnablementService.allUserExtensionsDisabled || !environmentService.extensionsPath
|
||||
? Promise.resolve([])
|
||||
: this._scanExtensionsWithCache(
|
||||
hostService,
|
||||
notificationService,
|
||||
environmentService,
|
||||
USER_MANIFEST_CACHE_FILE,
|
||||
new ExtensionScannerInput(version, commit, locale, devMode, environmentService.extensionsPath, false, false, translations),
|
||||
log
|
||||
)
|
||||
);
|
||||
const userExtensions = (this._scanExtensionsWithCache(
|
||||
hostService,
|
||||
notificationService,
|
||||
environmentService,
|
||||
USER_MANIFEST_CACHE_FILE,
|
||||
new ExtensionScannerInput(version, commit, locale, devMode, environmentService.extensionsPath, false, false, translations),
|
||||
log
|
||||
));
|
||||
|
||||
// Always load developed extensions while extensions development
|
||||
let developedExtensions: Promise<IExtensionDescription[]> = Promise.resolve([]);
|
||||
|
||||
@@ -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, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import { AbstractExtensionService, ExtensionRunningLocation, ExtensionRunningLocationClassifier, parseScannedExtension } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import * as nls from 'vs/nls';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
@@ -16,46 +16,36 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { getExtensionKind } from 'vs/workbench/services/extensions/common/extensionsUtil';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IExtensionService, toExtension, ExtensionHostKind, IExtensionHost, webWorkerExtHostConfig } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionHostManager } from 'vs/workbench/services/extensions/common/extensionHostManager';
|
||||
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription, ExtensionKind } from 'vs/platform/extensions/common/extensions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService';
|
||||
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
|
||||
import { WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost';
|
||||
import { IExtensionActivationHost as IWorkspaceContainsActivationHost, checkGlobFileExists, checkActivateWorkspaceContainsExtension } from 'vs/workbench/api/common/shared/workspaceContains';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { exists } from 'vs/base/node/pfs';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
class DeltaExtensionsQueueItem {
|
||||
constructor(
|
||||
public readonly toAdd: IExtension[],
|
||||
public readonly toRemove: string[]
|
||||
) { }
|
||||
}
|
||||
import { CATEGORIES } from 'vs/workbench/common/actions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
|
||||
export class ExtensionService extends AbstractExtensionService implements IExtensionService {
|
||||
|
||||
private readonly _enableLocalWebWorker: boolean;
|
||||
private readonly _remoteInitData: Map<string, IRemoteExtensionHostInitData>;
|
||||
private _runningLocation: Map<string, ExtensionRunningLocation>;
|
||||
private readonly _extensionScanner: CachedExtensionScanner;
|
||||
private _deltaExtensionsQueue: DeltaExtensionsQueueItem[];
|
||||
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -65,316 +55,63 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
@IWorkbenchExtensionEnablementService extensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IProductService productService: IProductService,
|
||||
@IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService,
|
||||
@IExtensionManagementService extensionManagementService: IExtensionManagementService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IWebExtensionsScannerService private readonly _webExtensionsScannerService: IWebExtensionsScannerService,
|
||||
@IElectronService private readonly _electronService: IElectronService,
|
||||
@INativeHostService private readonly _nativeHostService: INativeHostService,
|
||||
@IHostService private readonly _hostService: IHostService,
|
||||
@IRemoteExplorerService private readonly _remoteExplorerService: IRemoteExplorerService,
|
||||
@IExtensionGalleryService private readonly _extensionGalleryService: IExtensionGalleryService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
super(
|
||||
new ExtensionRunningLocationClassifier(
|
||||
productService,
|
||||
configurationService,
|
||||
(extensionKinds, isInstalledLocally, isInstalledRemotely) => this._pickRunningLocation(extensionKinds, isInstalledLocally, isInstalledRemotely)
|
||||
),
|
||||
instantiationService,
|
||||
notificationService,
|
||||
_environmentService,
|
||||
telemetryService,
|
||||
extensionEnablementService,
|
||||
fileService,
|
||||
productService
|
||||
productService,
|
||||
extensionManagementService,
|
||||
contextService,
|
||||
configurationService,
|
||||
);
|
||||
|
||||
this._enableLocalWebWorker = this._configurationService.getValue<boolean>(webWorkerExtHostConfig);
|
||||
|
||||
this._remoteInitData = new Map<string, IRemoteExtensionHostInitData>();
|
||||
this._runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
|
||||
this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner);
|
||||
this._deltaExtensionsQueue = [];
|
||||
|
||||
this._register(this._extensionEnablementService.onEnablementChanged((extensions) => {
|
||||
let toAdd: IExtension[] = [];
|
||||
let toRemove: string[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (this._extensionEnablementService.isEnabled(extension)) {
|
||||
// an extension has been enabled
|
||||
toAdd.push(extension);
|
||||
} else {
|
||||
// an extension has been disabled
|
||||
toRemove.push(extension.identifier.id);
|
||||
}
|
||||
}
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem(toAdd, toRemove));
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidInstallExtension((event) => {
|
||||
if (event.local) {
|
||||
if (this._extensionEnablementService.isEnabled(event.local)) {
|
||||
// an extension has been installed
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([event.local], []));
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._extensionManagementService.onDidUninstallExtension((event) => {
|
||||
if (!event.error) {
|
||||
// an extension has been uninstalled
|
||||
this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id]));
|
||||
}
|
||||
}));
|
||||
|
||||
// delay extension host creation and extension scanning
|
||||
// until the workbench is running. we cannot defer the
|
||||
// extension host more (LifecyclePhase.Restored) because
|
||||
// some editors require the extension host to restore
|
||||
// and this would result in a deadlock
|
||||
// see https://github.com/Microsoft/vscode/issues/41322
|
||||
// see https://github.com/microsoft/vscode/issues/41322
|
||||
this._lifecycleService.when(LifecyclePhase.Ready).then(() => {
|
||||
// reschedule to ensure this runs after restoring viewlets, panels, and editors
|
||||
runWhenIdle(() => {
|
||||
this._initialize();
|
||||
}, 50 /*max delay*/);
|
||||
});
|
||||
|
||||
// delay notification for extensions disabled until workbench restored
|
||||
if (this._extensionEnablementService.allUserExtensionsDisabled) {
|
||||
this._lifecycleService.when(LifecyclePhase.Restored).then(() => {
|
||||
this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{
|
||||
label: nls.localize('Reload', "Reload"),
|
||||
run: () => {
|
||||
this._hostService.reload();
|
||||
}
|
||||
}]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _getExtensionHostManager(kind: ExtensionHostKind): ExtensionHostManager | null {
|
||||
for (const extensionHostManager of this._extensionHostManagers) {
|
||||
if (extensionHostManager.kind === kind) {
|
||||
return extensionHostManager;
|
||||
}
|
||||
protected _scanSingleExtension(extension: IExtension): Promise<IExtensionDescription | null> {
|
||||
if (extension.location.scheme === Schemas.vscodeRemote) {
|
||||
return this._remoteAgentService.scanSingleExtension(extension.location, extension.type === ExtensionType.System);
|
||||
}
|
||||
return null;
|
||||
|
||||
return this._extensionScanner.scanSingleExtension(extension.location.fsPath, extension.type === ExtensionType.System, this.createLogger());
|
||||
}
|
||||
|
||||
//#region deltaExtensions
|
||||
|
||||
private _inHandleDeltaExtensions = false;
|
||||
private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise<void> {
|
||||
this._deltaExtensionsQueue.push(item);
|
||||
if (this._inHandleDeltaExtensions) {
|
||||
// Let the current item finish, the new one will be picked up
|
||||
return;
|
||||
}
|
||||
|
||||
while (this._deltaExtensionsQueue.length > 0) {
|
||||
const item = this._deltaExtensionsQueue.shift()!;
|
||||
try {
|
||||
this._inHandleDeltaExtensions = true;
|
||||
await this._deltaExtensions(item.toAdd, item.toRemove);
|
||||
} finally {
|
||||
this._inHandleDeltaExtensions = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
|
||||
if (this._environmentService.configuration.remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
|
||||
let toAdd: IExtensionDescription[] = [];
|
||||
for (let i = 0, len = _toAdd.length; i < len; i++) {
|
||||
const extension = _toAdd[i];
|
||||
|
||||
if (!this._canAddExtension(extension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const extensionDescription = await this._extensionScanner.scanSingleExtension(extension.location.fsPath, extension.type === ExtensionType.System, this.createLogger());
|
||||
if (!extensionDescription) {
|
||||
// could not scan extension...
|
||||
continue;
|
||||
}
|
||||
|
||||
toAdd.push(extensionDescription);
|
||||
}
|
||||
|
||||
let toRemove: IExtensionDescription[] = [];
|
||||
for (let i = 0, len = _toRemove.length; i < len; i++) {
|
||||
const extensionId = _toRemove[i];
|
||||
const extensionDescription = this._registry.getExtensionDescription(extensionId);
|
||||
if (!extensionDescription) {
|
||||
// ignore disabling/uninstalling an extension which is not running
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this._canRemoveExtension(extensionDescription)) {
|
||||
// uses non-dynamic extension point or is activated
|
||||
continue;
|
||||
}
|
||||
|
||||
toRemove.push(extensionDescription);
|
||||
}
|
||||
|
||||
if (toAdd.length === 0 && toRemove.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the local registry
|
||||
const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
|
||||
this._onDidChangeExtensions.fire(undefined);
|
||||
|
||||
toRemove = toRemove.concat(result.removedDueToLooping);
|
||||
if (result.removedDueToLooping.length > 0) {
|
||||
this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', ')));
|
||||
}
|
||||
|
||||
// enable or disable proposed API per extension
|
||||
this._checkEnableProposedApi(toAdd);
|
||||
|
||||
// Update extension points
|
||||
this._doHandleExtensionPoints((<IExtensionDescription[]>[]).concat(toAdd).concat(toRemove));
|
||||
|
||||
// Update the extension host
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess);
|
||||
if (localProcessExtensionHost) {
|
||||
await localProcessExtensionHost.deltaExtensions(toAdd, toRemove.map(e => e.identifier));
|
||||
}
|
||||
|
||||
for (let i = 0; i < toAdd.length; i++) {
|
||||
this._activateAddedExtensionIfNeeded(toAdd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public canAddExtension(extensionDescription: IExtensionDescription): boolean {
|
||||
return this._canAddExtension(toExtension(extensionDescription));
|
||||
}
|
||||
|
||||
private _canAddExtension(extension: IExtension): boolean {
|
||||
if (this._environmentService.configuration.remoteAuthority) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extension.location.scheme !== Schemas.file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// {{ SQL CARBON EDIT }}
|
||||
if (extension.manifest.forceReload) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id);
|
||||
if (extensionDescription) {
|
||||
// this extension is already running (most likely at a different version)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if extension is renamed
|
||||
if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public canRemoveExtension(extension: IExtensionDescription): boolean {
|
||||
if (this._environmentService.configuration.remoteAuthority) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extension.extensionLocation.scheme !== Schemas.file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const extensionDescription = this._registry.getExtensionDescription(extension.identifier);
|
||||
if (!extensionDescription) {
|
||||
// ignore removing an extension which is not running
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._canRemoveExtension(extensionDescription);
|
||||
}
|
||||
|
||||
private _canRemoveExtension(extension: IExtensionDescription): boolean {
|
||||
if (this._extensionHostActiveExtensions.has(ExtensionIdentifier.toKey(extension.identifier))) {
|
||||
// Extension is running, cannot remove it safely
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _activateAddedExtensionIfNeeded(extensionDescription: IExtensionDescription): Promise<void> {
|
||||
|
||||
let shouldActivate = false;
|
||||
let shouldActivateReason: string | null = null;
|
||||
let hasWorkspaceContains = false;
|
||||
if (Array.isArray(extensionDescription.activationEvents)) {
|
||||
for (let activationEvent of extensionDescription.activationEvents) {
|
||||
// TODO@joao: there's no easy way to contribute this
|
||||
if (activationEvent === 'onUri') {
|
||||
activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`;
|
||||
}
|
||||
|
||||
if (this._allRequestedActivateEvents.has(activationEvent)) {
|
||||
// This activation event was fired before the extension was added
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (activationEvent === '*') {
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
|
||||
if (/^workspaceContains/.test(activationEvent)) {
|
||||
hasWorkspaceContains = true;
|
||||
}
|
||||
|
||||
if (activationEvent === 'onStartupFinished') {
|
||||
shouldActivate = true;
|
||||
shouldActivateReason = activationEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldActivate) {
|
||||
await Promise.all(
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: shouldActivateReason! }))
|
||||
).then(() => { });
|
||||
} else if (hasWorkspaceContains) {
|
||||
const workspace = await this._contextService.getCompleteWorkspace();
|
||||
const forceUsingSearch = !!this._environmentService.configuration.remoteAuthority;
|
||||
const host: IWorkspaceContainsActivationHost = {
|
||||
folders: workspace.folders.map(folder => folder.uri),
|
||||
forceUsingSearch: forceUsingSearch,
|
||||
exists: (path) => exists(path),
|
||||
checkExists: (folders, includes, token) => this._instantiationService.invokeFunction((accessor) => checkGlobFileExists(accessor, folders, includes, token))
|
||||
};
|
||||
|
||||
const result = await checkActivateWorkspaceContainsExtension(host, extensionDescription);
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
this._extensionHostManagers.map(extHostManager => extHostManager.activate(extensionDescription.identifier, { startup: false, extensionId: extensionDescription.identifier, activationEvent: result.activationEvent }))
|
||||
).then(() => { });
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
private async _scanAllLocalExtensions(): Promise<IExtensionDescription[]> {
|
||||
return flatten(await Promise.all([
|
||||
this._extensionScanner.scannedExtensions,
|
||||
@@ -387,7 +124,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
getInitData: async () => {
|
||||
if (isInitialStart) {
|
||||
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
|
||||
const runningLocation = _determineRunningLocation(this._productService, this._configurationService, localExtensions, [], false, this._enableLocalWebWorker);
|
||||
const runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, []);
|
||||
const localProcessExtensions = filterByRunningLocation(localExtensions, runningLocation, desiredRunningLocation);
|
||||
return {
|
||||
autoStart: false,
|
||||
@@ -416,6 +153,28 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
};
|
||||
}
|
||||
|
||||
private _pickRunningLocation(extensionKinds: ExtensionKind[], isInstalledLocally: boolean, isInstalledRemotely: boolean): ExtensionRunningLocation {
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledLocally) {
|
||||
// ui extensions run locally if possible
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'workspace' && !this._environmentService.remoteAuthority) {
|
||||
// workspace extensions also run locally if there is no remote
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally && this._enableLocalWebWorker) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
return ExtensionRunningLocation.None;
|
||||
}
|
||||
|
||||
protected _createExtensionHosts(isInitialStart: boolean): IExtensionHost[] {
|
||||
const result: IExtensionHost[] = [];
|
||||
|
||||
@@ -441,7 +200,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
super._onExtensionHostCrashed(extensionHost, code, signal);
|
||||
|
||||
if (extensionHost.kind === ExtensionHostKind.LocalProcess) {
|
||||
if (code === 55) {
|
||||
if (code === ExtensionHostExitCode.VersionMismatch) {
|
||||
this._notificationService.prompt(
|
||||
Severity.Error,
|
||||
nls.localize('extensionService.versionMismatchCrash', "Extension host cannot start: version mismatch."),
|
||||
@@ -464,7 +223,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
this._notificationService.prompt(Severity.Error, nls.localize('extensionService.crash', "Extension host terminated unexpectedly."),
|
||||
[{
|
||||
label: nls.localize('devTools', "Open Developer Tools"),
|
||||
run: () => this._electronService.openDevTools()
|
||||
run: () => this._nativeHostService.openDevTools()
|
||||
},
|
||||
{
|
||||
label: nls.localize('restart', "Restart Extension Host"),
|
||||
@@ -503,7 +262,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
|
||||
private async _resolveAuthorityAgain(): Promise<void> {
|
||||
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
|
||||
const remoteAuthority = this._environmentService.remoteAuthority;
|
||||
if (!remoteAuthority) {
|
||||
return;
|
||||
}
|
||||
@@ -521,7 +280,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
protected async _scanAndHandleExtensions(): Promise<void> {
|
||||
this._extensionScanner.startScanningExtensions(this.createLogger());
|
||||
|
||||
const remoteAuthority = this._environmentService.configuration.remoteAuthority;
|
||||
const remoteAuthority = this._environmentService.remoteAuthority;
|
||||
const localProcessExtensionHost = this._getExtensionHostManager(ExtensionHostKind.LocalProcess)!;
|
||||
|
||||
const localExtensions = this._checkEnabledAndProposedAPI(await this._scanAllLocalExtensions());
|
||||
@@ -584,7 +343,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
|
||||
private async _startLocalExtensionHost(localExtensions: IExtensionDescription[], remoteAuthority: string | undefined = undefined, remoteEnv: IRemoteAgentEnvironment | null = null, remoteExtensions: IExtensionDescription[] = []): Promise<void> {
|
||||
|
||||
this._runningLocation = _determineRunningLocation(this._productService, this._configurationService, localExtensions, remoteExtensions, Boolean(remoteAuthority), this._enableLocalWebWorker);
|
||||
this._runningLocation = this._runningLocationClassifier.determineRunningLocation(localExtensions, remoteExtensions);
|
||||
|
||||
// remove non-UI extensions from the local extensions
|
||||
const localProcessExtensions = filterByRunningLocation(localExtensions, this._runningLocation, ExtensionRunningLocation.LocalProcess);
|
||||
@@ -633,10 +392,10 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
public _onExtensionHostExit(code: number): void {
|
||||
if (this._isExtensionDevTestFromCli) {
|
||||
// When CLI testing make sure to exit with proper exit code
|
||||
this._electronService.exit(code);
|
||||
this._nativeHostService.exit(code);
|
||||
} else {
|
||||
// Expected development extension termination: When the extension host goes down we also shutdown the window
|
||||
this._electronService.closeWindow();
|
||||
this._nativeHostService.closeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,58 +462,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
||||
}
|
||||
}
|
||||
|
||||
const enum ExtensionRunningLocation {
|
||||
None,
|
||||
LocalProcess,
|
||||
LocalWebWorker,
|
||||
Remote
|
||||
}
|
||||
|
||||
export function determineRunningLocation(localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], allExtensionKinds: Map<string, ExtensionKind[]>, hasRemote: boolean, hasLocalWebWorker: boolean): Map<string, ExtensionRunningLocation> {
|
||||
const localExtensionsSet = new Set<string>();
|
||||
localExtensions.forEach(ext => localExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const remoteExtensionsSet = new Set<string>();
|
||||
remoteExtensions.forEach(ext => remoteExtensionsSet.add(ExtensionIdentifier.toKey(ext.identifier)));
|
||||
|
||||
const pickRunningLocation = (extension: IExtensionDescription): ExtensionRunningLocation => {
|
||||
const isInstalledLocally = localExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const isInstalledRemotely = remoteExtensionsSet.has(ExtensionIdentifier.toKey(extension.identifier));
|
||||
const extensionKinds = allExtensionKinds.get(ExtensionIdentifier.toKey(extension.identifier)) || [];
|
||||
for (const extensionKind of extensionKinds) {
|
||||
if (extensionKind === 'ui' && isInstalledLocally) {
|
||||
// ui extensions run locally if possible
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'workspace' && isInstalledRemotely) {
|
||||
// workspace extensions run remotely if possible
|
||||
return ExtensionRunningLocation.Remote;
|
||||
}
|
||||
if (extensionKind === 'workspace' && !hasRemote) {
|
||||
// workspace extensions also run locally if there is no remote
|
||||
return ExtensionRunningLocation.LocalProcess;
|
||||
}
|
||||
if (extensionKind === 'web' && isInstalledLocally && hasLocalWebWorker) {
|
||||
// web worker extensions run in the local web worker if possible
|
||||
return ExtensionRunningLocation.LocalWebWorker;
|
||||
}
|
||||
}
|
||||
return ExtensionRunningLocation.None;
|
||||
};
|
||||
|
||||
const runningLocation = new Map<string, ExtensionRunningLocation>();
|
||||
localExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
remoteExtensions.forEach(ext => runningLocation.set(ExtensionIdentifier.toKey(ext.identifier), pickRunningLocation(ext)));
|
||||
return runningLocation;
|
||||
}
|
||||
|
||||
function _determineRunningLocation(productService: IProductService, configurationService: IConfigurationService, localExtensions: IExtensionDescription[], remoteExtensions: IExtensionDescription[], hasRemote: boolean, hasLocalWebWorker: boolean): Map<string, ExtensionRunningLocation> {
|
||||
const allExtensionKinds = new Map<string, ExtensionKind[]>();
|
||||
localExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, productService, configurationService)));
|
||||
remoteExtensions.forEach(ext => allExtensionKinds.set(ExtensionIdentifier.toKey(ext.identifier), getExtensionKind(ext, productService, configurationService)));
|
||||
return determineRunningLocation(localExtensions, remoteExtensions, allExtensionKinds, hasRemote, hasLocalWebWorker);
|
||||
}
|
||||
|
||||
function filterByRunningLocation(extensions: IExtensionDescription[], runningLocation: Map<string, ExtensionRunningLocation>, desiredRunningLocation: ExtensionRunningLocation): IExtensionDescription[] {
|
||||
return extensions.filter(ext => runningLocation.get(ExtensionIdentifier.toKey(ext.identifier)) === desiredRunningLocation);
|
||||
}
|
||||
@@ -767,7 +474,7 @@ class RestartExtensionHostAction extends Action2 {
|
||||
super({
|
||||
id: 'workbench.action.restartExtensionHost',
|
||||
title: { value: nls.localize('restartExtensionHost', "Restart Extension Host"), original: 'Restart Extension Host' },
|
||||
category: { value: nls.localize({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, "Developer"), original: 'Developer' },
|
||||
category: CATEGORIES.Developer,
|
||||
f1: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
import * as nls from 'vs/nls';
|
||||
import { ChildProcess, fork } from 'child_process';
|
||||
import { Server, Socket, createServer } from 'net';
|
||||
import { CrashReporterStartOptions } from 'vs/base/parts/sandbox/common/electronTypes';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { CrashReporterStartOptions } from 'vs/base/parts/sandbox/electron-sandbox/electronTypes';
|
||||
import { FileAccess } from 'vs/base/common/network';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
@@ -20,16 +20,15 @@ import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteCo
|
||||
import { findFreePort } from 'vs/base/node/ports';
|
||||
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { generateRandomPipeName, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { createRandomIPCHandle, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { ILifecycleService, WillShutdownEvent } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IElectronService } from 'vs/platform/electron/electron-sandbox/electron';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { IInitData, UIKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
@@ -90,9 +89,9 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
private readonly _initDataProvider: ILocalProcessExtensionHostDataProvider,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IElectronService private readonly _electronService: IElectronService,
|
||||
@INativeHostService private readonly _nativeHostService: INativeHostService,
|
||||
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
|
||||
@INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@ILabelService private readonly _labelService: ILabelService,
|
||||
@@ -122,7 +121,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
this._toDispose.add(this._lifecycleService.onShutdown(reason => this.terminate()));
|
||||
this._toDispose.add(this._extensionHostDebugService.onClose(event => {
|
||||
if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) {
|
||||
this._electronService.closeWindow();
|
||||
this._nativeHostService.closeWindow();
|
||||
}
|
||||
}));
|
||||
this._toDispose.add(this._extensionHostDebugService.onReload(event => {
|
||||
@@ -171,6 +170,12 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
delete env['DYLD_LIBRARY_PATH'];
|
||||
}
|
||||
|
||||
if (this._isExtensionDevHost) {
|
||||
// Unset `VSCODE_NODE_CACHED_DATA_DIR` when developing extensions because it might
|
||||
// be that dependencies, that otherwise would be cached, get modified.
|
||||
delete env['VSCODE_NODE_CACHED_DATA_DIR'];
|
||||
}
|
||||
|
||||
const opts = {
|
||||
env,
|
||||
// We only detach the extension host on windows. Linux and Mac orphan by default
|
||||
@@ -216,7 +221,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
}
|
||||
|
||||
// Run Extension Host as fork of current process
|
||||
this._extensionHostProcess = fork(getPathFromAmdModule(require, 'bootstrap-fork'), ['--type=extensionHost'], opts);
|
||||
this._extensionHostProcess = fork(FileAccess.asFileUri('bootstrap-fork', require).fsPath, ['--type=extensionHost'], opts);
|
||||
|
||||
// Catch all output coming from the extension host process
|
||||
type Output = { data: string, format: string[] };
|
||||
@@ -278,7 +283,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
|
||||
// Help in case we fail to start it
|
||||
let startupTimeoutHandle: any;
|
||||
if (!this._environmentService.isBuilt && !this._environmentService.configuration.remoteAuthority || this._isExtensionDevHost) {
|
||||
if (!this._environmentService.isBuilt && !this._environmentService.remoteAuthority || this._isExtensionDevHost) {
|
||||
startupTimeoutHandle = setTimeout(() => {
|
||||
const msg = this._isExtensionDevDebugBrk
|
||||
? nls.localize('extensionHost.startupFailDebug', "Extension host did not start in 10 seconds, it might be stopped on the first line and needs a debugger to continue.")
|
||||
@@ -310,7 +315,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
*/
|
||||
private _tryListenOnPipe(): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const pipeName = generateRandomPipeName();
|
||||
const pipeName = createRandomIPCHandle();
|
||||
|
||||
this._namedPipeServer = createServer();
|
||||
this._namedPipeServer.on('error', reject);
|
||||
@@ -467,7 +472,7 @@ export class LocalProcessExtensionHost implements IExtensionHost {
|
||||
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false
|
||||
},
|
||||
remote: {
|
||||
authority: this._environmentService.configuration.remoteAuthority,
|
||||
authority: this._environmentService.remoteAuthority,
|
||||
connectionData: null,
|
||||
isRemote: false
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@ import { PersistentProtocol, ProtocolConstants, BufferedEmitter } from 'vs/base/
|
||||
import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage, IExtHostReduceGraceTimeMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage, IExtHostReduceGraceTimeMessage, ExtensionHostExitCode } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { ExtensionHostMain, IExitFn } from 'vs/workbench/services/extensions/common/extensionHostMain';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc';
|
||||
@@ -225,7 +225,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
|
||||
if (rendererCommit && myCommit) {
|
||||
// Running in the built version where commits are defined
|
||||
if (rendererCommit !== myCommit) {
|
||||
nativeExit(55);
|
||||
nativeExit(ExtensionHostExitCode.VersionMismatch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,7 @@ export async function startExtensionHostProcess(): Promise<void> {
|
||||
const renderer = await connectToRenderer(protocol);
|
||||
const { initData } = renderer;
|
||||
// setup things
|
||||
patchProcess(!!initData.environment.extensionTestsLocationURI); // to support other test frameworks like Jasmin that use process.exit (https://github.com/Microsoft/vscode/issues/37708)
|
||||
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;
|
||||
|
||||
// host abstraction
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as semver from 'semver-umd';
|
||||
import * as semver from 'vs/base/common/semver/semver';
|
||||
import * as json from 'vs/base/common/json';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
|
||||
@@ -51,7 +51,9 @@ class ExtensionManifestParser extends ExtensionManifestHandler {
|
||||
return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => {
|
||||
const errors: json.ParseError[] = [];
|
||||
const manifest = json.parse(manifestContents.toString(), errors);
|
||||
if (errors.length === 0 && json.getNodeType(manifest) === 'object') {
|
||||
if (json.getNodeType(manifest) !== 'object') {
|
||||
this._log.error(this._absoluteFolderPath, nls.localize('jsonParseInvalidType', "Invalid manifest file {0}: Not an JSON object.", this._absoluteManifestPath));
|
||||
} else if (errors.length === 0) {
|
||||
if (manifest.__metadata) {
|
||||
manifest.uuid = manifest.__metadata.id;
|
||||
}
|
||||
@@ -291,6 +293,7 @@ export interface IRelaxedExtensionDescription {
|
||||
version: string;
|
||||
publisher: string;
|
||||
isBuiltin: boolean;
|
||||
isUserBuiltin: boolean;
|
||||
isUnderDevelopment: boolean;
|
||||
extensionLocation: URI;
|
||||
engines: {
|
||||
@@ -304,6 +307,7 @@ class ExtensionManifestValidator extends ExtensionManifestHandler {
|
||||
validate(_extensionDescription: IExtensionDescription): IExtensionDescription | null {
|
||||
let extensionDescription = <IRelaxedExtensionDescription>_extensionDescription;
|
||||
extensionDescription.isBuiltin = this._isBuiltin;
|
||||
extensionDescription.isUserBuiltin = !this._isBuiltin && !!extensionDescription.isUserBuiltin;
|
||||
extensionDescription.isUnderDevelopment = this._isUnderDevelopment;
|
||||
|
||||
let notices: string[] = [];
|
||||
@@ -448,7 +452,7 @@ export class ExtensionScannerInput {
|
||||
public readonly absoluteFolderPath: string,
|
||||
public readonly isBuiltin: boolean,
|
||||
public readonly isUnderDevelopment: boolean,
|
||||
public readonly tanslations: Translations
|
||||
public readonly translations: Translations
|
||||
) {
|
||||
// Keep empty!! (JSON.parse)
|
||||
}
|
||||
@@ -458,7 +462,7 @@ export class ExtensionScannerInput {
|
||||
devMode: input.devMode,
|
||||
locale: input.locale,
|
||||
pseudo: input.locale === 'pseudo',
|
||||
translations: input.tanslations
|
||||
translations: input.translations
|
||||
};
|
||||
}
|
||||
|
||||
@@ -472,7 +476,7 @@ export class ExtensionScannerInput {
|
||||
&& a.isBuiltin === b.isBuiltin
|
||||
&& a.isUnderDevelopment === b.isUnderDevelopment
|
||||
&& a.mtime === b.mtime
|
||||
&& Translations.equals(a.tanslations, b.tanslations)
|
||||
&& Translations.equals(a.translations, b.translations)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as cp from 'child_process';
|
||||
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ProxyAgent } from 'vscode-proxy-agent';
|
||||
@@ -290,7 +288,7 @@ function noProxyFromEnv(envValue?: string) {
|
||||
return () => false;
|
||||
}
|
||||
return (hostname: string, port: string) => filters.some(({ domain, port: filterPort }) => {
|
||||
return endsWith(`.${hostname.toLowerCase()}`, domain) && (!filterPort || port === filterPort);
|
||||
return `.${hostname.toLowerCase()}`.endsWith(domain) && (!filterPort || port === filterPort);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -314,20 +312,20 @@ function createPatchedModules(configProvider: ExtHostConfigProvider, resolveProx
|
||||
|
||||
return {
|
||||
http: {
|
||||
off: assign({}, http, patches(http, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: assign({}, http, patches(http, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: assign({}, http, patches(http, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: assign({}, http, patches(http, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: assign(http, patches(http, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
off: Object.assign({}, http, patches(http, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, http, patches(http, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, http, patches(http, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, http, patches(http, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(http, patches(http, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
} as Record<string, typeof http>,
|
||||
https: {
|
||||
off: assign({}, https, patches(https, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: assign({}, https, patches(https, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: assign({}, https, patches(https, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: assign({}, https, patches(https, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: assign(https, patches(https, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
off: Object.assign({}, https, patches(https, resolveProxy, { config: 'off' }, certSetting, true)),
|
||||
on: Object.assign({}, https, patches(https, resolveProxy, { config: 'on' }, certSetting, true)),
|
||||
override: Object.assign({}, https, patches(https, resolveProxy, { config: 'override' }, certSetting, true)),
|
||||
onRequest: Object.assign({}, https, patches(https, resolveProxy, proxySetting, certSetting, true)),
|
||||
default: Object.assign(https, patches(https, resolveProxy, proxySetting, certSetting, false)) // run last
|
||||
} as Record<string, typeof https>,
|
||||
tls: assign(tls, tlsPatches(tls))
|
||||
tls: Object.assign(tls, tlsPatches(tls))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -470,9 +468,12 @@ let _caCertificates: ReturnType<typeof readCaCertificates> | Promise<undefined>;
|
||||
async function getCaCertificates(extHostLogService: ILogService) {
|
||||
if (!_caCertificates) {
|
||||
_caCertificates = readCaCertificates()
|
||||
.then(res => res && res.certs.length ? res : undefined)
|
||||
.then(res => {
|
||||
extHostLogService.debug('ProxyResolver#getCaCertificates count', res && res.certs.length);
|
||||
return res && res.certs.length ? res : undefined;
|
||||
})
|
||||
.catch(err => {
|
||||
extHostLogService.error('ProxyResolver#getCertificates', toErrorMessage(err));
|
||||
extHostLogService.error('ProxyResolver#getCaCertificates error', toErrorMessage(err));
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ExtensionService as BrowserExtensionService } from 'vs/workbench/services/extensions/browser/extensionService';
|
||||
import { ExtensionRunningLocation } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
|
||||
suite('BrowserExtensionService', () => {
|
||||
test('pickRunningLocation', () => {
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation([], true, true), ExtensionRunningLocation.None);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], false, true), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'web', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['ui', 'workspace', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'ui', 'workspace'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['web', 'workspace', 'ui'], true, true), ExtensionRunningLocation.LocalWebWorker);
|
||||
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'ui', 'web'], true, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, false), ExtensionRunningLocation.None);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], false, true), ExtensionRunningLocation.Remote);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, false), ExtensionRunningLocation.LocalWebWorker);
|
||||
assert.deepEqual(BrowserExtensionService.pickRunningLocation(['workspace', 'web', 'ui'], true, true), ExtensionRunningLocation.Remote);
|
||||
});
|
||||
});
|
||||
@@ -22,7 +22,7 @@ declare function postMessage(data: any, transferables?: Transferable[]): void;
|
||||
declare namespace self {
|
||||
let close: any;
|
||||
let postMessage: any;
|
||||
let addEventLister: any;
|
||||
let addEventListener: any;
|
||||
let indexedDB: { open: any, [k: string]: any };
|
||||
let caches: { open: any, [k: string]: any };
|
||||
}
|
||||
@@ -33,8 +33,8 @@ self.close = () => console.trace(`'close' has been blocked`);
|
||||
const nativePostMessage = postMessage.bind(self);
|
||||
self.postMessage = () => console.trace(`'postMessage' has been blocked`);
|
||||
|
||||
// const nativeAddEventLister = addEventListener.bind(self);
|
||||
self.addEventLister = () => console.trace(`'addEventListener' has been blocked`);
|
||||
// const nativeAddEventListener = addEventListener.bind(self);
|
||||
self.addEventListener = () => console.trace(`'addEventListener' has been blocked`);
|
||||
|
||||
(<any>self)['AMDLoader'] = undefined;
|
||||
(<any>self)['NLSLoaderPlugin'] = undefined;
|
||||
@@ -45,9 +45,9 @@ self.addEventLister = () => console.trace(`'addEventListener' has been blocked`)
|
||||
(<any>self)['webkitResolveLocalFileSystemSyncURL'] = undefined;
|
||||
(<any>self)['webkitResolveLocalFileSystemURL'] = undefined;
|
||||
|
||||
if (location.protocol === 'data:') {
|
||||
if ((<any>self).Worker) {
|
||||
// make sure new Worker(...) always uses data:
|
||||
const _Worker = Worker;
|
||||
const _Worker = (<any>self).Worker;
|
||||
Worker = <any>function (stringUrl: string | URL, options?: WorkerOptions) {
|
||||
const js = `importScripts('${stringUrl}');`;
|
||||
options = options || {};
|
||||
|
||||
@@ -8,14 +8,20 @@
|
||||
let MonacoEnvironment = (<any>self).MonacoEnvironment;
|
||||
let monacoBaseUrl = MonacoEnvironment && MonacoEnvironment.baseUrl ? MonacoEnvironment.baseUrl : '../../../../../';
|
||||
|
||||
const trustedTypesPolicy = self.trustedTypes?.createPolicy('amdLoader', { createScriptURL: value => value });
|
||||
|
||||
if (typeof (<any>self).define !== 'function' || !(<any>self).define.amd) {
|
||||
importScripts(monacoBaseUrl + 'vs/loader.js');
|
||||
let loaderSrc: string | TrustedScriptURL = monacoBaseUrl + 'vs/loader.js';
|
||||
if (trustedTypesPolicy) {
|
||||
loaderSrc = trustedTypesPolicy.createScriptURL(loaderSrc);
|
||||
}
|
||||
importScripts(loaderSrc as string);
|
||||
}
|
||||
|
||||
require.config({
|
||||
baseUrl: monacoBaseUrl,
|
||||
catchError: true,
|
||||
createTrustedScriptURL: (value: string) => value
|
||||
trustedTypesPolicy
|
||||
});
|
||||
|
||||
require(['vs/workbench/services/extensions/worker/extensionHostWorker'], () => { }, err => console.error(err));
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data:; script-src 'unsafe-eval' 'sha256-DhNBVT9y4y9LG937ZrEbN5CwALd+WSpQnG3z5u1MOFk=' http: https:; connect-src http: https:" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {
|
||||
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
|
||||
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
|
||||
|
||||
function sendError(error) {
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
error: {
|
||||
name: error ? error.name : '',
|
||||
message: error ? error.message : '',
|
||||
stack: error ? error.stack : []
|
||||
}
|
||||
}, '*');
|
||||
}
|
||||
|
||||
try {
|
||||
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
const { data } = event;
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
data
|
||||
}, '*', [data]);
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
console.error(event.message, event.error);
|
||||
sendError(event.error);
|
||||
};
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
sendError(err);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; child-src 'self' data:; script-src 'unsafe-eval' 'sha256-DhNBVT9y4y9LG937ZrEbN5CwALd+WSpQnG3z5u1MOFk=' https:; connect-src https:" />
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {
|
||||
const idMatch = document.location.search.match(/\bvscodeWebWorkerExtHostId=([0-9a-f\-]+)/i);
|
||||
const vscodeWebWorkerExtHostId = idMatch ? idMatch[1] : '';
|
||||
|
||||
function sendError(error) {
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
error: {
|
||||
name: error ? error.name : '',
|
||||
message: error ? error.message : '',
|
||||
stack: error ? error.stack : []
|
||||
}
|
||||
}, '*');
|
||||
}
|
||||
|
||||
try {
|
||||
const worker = new Worker('extensionHostWorkerMain.js', { name: 'WorkerExtensionHost' });
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
const { data } = event;
|
||||
window.parent.postMessage({
|
||||
vscodeWebWorkerExtHostId,
|
||||
data
|
||||
}, '*', [data]);
|
||||
};
|
||||
|
||||
worker.onerror = (event) => {
|
||||
console.error(event.message, event.error);
|
||||
sendError(event.error);
|
||||
};
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
sendError(err);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user