提交 aa3ea85b 编写于 作者: A Alex Dima

Explorations

上级 3b6578a2
...@@ -42,9 +42,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; ...@@ -42,9 +42,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { DownloadService } from 'vs/platform/download/node/downloadService'; import { DownloadService } from 'vs/platform/download/node/downloadService';
import { IDownloadService } from 'vs/platform/download/common/download'; import { IDownloadService } from 'vs/platform/download/common/download';
import { RemoteAuthorityResolverService } from 'vs/platform/remote/node/remoteAuthorityResolverService';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { RemoteAuthorityResolverChannel } from 'vs/platform/remote/node/remoteAuthorityResolverChannel';
import { StaticRouter } from 'vs/base/parts/ipc/node/ipc'; import { StaticRouter } from 'vs/base/parts/ipc/node/ipc';
import { DefaultURITransformer } from 'vs/base/common/uriIpc'; import { DefaultURITransformer } from 'vs/base/common/uriIpc';
...@@ -130,16 +127,11 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I ...@@ -130,16 +127,11 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
services.set(IRemoteAuthorityResolverService, new SyncDescriptor(RemoteAuthorityResolverService));
const instantiationService2 = instantiationService.createChild(services); const instantiationService2 = instantiationService.createChild(services);
instantiationService2.invokeFunction(accessor => { instantiationService2.invokeFunction(accessor => {
const remoteAuthorityResolverService = accessor.get(IRemoteAuthorityResolverService);
const remoteAuthorityResolverChannel = new RemoteAuthorityResolverChannel(remoteAuthorityResolverService);
server.registerChannel('remoteAuthorityResolver', remoteAuthorityResolverChannel);
const extensionManagementService = accessor.get(IExtensionManagementService); const extensionManagementService = accessor.get(IExtensionManagementService);
const channel = new ExtensionManagementChannel(extensionManagementService, () => DefaultURITransformer); const channel = new ExtensionManagementChannel(extensionManagementService, () => DefaultURITransformer);
server.registerChannel('extensions', channel); server.registerChannel('extensions', channel);
...@@ -153,7 +145,6 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I ...@@ -153,7 +145,6 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
createSharedProcessContributions(instantiationService2); createSharedProcessContributions(instantiationService2);
disposables.push(extensionManagementService as ExtensionManagementService); disposables.push(extensionManagementService as ExtensionManagementService);
disposables.push(remoteAuthorityResolverService as RemoteAuthorityResolverService);
}); });
}); });
} }
......
...@@ -209,7 +209,7 @@ export class CodeApplication extends Disposable { ...@@ -209,7 +209,7 @@ export class CodeApplication extends Disposable {
} else { } else {
const [host, strPort] = authority.split(':'); const [host, strPort] = authority.split(':');
const port = parseInt(strPort, 10); const port = parseInt(strPort, 10);
return { authority, host, port }; return { authority, host, port, syncExtensions: false };
} }
}; };
......
...@@ -11,7 +11,6 @@ import { ILocalization } from 'vs/platform/localizations/common/localizations'; ...@@ -11,7 +11,6 @@ import { ILocalization } from 'vs/platform/localizations/common/localizations';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { IRemoteAuthorityResolver } from 'vs/platform/remote/common/remoteAuthorityResolver';
export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$'; export const EXTENSION_IDENTIFIER_PATTERN = '^([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*)$';
export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN); export const EXTENSION_IDENTIFIER_REGEX = new RegExp(EXTENSION_IDENTIFIER_PATTERN);
...@@ -109,7 +108,6 @@ export interface IExtensionContributions { ...@@ -109,7 +108,6 @@ export interface IExtensionContributions {
views?: { [location: string]: IView[] }; views?: { [location: string]: IView[] };
colors?: IColor[]; colors?: IColor[];
localizations?: ILocalization[]; localizations?: ILocalization[];
remoteAuthorityResolvers?: IRemoteAuthorityResolver[];
} }
export type ExtensionKind = 'ui' | 'workspace'; export type ExtensionKind = 'ui' | 'workspace';
......
...@@ -14,7 +14,7 @@ import { URI } from 'vs/base/common/uri'; ...@@ -14,7 +14,7 @@ import { URI } from 'vs/base/common/uri';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { IRemoteAuthorityResolverService, IRemoteAuthorityResolver } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IRemoteAuthorityResolverService, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil';
export class MulitExtensionManagementService extends Disposable implements IExtensionManagementService { export class MulitExtensionManagementService extends Disposable implements IExtensionManagementService {
...@@ -100,13 +100,13 @@ export class MulitExtensionManagementService extends Disposable implements IExte ...@@ -100,13 +100,13 @@ export class MulitExtensionManagementService extends Disposable implements IExte
return this.extensionManagementServerService.getExtensionManagementServer(extension.location); return this.extensionManagementServerService.getExtensionManagementServer(extension.location);
} }
private _remoteAuthorityResolverPromise: Thenable<IRemoteAuthorityResolver>; private _remoteAuthorityResolverPromise: Thenable<ResolvedAuthority>;
private hasToSyncExtensions(): Thenable<boolean> { private hasToSyncExtensions(): Thenable<boolean> {
if (!this.extensionManagementServerService.remoteExtensionManagementServer) { if (!this.extensionManagementServerService.remoteExtensionManagementServer) {
return Promise.resolve(false); return Promise.resolve(false);
} }
if (!this._remoteAuthorityResolverPromise) { if (!this._remoteAuthorityResolverPromise) {
this._remoteAuthorityResolverPromise = this.remoteAuthorityResolverService.getRemoteAuthorityResolver(this.extensionManagementServerService.remoteExtensionManagementServer.authority); this._remoteAuthorityResolverPromise = this.remoteAuthorityResolverService.resolveAuthority(this.extensionManagementServerService.remoteExtensionManagementServer.authority);
} }
return this._remoteAuthorityResolverPromise.then(({ syncExtensions }) => !!syncExtensions); return this._remoteAuthorityResolverPromise.then(({ syncExtensions }) => !!syncExtensions);
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProgressStep } from 'vs/platform/progress/common/progress';
import { Event } from 'vs/base/common/event';
export const IRemoteAuthorityResolverService = createDecorator<IRemoteAuthorityResolverService>('remoteAuthorityResolverService'); export const IRemoteAuthorityResolverService = createDecorator<IRemoteAuthorityResolverService>('remoteAuthorityResolverService');
...@@ -13,27 +11,14 @@ export interface ResolvedAuthority { ...@@ -13,27 +11,14 @@ export interface ResolvedAuthority {
readonly authority: string; readonly authority: string;
readonly host: string; readonly host: string;
readonly port: number; readonly port: number;
readonly syncExtensions: boolean;
} }
export type IResolvingProgressEvent =
{ type: 'progress', authority: string, data: IProgressStep }
| { type: 'finished', authority: string }
| { type: 'output', authority: string, data: { channel: string, message: string; isErr?: boolean; } };
export interface IRemoteAuthorityResolverService { export interface IRemoteAuthorityResolverService {
_serviceBrand: any; _serviceBrand: any;
onResolvingProgress: Event<IResolvingProgressEvent>;
resolveAuthority(authority: string): Thenable<ResolvedAuthority>; resolveAuthority(authority: string): Thenable<ResolvedAuthority>;
getRemoteAuthorityResolver(authority: string): Thenable<IRemoteAuthorityResolver | null>; setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void;
}
export interface IRemoteAuthorityResolver {
label: string;
path: string;
authorityPrefix: string;
syncExtensions?: boolean;
} }
...@@ -3,48 +3,53 @@ ...@@ -3,48 +3,53 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IChannel } from 'vs/base/parts/ipc/node/ipc'; import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { Event, buffer } from 'vs/base/common/event';
import { ResolvedAuthority, IResolvingProgressEvent, IRemoteAuthorityResolverService, IRemoteAuthorityResolver } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ipcRenderer as ipc } from 'electron'; import { ipcRenderer as ipc } from 'electron';
export class RemoteAuthorityResolverChannelClient implements IRemoteAuthorityResolverService { class PendingResolveAuthorityRequest {
constructor(
public readonly resolve: (value: ResolvedAuthority) => void,
public readonly reject: (err: any) => void,
public readonly promise: Promise<ResolvedAuthority>,
) {
}
}
export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService {
_serviceBrand: any; _serviceBrand: any;
private _resolveAuthorityCache: { [authority: string]: Thenable<ResolvedAuthority>; }; private _pendingResolveAuthorityRequests: { [authority: string]: PendingResolveAuthorityRequest; };
get onResolvingProgress(): Event<IResolvingProgressEvent> { return buffer(this.channel.listen('onResolvingProgress'), true); } private _resolvedAuthorities: { [authority: string]: ResolvedAuthority; };
constructor(private channel: IChannel) { constructor() {
this._resolveAuthorityCache = Object.create(null); this._pendingResolveAuthorityRequests = Object.create(null);
this._resolvedAuthorities = Object.create(null);
} }
resolveAuthority(authority: string): Thenable<ResolvedAuthority> { resolveAuthority(authority: string): Thenable<ResolvedAuthority> {
if (!this._resolveAuthorityCache[authority]) { if (this._resolvedAuthorities[authority]) {
this._resolveAuthorityCache[authority] = this._resolveAuthority(authority); return Promise.resolve(this._resolvedAuthorities[authority]);
this._resolveAuthorityCache[authority].then((r) => { }
ipc.send('vscode:remoteAuthorityResolved', { if (!this._pendingResolveAuthorityRequests[authority]) {
authority: authority, let resolve: (value: ResolvedAuthority) => void;
host: r.host, let reject: (err: any) => void;
port: r.port let promise = new Promise<ResolvedAuthority>((_resolve, _reject) => {
}); resolve = _resolve;
reject = _reject;
}); });
this._pendingResolveAuthorityRequests[authority] = new PendingResolveAuthorityRequest(resolve, reject, promise);
} }
return this._resolveAuthorityCache[authority]; return this._pendingResolveAuthorityRequests[authority].promise;
} }
getRemoteAuthorityResolver(authority: string): Thenable<IRemoteAuthorityResolver | null> { setResolvedAuthority(resolvedAuthority: ResolvedAuthority) {
return this.channel.call('getRemoteAuthorityResolver', [authority]); this._resolvedAuthorities[resolvedAuthority.authority] = resolvedAuthority;
} if (this._pendingResolveAuthorityRequests[resolvedAuthority.authority]) {
let request = this._pendingResolveAuthorityRequests[resolvedAuthority.authority];
private _resolveAuthority(authority: string): Thenable<ResolvedAuthority> { delete this._pendingResolveAuthorityRequests[resolvedAuthority.authority];
if (authority.indexOf('+') >= 0) { ipc.send('vscode:remoteAuthorityResolved', resolvedAuthority);
return this.channel.call('resolveAuthority', [authority]); request.resolve(resolvedAuthority);
} else {
const [host, strPort] = authority.split(':');
const port = parseInt(strPort, 10);
return Promise.resolve({ authority, host, port });
} }
} }
} }
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IServerChannel } from 'vs/base/parts/ipc/node/ipc';
import { Event, buffer } from 'vs/base/common/event';
import { IResolvingProgressEvent, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
export class RemoteAuthorityResolverChannel implements IServerChannel {
onResolvingProgress: Event<IResolvingProgressEvent>;
constructor(private service: IRemoteAuthorityResolverService) {
this.onResolvingProgress = buffer(service.onResolvingProgress, true);
}
listen(_, event: string): Event<any> {
switch (event) {
case 'onResolvingProgress': return this.onResolvingProgress;
}
throw new Error('Invalid listen');
}
call(_, command: string, args?: any): Thenable<any> {
switch (command) {
case 'resolveAuthority': return this.service.resolveAuthority(args[0]);
case 'getRemoteAuthorityResolver': return this.service.getRemoteAuthorityResolver(args[0]);
}
throw new Error('Invalid call');
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IRemoteAuthorityResolverService, ResolvedAuthority, IResolvingProgressEvent, IRemoteAuthorityResolver } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
_serviceBrand: any;
private _onResolvingProgress: Emitter<IResolvingProgressEvent> = this._register(new Emitter<IResolvingProgressEvent>());
readonly onResolvingProgress: Event<IResolvingProgressEvent> = this._onResolvingProgress.event;
constructor(
@IEnvironmentService environmentService: IEnvironmentService,
@IConfigurationService configurationService: IConfigurationService,
@ILogService logService: ILogService,
@IExtensionManagementService extensionManagementService: IExtensionManagementService
) {
super();
}
async resolveAuthority(authority: string): Promise<ResolvedAuthority> {
throw new Error(`Not implemented`);
}
async getRemoteAuthorityResolver(authority: string): Promise<IRemoteAuthorityResolver | null> {
throw new Error(`Not implemented`);
}
}
...@@ -61,10 +61,11 @@ import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow'; ...@@ -61,10 +61,11 @@ import { ExtHostWindow } from 'vs/workbench/api/node/extHostWindow';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { IExtensionDescription, throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionDescription, throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
export interface IExtensionApiFactory { export interface IExtensionApiFactory {
(extension: IExtensionDescription): typeof vscode; (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry): typeof vscode;
} }
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T { function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
...@@ -140,7 +141,7 @@ export function createApiFactory( ...@@ -140,7 +141,7 @@ export function createApiFactory(
// Register API-ish commands // Register API-ish commands
ExtHostApiCommands.register(extHostCommands); ExtHostApiCommands.register(extHostCommands);
return function (extension: IExtensionDescription): typeof vscode { return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry): typeof vscode {
// Check document selectors for being overly generic. Technically this isn't a problem but // Check document selectors for being overly generic. Technically this isn't a problem but
// in practice many extensions say they support `fooLang` but need fs-access to do so. Those // in practice many extensions say they support `fooLang` but need fs-access to do so. Those
...@@ -259,14 +260,14 @@ export function createApiFactory( ...@@ -259,14 +260,14 @@ export function createApiFactory(
// namespace: extensions // namespace: extensions
const extensions: typeof vscode.extensions = { const extensions: typeof vscode.extensions = {
getExtension(extensionId: string): Extension<any> { getExtension(extensionId: string): Extension<any> {
let desc = extensionService.getExtensionDescription(extensionId); let desc = extensionRegistry.getExtensionDescription(extensionId);
if (desc) { if (desc) {
return new Extension(extensionService, desc); return new Extension(extensionService, desc);
} }
return undefined; return undefined;
}, },
get all(): Extension<any>[] { get all(): Extension<any>[] {
return extensionService.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc)); return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
} }
}; };
...@@ -860,11 +861,11 @@ class Extension<T> implements vscode.Extension<T> { ...@@ -860,11 +861,11 @@ class Extension<T> implements vscode.Extension<T> {
} }
} }
export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory): Promise<void> { export function initializeExtensionApi(extensionService: ExtHostExtensionService, apiFactory: IExtensionApiFactory, extensionRegistry: ExtensionDescriptionRegistry): Promise<void> {
return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie)); return extensionService.getExtensionPathIndex().then(trie => defineAPI(apiFactory, trie, extensionRegistry));
} }
function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree<IExtensionDescription>): void { function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchTree<IExtensionDescription>, extensionRegistry: ExtensionDescriptionRegistry): void {
// each extension is meant to get its own api implementation // each extension is meant to get its own api implementation
const extApiImpl = new Map<string, typeof vscode>(); const extApiImpl = new Map<string, typeof vscode>();
...@@ -882,7 +883,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT ...@@ -882,7 +883,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT
if (ext) { if (ext) {
let apiImpl = extApiImpl.get(ext.id); let apiImpl = extApiImpl.get(ext.id);
if (!apiImpl) { if (!apiImpl) {
apiImpl = factory(ext); apiImpl = factory(ext, extensionRegistry);
extApiImpl.set(ext.id, apiImpl); extApiImpl.set(ext.id, apiImpl);
} }
return apiImpl; return apiImpl;
...@@ -893,7 +894,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT ...@@ -893,7 +894,7 @@ function defineAPI(factory: IExtensionApiFactory, extensionPaths: TernarySearchT
let extensionPathsPretty = ''; let extensionPathsPretty = '';
extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.id}\n`); extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.id}\n`);
console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`); console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`);
defaultApiImpl = factory(nullExtensionDescription); defaultApiImpl = factory(nullExtensionDescription, extensionRegistry);
} }
return defaultApiImpl; return defaultApiImpl;
}; };
......
...@@ -43,6 +43,7 @@ import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/pro ...@@ -43,6 +43,7 @@ import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/pro
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
export interface IEnvironment { export interface IEnvironment {
isExtensionDevelopmentDebug: boolean; isExtensionDevelopmentDebug: boolean;
...@@ -50,7 +51,7 @@ export interface IEnvironment { ...@@ -50,7 +51,7 @@ export interface IEnvironment {
appSettingsHome: URI; appSettingsHome: URI;
extensionDevelopmentLocationURI: URI; extensionDevelopmentLocationURI: URI;
extensionTestsPath: string; extensionTestsPath: string;
globalStorageHome: string; globalStorageHome: URI;
} }
export interface IWorkspaceData { export interface IWorkspaceData {
...@@ -70,6 +71,7 @@ export interface IInitData { ...@@ -70,6 +71,7 @@ export interface IInitData {
telemetryInfo: ITelemetryInfo; telemetryInfo: ITelemetryInfo;
logLevel: LogLevel; logLevel: LogLevel;
logsLocation: URI; logsLocation: URI;
autoStart: boolean;
remoteAuthority?: string | null; remoteAuthority?: string | null;
} }
...@@ -732,6 +734,8 @@ export interface ExtHostSearchShape { ...@@ -732,6 +734,8 @@ export interface ExtHostSearchShape {
} }
export interface ExtHostExtensionServiceShape { export interface ExtHostExtensionServiceShape {
$resolveAuthority(remoteAuthority: string): Thenable<ResolvedAuthority>;
$startExtensionHost(enabledExtensionIds: string[]): Thenable<void>;
$activateByEvent(activationEvent: string): Thenable<void>; $activateByEvent(activationEvent: string): Thenable<void>;
} }
......
...@@ -31,6 +31,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati ...@@ -31,6 +31,7 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands'; import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions'; import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/node/extensionDescriptionRegistry';
export class ExtHostDebugService implements ExtHostDebugServiceShape { export class ExtHostDebugService implements ExtHostDebugServiceShape {
...@@ -119,28 +120,29 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -119,28 +120,29 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
this._breakpoints = new Map<string, vscode.Breakpoint>(); this._breakpoints = new Map<string, vscode.Breakpoint>();
this._breakpointEventsActive = false; this._breakpointEventsActive = false;
this._extensionService.getExtensionRegistry().then((extensionRegistry: ExtensionDescriptionRegistry) => {
// register all debug extensions // register all debug extensions
const debugTypes: string[] = []; const debugTypes: string[] = [];
for (const ed of this._extensionService.getAllExtensionDescriptions()) { for (const ed of extensionRegistry.getAllExtensionDescriptions()) {
if (ed.contributes) { if (ed.contributes) {
const debuggers = <IDebuggerContribution[]>ed.contributes['debuggers']; const debuggers = <IDebuggerContribution[]>ed.contributes['debuggers'];
if (debuggers && debuggers.length > 0) { if (debuggers && debuggers.length > 0) {
for (const dbg of debuggers) { for (const dbg of debuggers) {
// only debugger contributions with a "label" are considered a "defining" debugger contribution // only debugger contributions with a "label" are considered a "defining" debugger contribution
if (dbg.type && dbg.label) { if (dbg.type && dbg.label) {
debugTypes.push(dbg.type); debugTypes.push(dbg.type);
if (dbg.adapterExecutableCommand) { if (dbg.adapterExecutableCommand) {
this._aexCommands.set(dbg.type, dbg.adapterExecutableCommand); this._aexCommands.set(dbg.type, dbg.adapterExecutableCommand);
}
} }
} }
} }
} }
} }
} if (debugTypes.length > 0) {
if (debugTypes.length > 0) { this._debugServiceProxy.$registerDebugTypes(debugTypes);
this._debugServiceProxy.$registerDebugTypes(debugTypes); }
} });
} }
// extension debug API // extension debug API
...@@ -722,7 +724,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -722,7 +724,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
}); });
} }
private getAdapterDescriptor(adapterProvider: vscode.DebugAdapterDescriptorFactory, session: ExtHostDebugSession): Thenable<vscode.DebugAdapterDescriptor> { private async getAdapterDescriptor(adapterProvider: vscode.DebugAdapterDescriptorFactory, session: ExtHostDebugSession): Promise<vscode.DebugAdapterDescriptor> {
// a "debugServer" attribute in the launch config takes precedence // a "debugServer" attribute in the launch config takes precedence
const serverPort = session.configuration.debugServer; const serverPort = session.configuration.debugServer;
...@@ -739,7 +741,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -739,7 +741,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
} }
if (adapterProvider) { if (adapterProvider) {
return asThenable(() => adapterProvider.createDebugAdapterDescriptor(session, this.daExecutableFromPackage(session))); const extensionRegistry = await this._extensionService.getExtensionRegistry();
return asThenable(() => adapterProvider.createDebugAdapterDescriptor(session, this.daExecutableFromPackage(session, extensionRegistry)));
} }
// try deprecated command based extension API "adapterExecutableCommand" to determine the executable // try deprecated command based extension API "adapterExecutableCommand" to determine the executable
...@@ -754,11 +757,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { ...@@ -754,11 +757,12 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
} }
// fallback: use executable information from package.json // fallback: use executable information from package.json
return Promise.resolve(this.daExecutableFromPackage(session)); const extensionRegistry = await this._extensionService.getExtensionRegistry();
return Promise.resolve(this.daExecutableFromPackage(session, extensionRegistry));
} }
private daExecutableFromPackage(session: ExtHostDebugSession): DebugAdapterExecutable | undefined { private daExecutableFromPackage(session: ExtHostDebugSession, extensionRegistry: ExtensionDescriptionRegistry): DebugAdapterExecutable | undefined {
const dae = ExecutableDebugAdapter.platformAdapterExecutable(this._extensionService.getAllExtensionDescriptions(), session.type); const dae = ExecutableDebugAdapter.platformAdapterExecutable(extensionRegistry.getAllExtensionDescriptions(), session.type);
if (dae) { if (dae) {
return new DebugAdapterExecutable(dae.command, dae.args, dae.options); return new DebugAdapterExecutable(dae.command, dae.args, dae.options);
} }
......
...@@ -103,7 +103,7 @@ import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc'; ...@@ -103,7 +103,7 @@ import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc';
import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService'; import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService';
import { MulitExtensionManagementService } from 'vs/platform/extensionManagement/node/multiExtensionManagement'; import { MulitExtensionManagementService } from 'vs/platform/extensionManagement/node/multiExtensionManagement';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { RemoteAuthorityResolverChannelClient } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService';
/** /**
* Services that we require for the Shell * Services that we require for the Shell
...@@ -437,8 +437,7 @@ export class WorkbenchShell extends Disposable { ...@@ -437,8 +437,7 @@ export class WorkbenchShell extends Disposable {
serviceCollection.set(IDownloadService, new SyncDescriptor(DownloadService)); serviceCollection.set(IDownloadService, new SyncDescriptor(DownloadService));
serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); serviceCollection.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
const remoteAuthorityResolverChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('remoteAuthorityResolver'))); const remoteAuthorityResolverService = new RemoteAuthorityResolverService();
const remoteAuthorityResolverService = new RemoteAuthorityResolverChannelClient(remoteAuthorityResolverChannel);
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService); const remoteAgentService = new RemoteAgentService(this.configuration, this.notificationService, this.environmentService, remoteAuthorityResolverService);
......
...@@ -3,20 +3,15 @@ ...@@ -3,20 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { join } from 'path';
import { timeout } from 'vs/base/common/async'; import { timeout } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors'; import * as errors from 'vs/base/common/errors';
import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Counter } from 'vs/base/common/numbers'; import { Counter } from 'vs/base/common/numbers';
import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri'; import { URI, setUriThrowOnMissingScheme } from 'vs/base/common/uri';
import { IURITransformer } from 'vs/base/common/uriIpc'; import { IURITransformer } from 'vs/base/common/uriIpc';
import * as pfs from 'vs/base/node/pfs';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/node/ipc';
import { IEnvironment, IInitData, IWorkspaceData, MainContext, MainThreadWorkspaceShape } from 'vs/workbench/api/node/extHost.protocol'; import { IEnvironment, IInitData, MainContext } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration'; import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtensionActivatedByEvent } from 'vs/workbench/api/node/extHostExtensionActivator';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService'; import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace'; import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
...@@ -48,33 +43,26 @@ export function exit(code?: number) { ...@@ -48,33 +43,26 @@ export function exit(code?: number) {
nativeExit(code); nativeExit(code);
} }
interface ITestRunner {
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
}
export class ExtensionHostMain { export class ExtensionHostMain {
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
private _isTerminating: boolean = false; private _isTerminating: boolean;
private _workspace: IWorkspaceData; private readonly _environment: IEnvironment;
private _environment: IEnvironment; private readonly _extensionService: ExtHostExtensionService;
private _extensionService: ExtHostExtensionService; private readonly _extHostConfiguration: ExtHostConfiguration;
private _extHostConfiguration: ExtHostConfiguration; private readonly _extHostLogService: ExtHostLogService;
private _extHostLogService: ExtHostLogService;
private disposables: IDisposable[] = []; private disposables: IDisposable[] = [];
private _searchRequestIdProvider: Counter; private _searchRequestIdProvider: Counter;
private _mainThreadWorkspace: MainThreadWorkspaceShape;
constructor(protocol: IMessagePassingProtocol, initData: IInitData) { constructor(protocol: IMessagePassingProtocol, initData: IInitData) {
this._isTerminating = false;
const uriTransformer: IURITransformer = null; const uriTransformer: IURITransformer = null;
const rpcProtocol = new RPCProtocol(protocol, null, uriTransformer); const rpcProtocol = new RPCProtocol(protocol, null, uriTransformer);
// ensure URIs are transformed and revived // ensure URIs are transformed and revived
initData = this.transform(initData, rpcProtocol); initData = this.transform(initData, rpcProtocol);
this._environment = initData.environment; this._environment = initData.environment;
this._workspace = initData.workspace;
const allowExit = !!this._environment.extensionTestsPath; // to support other test frameworks like Jasmin that use process.exit (https://github.com/Microsoft/vscode/issues/37708) const allowExit = !!this._environment.extensionTestsPath; // to support other test frameworks like Jasmin that use process.exit (https://github.com/Microsoft/vscode/issues/37708)
patchProcess(allowExit); patchProcess(allowExit);
...@@ -90,8 +78,7 @@ export class ExtensionHostMain { ...@@ -90,8 +78,7 @@ export class ExtensionHostMain {
this._extHostLogService.trace('initData', initData); this._extHostLogService.trace('initData', initData);
this._extHostConfiguration = new ExtHostConfiguration(rpcProtocol.getProxy(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration); this._extHostConfiguration = new ExtHostConfiguration(rpcProtocol.getProxy(MainContext.MainThreadConfiguration), extHostWorkspace, initData.configuration);
const mainThreadTelemetry = rpcProtocol.getProxy(MainContext.MainThreadTelemetry); this._extensionService = new ExtHostExtensionService(nativeExit, initData, rpcProtocol, extHostWorkspace, this._extHostConfiguration, this._extHostLogService);
this._extensionService = new ExtHostExtensionService(initData, rpcProtocol, extHostWorkspace, this._extHostConfiguration, this._extHostLogService, mainThreadTelemetry);
// error forwarding and stack trace scanning // 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) Error.stackTraceLimit = 100; // increase number of stack frames (from 10, https://github.com/v8/v8/wiki/Stack-Trace-API)
...@@ -125,17 +112,6 @@ export class ExtensionHostMain { ...@@ -125,17 +112,6 @@ export class ExtensionHostMain {
mainThreadErrors.$onUnexpectedError(data); mainThreadErrors.$onUnexpectedError(data);
} }
}); });
this._mainThreadWorkspace = rpcProtocol.getProxy(MainContext.MainThreadWorkspace);
}
start(): Thenable<void> {
return this._extensionService.onExtensionAPIReady()
.then(() => this.handleEagerExtensions())
.then(() => this.handleExtensionTests())
.then(() => {
this._extHostLogService.info(`eager extensions activated`);
});
} }
terminate(): void { terminate(): void {
...@@ -151,184 +127,22 @@ export class ExtensionHostMain { ...@@ -151,184 +127,22 @@ export class ExtensionHostMain {
// TODO: write to log once we have one // TODO: write to log once we have one
}); });
let allPromises: Thenable<void>[] = []; const extensionsDeactivated = this._extensionService.deactivateAll();
try {
const allExtensions = this._extensionService.getAllExtensionDescriptions();
const allExtensionsIds = allExtensions.map(ext => ext.id);
const activatedExtensions = allExtensionsIds.filter(id => this._extensionService.isActivated(id));
allPromises = activatedExtensions.map((extensionId) => {
return this._extensionService.deactivate(extensionId);
});
} catch (err) {
// TODO: write to log once we have one
}
const extensionsDeactivated = Promise.all(allPromises).then<void>(() => void 0);
// Give extensions 1 second to wrap up any async dispose, then exit // Give extensions 1 second to wrap up any async dispose, then exit in at most 4 seconds
setTimeout(() => { setTimeout(() => {
Promise.race([timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit()); Promise.race([timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit());
}, 1000); }, 1000);
} }
// Handle "eager" activation extensions
private handleEagerExtensions(): Promise<void> {
this._extensionService.activateByEvent('*', true).then(null, (err) => {
console.error(err);
});
return this.handleWorkspaceContainsEagerExtensions();
}
private handleWorkspaceContainsEagerExtensions(): Promise<void> {
if (!this._workspace || this._workspace.folders.length === 0) {
return Promise.resolve(null);
}
return Promise.all(
this._extensionService.getAllExtensionDescriptions().map((desc) => {
return this.handleWorkspaceContainsEagerExtension(desc);
})
).then(() => { });
}
private handleWorkspaceContainsEagerExtension(desc: IExtensionDescription): Promise<void> {
const activationEvents = desc.activationEvents;
if (!activationEvents) {
return Promise.resolve(void 0);
}
const fileNames: string[] = [];
const globPatterns: string[] = [];
for (let i = 0; i < activationEvents.length; i++) {
if (/^workspaceContains:/.test(activationEvents[i])) {
const fileNameOrGlob = activationEvents[i].substr('workspaceContains:'.length);
if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0) {
globPatterns.push(fileNameOrGlob);
} else {
fileNames.push(fileNameOrGlob);
}
}
}
if (fileNames.length === 0 && globPatterns.length === 0) {
return Promise.resolve(void 0);
}
const fileNamePromise = Promise.all(fileNames.map((fileName) => this.activateIfFileName(desc.id, fileName))).then(() => { });
const globPatternPromise = this.activateIfGlobPatterns(desc.id, globPatterns);
return Promise.all([fileNamePromise, globPatternPromise]).then(() => { });
}
private async activateIfFileName(extensionId: string, fileName: string): Promise<void> {
// find exact path
for (const { uri } of this._workspace.folders) {
if (await pfs.exists(join(URI.revive(uri).fsPath, fileName))) {
// the file was found
return (
this._extensionService.activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${fileName}`))
.then(null, err => console.error(err))
);
}
}
return undefined;
}
private async activateIfGlobPatterns(extensionId: string, globPatterns: string[]): Promise<void> {
this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId}, entryPoint: workspaceContains`);
if (globPatterns.length === 0) {
return Promise.resolve(void 0);
}
const tokenSource = new CancellationTokenSource();
const searchP = this._mainThreadWorkspace.$checkExists(globPatterns, tokenSource.token);
const timer = setTimeout(async () => {
tokenSource.cancel();
this._extensionService.activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContainsTimeout:${globPatterns.join(',')}`))
.then(null, err => console.error(err));
}, ExtensionHostMain.WORKSPACE_CONTAINS_TIMEOUT);
let exists: boolean;
try {
exists = await searchP;
} catch (err) {
if (!errors.isPromiseCanceledError(err)) {
console.error(err);
}
}
tokenSource.dispose();
clearTimeout(timer);
if (exists) {
// a file was found matching one of the glob patterns
return (
this._extensionService.activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${globPatterns.join(',')}`))
.then(null, err => console.error(err))
);
}
return Promise.resolve(void 0);
}
private handleExtensionTests(): Promise<void> {
if (!this._environment.extensionTestsPath || !this._environment.extensionDevelopmentLocationURI) {
return Promise.resolve(null);
}
// Require the test runner via node require from the provided path
let testRunner: ITestRunner;
let requireError: Error;
try {
testRunner = <any>require.__$__nodeRequire(this._environment.extensionTestsPath);
} catch (error) {
requireError = error;
}
// Execute the runner if it follows our spec
if (testRunner && typeof testRunner.run === 'function') {
return new Promise<void>((c, e) => {
testRunner.run(this._environment.extensionTestsPath, (error, failures) => {
if (error) {
e(error.toString());
} else {
c(null);
}
// after tests have run, we shutdown the host
this.gracefulExit(failures && failures > 0 ? 1 /* ERROR */ : 0 /* OK */);
});
});
}
// Otherwise make sure to shutdown anyway even in case of an error
else {
this.gracefulExit(1 /* ERROR */);
}
return Promise.reject(new Error(requireError ? requireError.toString() : nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", this._environment.extensionTestsPath)));
}
private transform(initData: IInitData, rpcProtocol: RPCProtocol): IInitData { private transform(initData: IInitData, rpcProtocol: RPCProtocol): IInitData {
initData.extensions.forEach((ext) => (<any>ext).extensionLocation = URI.revive(rpcProtocol.transformIncomingURIs(ext.extensionLocation))); 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.appRoot = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appRoot));
initData.environment.appSettingsHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appSettingsHome)); initData.environment.appSettingsHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.appSettingsHome));
initData.environment.extensionDevelopmentLocationURI = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.extensionDevelopmentLocationURI)); initData.environment.extensionDevelopmentLocationURI = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.extensionDevelopmentLocationURI));
initData.environment.globalStorageHome = URI.revive(rpcProtocol.transformIncomingURIs(initData.environment.globalStorageHome));
initData.logsLocation = URI.revive(rpcProtocol.transformIncomingURIs(initData.logsLocation)); initData.logsLocation = URI.revive(rpcProtocol.transformIncomingURIs(initData.logsLocation));
initData.workspace = rpcProtocol.transformIncomingURIs(initData.workspace); initData.workspace = rpcProtocol.transformIncomingURIs(initData.workspace);
return initData; return initData;
} }
private gracefulExit(code: number): void {
// to give the PH process a chance to flush any outstanding console
// messages to the main process, we delay the exit() by some time
setTimeout(() => exit(code), 500);
}
} }
...@@ -167,7 +167,6 @@ createExtHostProtocol().then(protocol => { ...@@ -167,7 +167,6 @@ createExtHostProtocol().then(protocol => {
// setup things // setup things
const extensionHostMain = new ExtensionHostMain(renderer.protocol, renderer.initData); const extensionHostMain = new ExtensionHostMain(renderer.protocol, renderer.initData);
onTerminate = () => extensionHostMain.terminate(); onTerminate = () => extensionHostMain.terminate();
return extensionHostMain.start();
}).catch(err => console.error(err)); }).catch(err => console.error(err));
function patchExecArgv() { function patchExecArgv() {
......
...@@ -38,7 +38,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; ...@@ -38,7 +38,7 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { randomPort } from 'vs/base/node/ports'; import { randomPort } from 'vs/base/node/ports';
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ILabelService } from 'vs/platform/label/common/label';
import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { renderOcticons } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
import { join } from 'path'; import { join } from 'path';
import { onUnexpectedError } from 'vs/base/common/errors'; import { onUnexpectedError } from 'vs/base/common/errors';
...@@ -117,7 +117,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { ...@@ -117,7 +117,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
@IInstantiationService private readonly _instantiationService: IInstantiationService, @IInstantiationService private readonly _instantiationService: IInstantiationService,
@IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService, @IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService,
@IStorageService storageService: IStorageService, @IStorageService storageService: IStorageService,
@IRemoteAuthorityResolverService private remoteAuthorityResolverService: IRemoteAuthorityResolverService @ILabelService private readonly _labelService: ILabelService
) { ) {
super(RuntimeExtensionsEditor.ID, telemetryService, themeService, storageService); super(RuntimeExtensionsEditor.ID, telemetryService, themeService, storageService);
...@@ -375,11 +375,11 @@ export class RuntimeExtensionsEditor extends BaseEditor { ...@@ -375,11 +375,11 @@ export class RuntimeExtensionsEditor extends BaseEditor {
const el = $('span'); const el = $('span');
el.innerHTML = renderOcticons(`$(rss) ${element.description.extensionLocation.authority}`); el.innerHTML = renderOcticons(`$(rss) ${element.description.extensionLocation.authority}`);
data.msgContainer.appendChild(el); data.msgContainer.appendChild(el);
this.remoteAuthorityResolverService.getRemoteAuthorityResolver(element.description.extensionLocation.authority).then(resolver => {
if (resolver && resolver.label.length) { const hostLabel = this._labelService.getHostLabel();
el.innerHTML = renderOcticons(`$(rss) ${resolver.label}`); if (hostLabel) {
} el.innerHTML = renderOcticons(`$(rss) ${hostLabel}`);
}); }
} }
if (this._profileInfo) { if (this._profileInfo) {
......
...@@ -42,7 +42,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e ...@@ -42,7 +42,7 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e
export interface IExtensionHostStarter { export interface IExtensionHostStarter {
readonly onCrashed: Event<[number, string]>; readonly onCrashed: Event<[number, string]>;
start(): Promise<IMessagePassingProtocol>; start(): Thenable<IMessagePassingProtocol>;
getInspectPort(): number; getInspectPort(): number;
dispose(): void; dispose(): void;
} }
...@@ -93,6 +93,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { ...@@ -93,6 +93,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
private _messageProtocol: Promise<IMessagePassingProtocol>; private _messageProtocol: Promise<IMessagePassingProtocol>;
constructor( constructor(
private readonly _autoStart: boolean,
private readonly _extensions: Promise<IExtensionDescription[]>, private readonly _extensions: Promise<IExtensionDescription[]>,
private readonly _extensionHostLogsLocation: URI, private readonly _extensionHostLogsLocation: URI,
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
...@@ -425,7 +426,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { ...@@ -425,7 +426,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
appSettingsHome: this._environmentService.appSettingsHome ? URI.file(this._environmentService.appSettingsHome) : void 0, appSettingsHome: this._environmentService.appSettingsHome ? URI.file(this._environmentService.appSettingsHome) : void 0,
extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI,
extensionTestsPath: this._environmentService.extensionTestsPath, extensionTestsPath: this._environmentService.extensionTestsPath,
globalStorageHome: this._environmentService.globalStorageHome globalStorageHome: URI.file(this._environmentService.globalStorageHome)
}, },
workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : {
configuration: workspace.configuration, configuration: workspace.configuration,
...@@ -438,7 +439,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { ...@@ -438,7 +439,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter {
configuration: !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment ? { ...configurationData, configurationScopes: getScopes() } : configurationData, configuration: !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment ? { ...configurationData, configurationScopes: getScopes() } : configurationData,
telemetryInfo, telemetryInfo,
logLevel: this._logService.getLevel(), logLevel: this._logService.getLevel(),
logsLocation: this._extensionHostLogsLocation logsLocation: this._extensionHostLogsLocation,
autoStart: this._autoStart
}; };
return r; return r;
}); });
......
...@@ -17,6 +17,7 @@ import { IExtensionHostStarter } from 'vs/workbench/services/extensions/electron ...@@ -17,6 +17,7 @@ import { IExtensionHostStarter } from 'vs/workbench/services/extensions/electron
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler'; import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/node/rpcProtocol'; import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/node/rpcProtocol';
import { ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
// Enable to see detailed message communication between window and extension host // Enable to see detailed message communication between window and extension host
const LOG_EXTENSION_HOST_COMMUNICATION = false; const LOG_EXTENSION_HOST_COMMUNICATION = false;
...@@ -171,6 +172,14 @@ export class ExtensionHostProcessManager extends Disposable { ...@@ -171,6 +172,14 @@ export class ExtensionHostProcessManager extends Disposable {
} }
return 0; return 0;
} }
public resolveAuthority(remoteAuthority: string): Thenable<ResolvedAuthority> {
return this._extensionHostProcessProxy.then(proxy => proxy.value.$resolveAuthority(remoteAuthority));
}
public start(enabledExtensionIds: string[]): Thenable<void> {
return this._extensionHostProcessProxy.then(proxy => proxy.value.$startExtensionHost(enabledExtensionIds));
}
} }
const colorTables = [ const colorTables = [
......
...@@ -112,8 +112,8 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -112,8 +112,8 @@ export class ExtensionService extends Disposable implements IExtensionService {
// reschedule to ensure this runs after restoring viewlets, panels, and editors // reschedule to ensure this runs after restoring viewlets, panels, and editors
runWhenIdle(() => { runWhenIdle(() => {
perf.mark('willLoadExtensions'); perf.mark('willLoadExtensions');
this._startExtensionHostProcess(true, []);
this._scanAndHandleExtensions(); this._scanAndHandleExtensions();
this._startExtensionHostProcess([]);
this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions')); this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions'));
}, 50 /*max delay*/); }, 50 /*max delay*/);
}); });
...@@ -127,11 +127,11 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -127,11 +127,11 @@ export class ExtensionService extends Disposable implements IExtensionService {
public restartExtensionHost(): void { public restartExtensionHost(): void {
this._stopExtensionHostProcess(); this._stopExtensionHostProcess();
this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents)); this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents));
} }
public startExtensionHost(): void { public startExtensionHost(): void {
this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents)); this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents));
} }
public stopExtensionHost(): void { public stopExtensionHost(): void {
...@@ -153,10 +153,10 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -153,10 +153,10 @@ export class ExtensionService extends Disposable implements IExtensionService {
} }
} }
private _startExtensionHostProcess(initialActivationEvents: string[]): void { private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void {
this._stopExtensionHostProcess(); this._stopExtensionHostProcess();
const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, this.getExtensions(), this._extensionHostLogsLocation); const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, !isInitialStart, this.getExtensions(), this._extensionHostLogsLocation);
const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, extHostProcessWorker, null, initialActivationEvents); const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, extHostProcessWorker, null, initialActivationEvents);
extHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal)); extHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal));
extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ target: extHostProcessManager, isResponsive: responsiveState === ResponsiveState.Responsive }); }); extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ target: extHostProcessManager, isResponsive: responsiveState === ResponsiveState.Responsive }); });
...@@ -196,7 +196,7 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -196,7 +196,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
}, },
{ {
label: nls.localize('restart', "Restart Extension Host"), label: nls.localize('restart', "Restart Extension Host"),
run: () => this._startExtensionHostProcess(Object.keys(this._allRequestedActivateEvents)) run: () => this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents))
}] }]
); );
} }
...@@ -318,7 +318,7 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -318,7 +318,7 @@ export class ExtensionService extends Disposable implements IExtensionService {
// --- impl // --- impl
private _scanAndHandleExtensions(): void { private async _scanAndHandleExtensions(): Promise<void> {
this._extensionScanner.startScanningExtensions(new Logger((severity, source, message) => { this._extensionScanner.startScanningExtensions(new Logger((severity, source, message) => {
if (this._isDev && source) { if (this._isDev && source) {
this._logOrShowMessage(severity, `[${source}]: ${message}`); this._logOrShowMessage(severity, `[${source}]: ${message}`);
...@@ -327,25 +327,29 @@ export class ExtensionService extends Disposable implements IExtensionService { ...@@ -327,25 +327,29 @@ export class ExtensionService extends Disposable implements IExtensionService {
} }
})); }));
this._extensionScanner.scannedExtensions const extensionHost = this._extensionHostProcessManagers[0];
.then(allExtensions => this._getRuntimeExtensions(allExtensions)) const extensions = await this._extensionScanner.scannedExtensions;
.then(allExtensions => { const enabledExtensions = await this._getRuntimeExtensions(extensions);
this._registry = new ExtensionDescriptionRegistry(allExtensions); extensionHost.start(enabledExtensions.map(extension => extension.id));
this._onHasExtensions(enabledExtensions);
}
let availableExtensions = this._registry.getAllExtensionDescriptions(); private _onHasExtensions(allExtensions: IExtensionDescription[]): void {
let extensionPoints = ExtensionsRegistry.getExtensionPoints(); this._registry = new ExtensionDescriptionRegistry(allExtensions);
let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); let availableExtensions = this._registry.getAllExtensionDescriptions();
let extensionPoints = ExtensionsRegistry.getExtensionPoints();
for (let i = 0, len = extensionPoints.length; i < len; i++) { let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg);
ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler);
}
perf.mark('extensionHostReady'); for (let i = 0, len = extensionPoints.length; i < len; i++) {
this._installedExtensionsReady.open(); ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler);
this._onDidRegisterExtensions.fire(void 0); }
this._onDidChangeExtensionsStatus.fire(availableExtensions.map(e => e.id));
}); perf.mark('extensionHostReady');
this._installedExtensionsReady.open();
this._onDidRegisterExtensions.fire(void 0);
this._onDidChangeExtensionsStatus.fire(availableExtensions.map(e => e.id));
} }
private _getRuntimeExtensions(allExtensions: IExtensionDescription[]): Promise<IExtensionDescription[]> { private _getRuntimeExtensions(allExtensions: IExtensionDescription[]): Promise<IExtensionDescription[]> {
......
...@@ -8,17 +8,23 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e ...@@ -8,17 +8,23 @@ import { IExtensionDescription } from 'vs/workbench/services/extensions/common/e
const hasOwnProperty = Object.hasOwnProperty; const hasOwnProperty = Object.hasOwnProperty;
export class ExtensionDescriptionRegistry { export class ExtensionDescriptionRegistry {
private _extensionDescriptions: IExtensionDescription[];
private _extensionsMap: { [extensionId: string]: IExtensionDescription; }; private _extensionsMap: { [extensionId: string]: IExtensionDescription; };
private _extensionsArr: IExtensionDescription[]; private _extensionsArr: IExtensionDescription[];
private _activationMap: { [activationEvent: string]: IExtensionDescription[]; }; private _activationMap: { [activationEvent: string]: IExtensionDescription[]; };
constructor(extensionDescriptions: IExtensionDescription[]) { constructor(extensionDescriptions: IExtensionDescription[]) {
this._extensionDescriptions = extensionDescriptions;
this._initialize();
}
private _initialize(): void {
this._extensionsMap = {}; this._extensionsMap = {};
this._extensionsArr = []; this._extensionsArr = [];
this._activationMap = {}; this._activationMap = {};
for (let i = 0, len = extensionDescriptions.length; i < len; i++) { for (let i = 0, len = this._extensionDescriptions.length; i < len; i++) {
let extensionDescription = extensionDescriptions[i]; let extensionDescription = this._extensionDescriptions[i];
if (hasOwnProperty.call(this._extensionsMap, extensionDescription.id)) { if (hasOwnProperty.call(this._extensionsMap, extensionDescription.id)) {
// No overwriting allowed! // No overwriting allowed!
...@@ -45,6 +51,13 @@ export class ExtensionDescriptionRegistry { ...@@ -45,6 +51,13 @@ export class ExtensionDescriptionRegistry {
} }
} }
public keepOnly(extensionIds: string[]): void {
let toKeep = new Set<string>();
extensionIds.forEach(extensionId => toKeep.add(extensionId));
this._extensionDescriptions = this._extensionDescriptions.filter(extension => toKeep.has(extension.id));
this._initialize();
}
public containsActivationEvent(activationEvent: string): boolean { public containsActivationEvent(activationEvent: string): boolean {
return hasOwnProperty.call(this._activationMap, activationEvent); return hasOwnProperty.call(this._activationMap, activationEvent);
} }
......
...@@ -41,7 +41,7 @@ class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection ...@@ -41,7 +41,7 @@ class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection
readonly remoteAuthority: string; readonly remoteAuthority: string;
private _connection: Thenable<Client<RemoteAgentConnectionContext>> | null; private _connection: Thenable<Client<RemoteAgentConnectionContext>> | null;
private _environment: Thenable<IRemoteAgentEnvironment | null> | null; private _environment: Thenable<IRemoteAgentEnvironment> | null;
constructor( constructor(
remoteAuthority: string, remoteAuthority: string,
...@@ -55,7 +55,7 @@ class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection ...@@ -55,7 +55,7 @@ class RemoteAgentConnection extends Disposable implements IRemoteAgentConnection
this._environment = null; this._environment = null;
} }
getEnvironment(): Thenable<IRemoteAgentEnvironment | null> { getEnvironment(): Thenable<IRemoteAgentEnvironment> {
if (!this._environment) { if (!this._environment) {
const client = new RemoteExtensionEnvironmentChannelClient(this.getChannel('remoteextensionsenvironment')); const client = new RemoteExtensionEnvironmentChannelClient(this.getChannel('remoteextensionsenvironment'));
......
...@@ -16,6 +16,7 @@ export interface IRemoteAgentEnvironmentDTO { ...@@ -16,6 +16,7 @@ export interface IRemoteAgentEnvironmentDTO {
logsPath: UriComponents; logsPath: UriComponents;
extensionsPath: UriComponents; extensionsPath: UriComponents;
extensionHostLogsPath: UriComponents; extensionHostLogsPath: UriComponents;
globalStorageHome: UriComponents;
extensions: IExtensionDescription[]; extensions: IExtensionDescription[];
os: OperatingSystem; os: OperatingSystem;
} }
...@@ -34,6 +35,7 @@ export class RemoteExtensionEnvironmentChannelClient { ...@@ -34,6 +35,7 @@ export class RemoteExtensionEnvironmentChannelClient {
logsPath: URI.revive(data.logsPath), logsPath: URI.revive(data.logsPath),
extensionsPath: URI.revive(data.extensionsPath), extensionsPath: URI.revive(data.extensionsPath),
extensionHostLogsPath: URI.revive(data.extensionHostLogsPath), extensionHostLogsPath: URI.revive(data.extensionHostLogsPath),
globalStorageHome: URI.revive(data.globalStorageHome),
extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }), extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }),
os: data.os os: data.os
}; };
......
...@@ -21,6 +21,7 @@ export interface IRemoteAgentEnvironment { ...@@ -21,6 +21,7 @@ export interface IRemoteAgentEnvironment {
logsPath: URI; logsPath: URI;
extensionsPath: URI; extensionsPath: URI;
extensionHostLogsPath: URI; extensionHostLogsPath: URI;
globalStorageHome: URI;
extensions: IExtensionDescription[]; extensions: IExtensionDescription[];
os: OperatingSystem; os: OperatingSystem;
} }
...@@ -34,7 +35,7 @@ export interface IRemoteAgentService { ...@@ -34,7 +35,7 @@ export interface IRemoteAgentService {
export interface IRemoteAgentConnection { export interface IRemoteAgentConnection {
readonly remoteAuthority: string; readonly remoteAuthority: string;
getEnvironment(): Thenable<IRemoteAgentEnvironment | null>; getEnvironment(): Thenable<IRemoteAgentEnvironment>;
getChannel<T extends IChannel>(channelName: string): T; getChannel<T extends IChannel>(channelName: string): T;
registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T); registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册