Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)

This commit is contained in:
Anthony Dresser
2019-04-10 16:29:23 -07:00
committed by GitHub
parent 18c54f41bd
commit 8315dacda4
320 changed files with 5540 additions and 3822 deletions

View File

@@ -18,15 +18,13 @@ export function parseExtensionDevOptions(environmentService: IEnvironmentService
let isExtensionDevHost = environmentService.isExtensionDevelopment;
let debugOk = true;
let extDevLoc = environmentService.extensionDevelopmentLocationURI;
if (Array.isArray(extDevLoc)) {
for (let x of extDevLoc) {
let extDevLocs = environmentService.extensionDevelopmentLocationURI;
if (extDevLocs) {
for (let x of extDevLocs) {
if (x.scheme !== Schemas.file) {
debugOk = false;
}
}
} else if (extDevLoc && extDevLoc.scheme !== Schemas.file) {
debugOk = false;
}
let isExtensionDevDebug = debugOk && typeof environmentService.debugExtensionHost.port === 'number';

View File

@@ -10,6 +10,22 @@ import { IRemoteConsoleLog } from 'vs/base/common/console';
export const IExtensionHostDebugService = createDecorator<IExtensionHostDebugService>('extensionHostDebugService');
export interface IAttachSessionEvent {
sessionId: string;
subId?: string;
port: number;
}
export interface ILogToSessionEvent {
sessionId: string;
log: IRemoteConsoleLog;
}
export interface ITerminateSessionEvent {
sessionId: string;
subId?: string;
}
export interface IExtensionHostDebugService {
_serviceBrand: any;
@@ -19,12 +35,12 @@ export interface IExtensionHostDebugService {
close(resource: URI): void;
onClose: Event<URI>;
attachSession(id: string, port: number): void;
onAttachSession: Event<{ id: string, port: number }>;
attachSession(sessionId: string, port: number, subId?: string): void;
onAttachSession: Event<IAttachSessionEvent>;
logToSession(id: string, log: IRemoteConsoleLog): void;
onLogToSession: Event<{ id: string, log: IRemoteConsoleLog }>;
logToSession(sessionId: string, log: IRemoteConsoleLog): void;
onLogToSession: Event<ILogToSessionEvent>;
terminateSession(id: string): void;
onTerminateSession: Event<string>;
terminateSession(sessionId: string, subId?: string): void;
onTerminateSession: Event<ITerminateSessionEvent>;
}

View File

@@ -11,7 +11,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IURITransformer, transformIncomingURIs } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { LazyPromise } from 'vs/workbench/services/extensions/node/lazyPromise';
import { LazyPromise } from 'vs/workbench/services/extensions/common/lazyPromise';
import { IRPCProtocol, ProxyIdentifier, getStringIdentifierForProxy } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -739,7 +739,6 @@ class MessageIO {
}
private static _serializeReplyOKVSBuffer(req: number, res: VSBuffer): VSBuffer {
let len = 0;
len += MessageBuffer.sizeVSBuffer(res);
@@ -809,10 +808,10 @@ const enum MessageType {
Cancel = 6,
ReplyOKEmpty = 7,
ReplyOKBuffer = 8,
ReplyOKVSBuffer = 8,
ReplyOKJSON = 9,
ReplyErrError = 10,
ReplyErrEmpty = 11,
ReplyOKVSBuffer = 9,
ReplyOKJSON = 10,
ReplyErrError = 11,
ReplyErrEmpty = 12,
}
const enum ArgType {

View File

@@ -294,30 +294,19 @@ export class CachedExtensionScanner {
// Always load developed extensions while extensions development
let developedExtensions: Promise<IExtensionDescription[]> = Promise.resolve([]);
if (environmentService.isExtensionDevelopment) {
if (Array.isArray(environmentService.extensionDevelopmentLocationURI)) {
const extDescsP = environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file).map(extLoc => {
return ExtensionScanner.scanOneOrMultipleExtensions(
new ExtensionScannerInput(version, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), log
);
});
developedExtensions = Promise.all(extDescsP).then((extDescArrays: IExtensionDescription[][]) => {
let extDesc: IExtensionDescription[] = [];
for (let eds of extDescArrays) {
extDesc = extDesc.concat(eds);
}
return extDesc;
});
} else if (environmentService.extensionDevelopmentLocationURI) {
if (environmentService.extensionDevelopmentLocationURI.scheme === Schemas.file) {
developedExtensions = ExtensionScanner.scanOneOrMultipleExtensions(
new ExtensionScannerInput(version, commit, locale, devMode, originalFSPath(environmentService.extensionDevelopmentLocationURI), false, true, translations), log
);
if (environmentService.isExtensionDevelopment && environmentService.extensionDevelopmentLocationURI) {
const extDescsP = environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file).map(extLoc => {
return ExtensionScanner.scanOneOrMultipleExtensions(
new ExtensionScannerInput(version, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), log
);
});
developedExtensions = Promise.all(extDescsP).then((extDescArrays: IExtensionDescription[][]) => {
let extDesc: IExtensionDescription[] = [];
for (let eds of extDescArrays) {
extDesc = extDesc.concat(eds);
}
}
return extDesc;
});
}
return Promise.all([finalBuiltinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => {

View File

@@ -22,7 +22,7 @@ import { findFreePort, randomPort } 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 { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
@@ -32,7 +32,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/node/extensionHostProtocol';
import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { parseExtensionDevOptions } from '../common/extensionDevOptions';
@@ -78,7 +78,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
@IWindowsService private readonly _windowsService: IWindowsService,
@IWindowService private readonly _windowService: IWindowService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@ILogService private readonly _logService: ILogService,
@ILabelService private readonly _labelService: ILabelService,
@@ -124,10 +124,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
private matchesExtDevLocations(resource: URI): boolean {
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
if (Array.isArray(extDevLocs)) {
if (extDevLocs) {
return extDevLocs.some(extDevLoc => isEqual(extDevLoc, resource));
} else if (extDevLocs) {
return isEqual(extDevLocs, resource);
}
return false;
}
@@ -240,7 +238,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
// Help in case we fail to start it
let startupTimeoutHandle: any;
if (!this._environmentService.isBuilt && !this._windowService.getConfiguration().remoteAuthority || this._isExtensionDevHost) {
if (!this._environmentService.isBuilt && !this._environmentService.configuration.remoteAuthority || this._isExtensionDevHost) {
startupTimeoutHandle = setTimeout(() => {
const msg = this._isExtensionDevDebugBrk
? nls.localize('extensionHostProcess.startupFailDebug', "Extension host did not start in 10 seconds, it might be stopped on the first line and needs a debugger to continue.")

View File

@@ -6,7 +6,7 @@
import { Event, Emitter } from 'vs/base/common/event';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug';
import { IExtensionHostDebugService, IAttachSessionEvent, ITerminateSessionEvent, ILogToSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug';
import { URI } from 'vs/base/common/uri';
import { IRemoteConsoleLog } from 'vs/base/common/console';
import { ipcRenderer as ipc } from 'electron';
@@ -16,10 +16,8 @@ interface IReloadBroadcast {
resource: string;
}
interface IAttachSessionBroadcast {
interface IAttachSessionBroadcast extends IAttachSessionEvent {
type: 'vscode:extensionAttach';
id: string;
port: number;
}
interface ICloseBroadcast {
@@ -27,15 +25,12 @@ interface ICloseBroadcast {
resource: string;
}
interface ILogToSessionBroadcast {
interface ILogToSessionBroadcast extends ILogToSessionEvent {
type: 'vscode:extensionLog';
id: string;
log: IRemoteConsoleLog;
}
interface ITerminateSessionBroadcast {
interface ITerminateSessionBroadcast extends ITerminateSessionEvent {
type: 'vscode:extensionTerminate';
id: string;
}
const CHANNEL = 'vscode:extensionHostDebug';
@@ -46,30 +41,32 @@ class ExtensionHostDebugService implements IExtensionHostDebugService {
private windowId: number;
private readonly _onReload = new Emitter<URI>();
private readonly _onClose = new Emitter<URI>();
private readonly _onAttachSession = new Emitter<{ id: string, port: number }>();
private readonly _onLogToSession = new Emitter<{ id: string, log: IRemoteConsoleLog }>();
private readonly _onTerminateSession = new Emitter<string>();
private readonly _onAttachSession = new Emitter<IAttachSessionEvent>();
private readonly _onLogToSession = new Emitter<ILogToSessionEvent>();
private readonly _onTerminateSession = new Emitter<ITerminateSessionEvent>();
constructor(
@IWindowService readonly windowService: IWindowService,
) {
this.windowId = windowService.getCurrentWindowId();
this.windowId = windowService.windowId;
ipc.on(CHANNEL, (_: unknown, broadcast: IReloadBroadcast | ICloseBroadcast | IAttachSessionBroadcast | ILogToSessionBroadcast | ITerminateSessionBroadcast) => {
if (broadcast.type === 'vscode:extensionReload') {
this._onReload.fire(URI.parse(broadcast.resource));
}
if (broadcast.type === 'vscode:extensionCloseExtensionHost') {
this._onClose.fire(URI.parse(broadcast.resource));
}
if (broadcast.type === 'vscode:extensionAttach') {
this._onAttachSession.fire({ id: broadcast.id, port: broadcast.port });
}
if (broadcast.type === 'vscode:extensionLog') {
this._onLogToSession.fire({ id: broadcast.id, log: broadcast.log });
}
if (broadcast.type === 'vscode:extensionTerminate') {
this._onTerminateSession.fire(broadcast.id);
switch (broadcast.type) {
case 'vscode:extensionReload':
this._onReload.fire(URI.parse(broadcast.resource));
break;
case 'vscode:extensionCloseExtensionHost':
this._onClose.fire(URI.parse(broadcast.resource));
break;
case 'vscode:extensionAttach':
this._onAttachSession.fire(broadcast);
break;
case 'vscode:extensionLog':
this._onLogToSession.fire(broadcast);
break;
case 'vscode:extensionTerminate':
this._onTerminateSession.fire(broadcast);
break;
}
});
}
@@ -96,38 +93,40 @@ class ExtensionHostDebugService implements IExtensionHostDebugService {
return this._onClose.event;
}
attachSession(id: string, port: number): void {
attachSession(sessionId: string, port: number, subId?: string): void {
ipc.send(CHANNEL, this.windowId, <IAttachSessionBroadcast>{
type: 'vscode:extensionAttach',
id,
port
sessionId,
port,
subId
});
}
get onAttachSession(): Event<{ id: string, port: number }> {
get onAttachSession(): Event<IAttachSessionEvent> {
return this._onAttachSession.event;
}
logToSession(id: string, log: IRemoteConsoleLog): void {
logToSession(sessionId: string, log: IRemoteConsoleLog): void {
ipc.send(CHANNEL, this.windowId, <ILogToSessionBroadcast>{
type: 'vscode:extensionLog',
id,
sessionId,
log
});
}
get onLogToSession(): Event<{ id: string, log: IRemoteConsoleLog }> {
get onLogToSession(): Event<ILogToSessionEvent> {
return this._onLogToSession.event;
}
terminateSession(id: string): void {
terminateSession(sessionId: string, subId?: string): void {
ipc.send(CHANNEL, this.windowId, <ITerminateSessionBroadcast>{
type: 'vscode:extensionTerminate',
id
sessionId,
subId
});
}
get onTerminateSession(): Event<string> {
get onTerminateSession(): Event<ITerminateSessionEvent> {
return this._onTerminateSession.event;
}
}

View File

@@ -16,7 +16,7 @@ import { ProfileSession } from 'vs/workbench/services/extensions/common/extensio
import { IExtensionHostStarter } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/node/rpcProtocol';
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as nls from 'vs/nls';
@@ -27,6 +27,7 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IUntitledResourceInput } from 'vs/workbench/common/editor';
import { StopWatch } from 'vs/base/common/stopwatch';
import { VSBuffer } from 'vs/base/common/buffer';
// Enable to see detailed message communication between window and extension host
const LOG_EXTENSION_HOST_COMMUNICATION = false;
@@ -154,7 +155,7 @@ export class ExtensionHostProcessManager extends Disposable {
let b = Buffer.alloc(SIZE, Math.random() % 256);
const sw = StopWatch.create(true);
await proxy.$test_up(b);
await proxy.$test_up(VSBuffer.wrap(b));
sw.stop();
return ExtensionHostProcessManager._convert(SIZE, sw.elapsed());
}

View File

@@ -33,7 +33,7 @@ export class ExtensionManagementServerService implements IExtensionManagementSer
const remoteAgentConnection = remoteAgentService.getConnection();
if (remoteAgentConnection) {
const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection.getChannel<IChannel>('extensions'));
this.remoteExtensionManagementServer = { authority: remoteAgentConnection.remoteAuthority, extensionManagementService, label: remoteAgentConnection.remoteAuthority };
this.remoteExtensionManagementServer = { authority: remoteAgentConnection.remoteAuthority, extensionManagementService, label: localize('remote', "Remote") };
}
}

View File

@@ -13,7 +13,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import * as perf from 'vs/base/common/performance';
import { isEqualOrParent } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { EnablementState, IExtensionEnablementService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { BetterMergeId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -26,8 +26,8 @@ import { IWindowService, IWindowsService } from 'vs/platform/windows/common/wind
import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, ProfileSession, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser, schema } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
import { ResponsiveState } from 'vs/workbench/services/extensions/node/rpcProtocol';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { CachedExtensionScanner, Logger } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner';
import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/electron-browser/extensionHostProcessManager';
import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -97,7 +97,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@INotificationService private readonly _notificationService: INotificationService,
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IExtensionEnablementService private readonly _extensionEnablementService: IExtensionEnablementService,
@IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService,
@@ -112,7 +112,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
e.join(this.activateByEvent(`onFileSystem:${e.scheme}`));
}));
this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.getCurrentWindowId()}`));
this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.windowId}`));
this._registry = new ExtensionDescriptionRegistry([]);
this._installedExtensionsReady = new Barrier();
this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment;
@@ -189,7 +189,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
}
private async _deltaExtensions(_toAdd: IExtension[], _toRemove: string[]): Promise<void> {
if (this._windowService.getConfiguration().remoteAuthority) {
if (this._environmentService.configuration.remoteAuthority) {
return;
}
@@ -283,7 +283,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
}
public canAddExtension(extension: IExtensionDescription): boolean {
if (this._windowService.getConfiguration().remoteAuthority) {
if (this._environmentService.configuration.remoteAuthority) {
return false;
}
@@ -303,7 +303,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
}
public canRemoveExtension(extension: IExtensionDescription): boolean {
if (this._windowService.getConfiguration().remoteAuthority) {
if (this._environmentService.configuration.remoteAuthority) {
return false;
}
@@ -647,16 +647,14 @@ export class ExtensionService extends Disposable implements IExtensionService {
private isExtensionUnderDevelopment(extension: IExtensionDescription): boolean {
if (this._environmentService.isExtensionDevelopment) {
const extDevLoc = this._environmentService.extensionDevelopmentLocationURI;
const extLocation = extension.extensionLocation;
if (Array.isArray(extDevLoc)) {
for (let p of extDevLoc) {
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
if (extDevLocs) {
const extLocation = extension.extensionLocation;
for (let p of extDevLocs) {
if (isEqualOrParent(extLocation, p)) {
return true;
}
}
} else if (extDevLoc) {
return isEqualOrParent(extLocation, extDevLoc);
}
}
return false;

View File

@@ -10,67 +10,56 @@ import { Counter } from 'vs/base/common/numbers';
import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { IEnvironment, IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { IInitData, MainContext, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { withNullAsUndefined } from 'vs/base/common/types';
import { ILogService } from 'vs/platform/log/common/log';
// we don't (yet) throw when extensions parse
// uris that have no scheme
setUriThrowOnMissingScheme(false);
const nativeExit = process.exit.bind(process);
function patchProcess(allowExit: boolean) {
process.exit = function (code?: number) {
if (allowExit) {
exit(code);
} else {
const err = new Error('An extension called process.exit() and this was prevented.');
console.warn(err.stack);
}
} as (code?: number) => never;
process.crash = function () {
const err = new Error('An extension called process.crash() and this was prevented.');
console.warn(err.stack);
};
export interface IExitFn {
(code?: number): any;
}
export function exit(code?: number) {
nativeExit(code);
export interface IConsolePatchFn {
(mainThreadConsole: MainThreadConsoleShape): any;
}
export interface ILogServiceFn {
(initData: IInitData): ILogService;
}
export class ExtensionHostMain {
private _isTerminating: boolean;
private readonly _environment: IEnvironment;
private readonly _exitFn: IExitFn;
private readonly _extensionService: ExtHostExtensionService;
private readonly _extHostLogService: ExtHostLogService;
private disposables: IDisposable[] = [];
private _searchRequestIdProvider: Counter;
constructor(protocol: IMessagePassingProtocol, initData: IInitData) {
constructor(protocol: IMessagePassingProtocol, initData: IInitData, exitFn: IExitFn, consolePatchFn: IConsolePatchFn, logServiceFn: ILogServiceFn) {
this._isTerminating = false;
this._exitFn = exitFn;
const uriTransformer: IURITransformer | null = null;
const rpcProtocol = new RPCProtocol(protocol, null, uriTransformer);
// ensure URIs are transformed and revived
initData = this.transform(initData, rpcProtocol);
this._environment = initData.environment;
const allowExit = !!this._environment.extensionTestsLocationURI; // to support other test frameworks like Jasmin that use process.exit (https://github.com/Microsoft/vscode/issues/37708)
patchProcess(allowExit);
this._patchPatchedConsole(rpcProtocol.getProxy(MainContext.MainThreadConsole));
// allow to patch console
consolePatchFn(rpcProtocol.getProxy(MainContext.MainThreadConsole));
// services
this._extHostLogService = new ExtHostLogService(initData.logLevel, initData.logsLocation.fsPath);
this._extHostLogService = new ExtHostLogService(logServiceFn(initData), initData.logsLocation.fsPath);
this.disposables.push(this._extHostLogService);
this._searchRequestIdProvider = new Counter();
@@ -80,7 +69,7 @@ export class ExtensionHostMain {
this._extHostLogService.trace('initData', initData);
const extHostConfiguraiton = new ExtHostConfiguration(rpcProtocol.getProxy(MainContext.MainThreadConfiguration), extHostWorkspace);
this._extensionService = new ExtHostExtensionService(nativeExit, initData, rpcProtocol, extHostWorkspace, extHostConfiguraiton, this._extHostLogService);
this._extensionService = new ExtHostExtensionService(exitFn, initData, rpcProtocol, extHostWorkspace, extHostConfiguraiton, initData.environment, this._extHostLogService);
// error forwarding and stack trace scanning
Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
@@ -116,18 +105,6 @@ export class ExtensionHostMain {
});
}
private _patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void {
// The console is already patched to use `process.send()`
const nativeProcessSend = process.send!;
process.send = (...args: any[]) => {
if (args.length === 0 || !args[0] || args[0].type !== '__$console') {
return nativeProcessSend.apply(process, args);
}
mainThreadConsole.$logExtensionHostMessage(args[0]);
};
}
terminate(): void {
if (this._isTerminating) {
// we are already shutting down...
@@ -145,7 +122,7 @@ export class ExtensionHostMain {
// Give extensions 1 second to wrap up any async dispose, then exit in at most 4 seconds
setTimeout(() => {
Promise.race([timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit());
Promise.race([timeout(4000), extensionsDeactivated]).finally(() => this._exitFn());
}, 1000);
}
@@ -153,7 +130,10 @@ export class ExtensionHostMain {
initData.extensions.forEach((ext) => (<any>ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation)));
initData.environment.appRoot = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appRoot));
initData.environment.appSettingsHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appSettingsHome));
initData.environment.extensionDevelopmentLocationURI = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.extensionDevelopmentLocationURI));
const extDevLocs = initData.environment.extensionDevelopmentLocationURI;
if (extDevLocs) {
initData.environment.extensionDevelopmentLocationURI = extDevLocs.map(url => URI.revive(rpcProtocol.transformIncomingURIs(url)));
}
initData.environment.extensionTestsLocationURI = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.extensionTestsLocationURI));
initData.environment.globalStorageHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.globalStorageHome));
initData.environment.userHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.userHome));

View File

@@ -11,10 +11,12 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { PersistentProtocol, ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net';
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import product from 'vs/platform/product/node/product';
import { IInitData } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/node/extensionHostProtocol';
import { exit, ExtensionHostMain } from 'vs/workbench/services/extensions/node/extensionHostMain';
import { IInitData, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol';
import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
import { ExtensionHostMain, IExitFn, ILogServiceFn } from 'vs/workbench/services/extensions/node/extensionHostMain';
import { VSBuffer } from 'vs/base/common/buffer';
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
// With Electron 2.x and node.js 8.x the "natives" module
// can cause a native crash (see https://github.com/nodejs/node/issues/19891 and
@@ -34,6 +36,39 @@ import { VSBuffer } from 'vs/base/common/buffer';
};
})();
// custom process.exit logic...
const nativeExit: IExitFn = process.exit.bind(process);
function patchProcess(allowExit: boolean) {
process.exit = function (code?: number) {
if (allowExit) {
nativeExit(code);
} else {
const err = new Error('An extension called process.exit() and this was prevented.');
console.warn(err.stack);
}
} as (code?: number) => never;
process.crash = function () {
const err = new Error('An extension called process.crash() and this was prevented.');
console.warn(err.stack);
};
}
// use IPC messages to forward console-calls
function patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void {
// The console is already patched to use `process.send()`
const nativeProcessSend = process.send!;
process.send = (...args: any[]) => {
if (args.length === 0 || !args[0] || args[0].type !== '__$console') {
return nativeProcessSend.apply(process, args);
}
mainThreadConsole.$logExtensionHostMessage(args[0]);
};
}
const createLogService: ILogServiceFn = initData => createSpdLogService(ExtensionHostLogFileName, initData.logLevel, initData.logsLocation.fsPath);
interface IRendererConnection {
protocol: IMessagePassingProtocol;
initData: IInitData;
@@ -42,7 +77,7 @@ interface IRendererConnection {
// This calls exit directly in case the initialization is not finished and we need to exit
// Otherwise, if initialization completed we go to extensionHostMain.terminate()
let onTerminate = function () {
exit();
nativeExit();
};
function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
@@ -149,7 +184,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise<IRenderer
if (rendererCommit && myCommit) {
// Running in the built version where commits are defined
if (rendererCommit !== myCommit) {
exit(55);
nativeExit(55);
}
}
@@ -230,8 +265,13 @@ createExtHostProtocol().then(protocol => {
// connect to main side
return connectToRenderer(protocol);
}).then(renderer => {
const { initData } = renderer;
// setup things
const extensionHostMain = new ExtensionHostMain(renderer.protocol, renderer.initData);
patchProcess(!!initData.environment.extensionTestsLocationURI); // to support other test frameworks like Jasmin that use process.exit (https://github.com/Microsoft/vscode/issues/37708)
const extensionHostMain = new ExtensionHostMain(renderer.protocol, initData, nativeExit, patchPatchedConsole, createLogService);
// rewrite onTerminate-function to be a proper shutdown
onTerminate = () => extensionHostMain.terminate();
}).catch(err => console.error(err));

View File

@@ -13,11 +13,11 @@ 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/node/extHostWorkspace';
import { ExtHostConfigProvider } from 'vs/workbench/api/node/extHostConfiguration';
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ProxyAgent } from 'vscode-proxy-agent';
import { MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { URI } from 'vs/base/common/uri';

View File

@@ -8,7 +8,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
import { Emitter, Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol';
import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol';
import { VSBuffer } from 'vs/base/common/buffer';
suite('RPCProtocol', () => {