Merge from vscode 591842cc4b71958c81947b254924a215fe3edcbd (#4886)

This commit is contained in:
Karl Burtram
2019-04-05 14:14:26 -07:00
committed by GitHub
parent 657adafb7d
commit 0532346f4f
117 changed files with 1691 additions and 1191 deletions

View File

@@ -125,7 +125,6 @@ export interface IConfigurationData {
user: IConfigurationModel;
workspace: IConfigurationModel;
folders: { [folder: string]: IConfigurationModel };
isComplete: boolean;
}
export function compare(from: IConfigurationModel, to: IConfigurationModel): { added: string[], removed: string[], updated: string[] } {

View File

@@ -513,8 +513,7 @@ export class Configuration {
const { contents, overrides, keys } = this._folderConfigurations.get(folder)!;
result[folder.toString()] = { contents, overrides, keys };
return result;
}, Object.create({})),
isComplete: true
}, Object.create({}))
};
}

View File

@@ -22,9 +22,14 @@ export interface SystemInfo extends IMachineInfo {
processArgs: string;
gpuStatus: any;
screenReader: string;
remoteData: IRemoteDiagnosticInfo[];
load?: string;
}
export interface IRemoteDiagnosticInfo extends IDiagnosticInfo {
hostName: string;
}
export interface IDiagnosticInfoOptions {
includeProcesses?: boolean;
folders?: UriComponents[];

View File

@@ -15,7 +15,7 @@ import { app } from 'electron';
import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
import { IMachineInfo, WorkspaceStats, SystemInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
import { collectWorkspaceStats, getMachineInfo } from 'vs/platform/diagnostics/node/diagnosticsService';
import { ProcessItem } from 'vs/base/common/processes';
@@ -46,12 +46,21 @@ export interface PerformanceInfo {
processInfo?: string;
workspaceInfo?: string;
}
export class DiagnosticsService implements IDiagnosticsService {
_serviceBrand: any;
formatEnvironment(info: IMainProcessInfo): string {
private formatMachineInfo(info: IMachineInfo): string {
const output: string[] = [];
output.push(`OS Version: ${info.os}`);
output.push(`CPUs: ${info.cpus}`);
output.push(`Memory (System): ${info.memory}`);
output.push(`VM: ${info.vmHint}`);
return output.join('\n');
}
private formatEnvironment(info: IMainProcessInfo): string {
const MB = 1024 * 1024;
const GB = 1024 * MB;
@@ -76,10 +85,40 @@ export class DiagnosticsService implements IDiagnosticsService {
async getPerformanceInfo(launchService: ILaunchService): Promise<PerformanceInfo> {
const info = await launchService.getMainProcessInfo();
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(result => {
const [rootProcess, workspaceInfo] = result;
return Promise.all<ProcessItem, string>([listProcesses(info.mainPID), this.formatWorkspaceMetadata(info)]).then(async result => {
let [rootProcess, workspaceInfo] = result;
let processInfo = this.formatProcessList(info, rootProcess);
try {
const remoteData = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
remoteData.forEach(diagnostics => {
processInfo += `\n\nRemote: ${diagnostics.hostName}`;
if (diagnostics.processes) {
processInfo += `\n${this.formatProcessList(info, diagnostics.processes)}`;
}
if (diagnostics.workspaceMetadata) {
workspaceInfo += `\n| Remote: ${diagnostics.hostName}`;
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
workspaceInfo += `| Folder (${folder}): ${countMessage}`;
workspaceInfo += this.formatWorkspaceStats(metadata);
}
}
});
} catch (e) {
processInfo += `\nFetching remote data failed: ${e}`;
workspaceInfo += `\nFetching remote data failed: ${e}`;
}
return {
processInfo: this.formatProcessList(info, rootProcess),
processInfo,
workspaceInfo
};
});
@@ -95,7 +134,8 @@ export class DiagnosticsService implements IDiagnosticsService {
vmHint,
processArgs: `${info.mainArguments.join(' ')}`,
gpuStatus: app.getGPUFeatureStatus(),
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`
screenReader: `${app.isAccessibilitySupportEnabled() ? 'yes' : 'no'}`,
remoteData: await launchService.getRemoteDiagnostics({ includeProcesses: false, includeWorkspaceMetadata: false })
};
@@ -120,12 +160,42 @@ export class DiagnosticsService implements IDiagnosticsService {
output.push(this.formatProcessList(info, rootProcess));
// Workspace Stats
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0)) {
if (info.windows.some(window => window.folderURIs && window.folderURIs.length > 0 && !window.remoteAuthority)) {
output.push('');
output.push('Workspace Stats: ');
output.push(await this.formatWorkspaceMetadata(info));
}
try {
const data = await launchService.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true });
data.forEach(diagnostics => {
output.push('\n\n');
output.push(`Remote: ${diagnostics.hostName}`);
output.push(this.formatMachineInfo(diagnostics.machineInfo));
if (diagnostics.processes) {
output.push(this.formatProcessList(info, diagnostics.processes));
}
if (diagnostics.workspaceMetadata) {
for (const folder of Object.keys(diagnostics.workspaceMetadata)) {
const metadata = diagnostics.workspaceMetadata[folder];
let countMessage = `${metadata.fileCount} files`;
if (metadata.maxFilesReached) {
countMessage = `more than ${countMessage}`;
}
output.push(`Folder (${folder}): ${countMessage}`);
output.push(this.formatWorkspaceStats(metadata));
}
}
});
} catch (e) {
output.push('\n\n');
output.push(`Fetching status information from remotes failed: ${e.message}`);
}
output.push('');
output.push('');
@@ -195,7 +265,7 @@ export class DiagnosticsService implements IDiagnosticsService {
const workspaceStatPromises: Promise<void>[] = [];
info.windows.forEach(window => {
if (window.folderURIs.length === 0) {
if (window.folderURIs.length === 0 || !!window.remoteAuthority) {
return;
}

View File

@@ -37,7 +37,7 @@ export interface ParsedArgs {
logExtensionHostCommunication?: boolean;
'extensions-dir'?: string;
'builtin-extensions-dir'?: string;
extensionDevelopmentPath?: string; // either a local path or a URI
extensionDevelopmentPath?: string | string[]; // one or more local paths or URIs
extensionTestsPath?: string; // either a local path or a URI
'inspect-extensions'?: string;
'inspect-brk-extensions'?: string;
@@ -124,7 +124,7 @@ export interface IEnvironmentService {
disableExtensions: boolean | string[];
builtinExtensionsPath: string;
extensionsPath: string;
extensionDevelopmentLocationURI?: URI;
extensionDevelopmentLocationURI?: URI | URI[];
extensionTestsLocationURI?: URI;
debugExtensionHost: IExtensionHostDebugParams;

View File

@@ -172,9 +172,16 @@ export class EnvironmentService implements IEnvironmentService {
}
@memoize
get extensionDevelopmentLocationURI(): URI | undefined {
get extensionDevelopmentLocationURI(): URI | URI[] | undefined {
const s = this._args.extensionDevelopmentPath;
if (s) {
if (Array.isArray(s)) {
return s.map(p => {
if (/^[^:/?#]+?:\/\//.test(p)) {
return URI.parse(p);
}
return URI.file(path.normalize(p));
});
} else if (s) {
if (/^[^:/?#]+?:\/\//.test(s)) {
return URI.parse(s);
}

View File

@@ -1,388 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions';
const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled';
const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled';
export class ExtensionEnablementService extends Disposable implements IExtensionEnablementService {
_serviceBrand: any;
private _onEnablementChanged = new Emitter<IExtension[]>();
public readonly onEnablementChanged: Event<IExtension[]> = this._onEnablementChanged.event;
private readonly storageManger: StorageManager;
constructor(
@IStorageService storageService: IStorageService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService
) {
super();
this.storageManger = this._register(new StorageManager(storageService));
this._register(this.storageManger.onDidChange(extensions => this.onDidChangeStorage(extensions)));
this._register(extensionManagementService.onDidInstallExtension(this._onDidInstallExtension, this));
this._register(extensionManagementService.onDidUninstallExtension(this._onDidUninstallExtension, this));
}
private get hasWorkspace(): boolean {
return this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY;
}
get allUserExtensionsDisabled(): boolean {
return this.environmentService.disableExtensions === true;
}
async getDisabledExtensions(): Promise<IExtensionIdentifier[]> {
let result = this._getDisabledExtensions(StorageScope.GLOBAL);
if (this.hasWorkspace) {
for (const e of this._getDisabledExtensions(StorageScope.WORKSPACE)) {
if (!result.some(r => areSameExtensions(r, e))) {
result.push(e);
}
}
const workspaceEnabledExtensions = this._getEnabledExtensions(StorageScope.WORKSPACE);
if (workspaceEnabledExtensions.length) {
result = result.filter(r => !workspaceEnabledExtensions.some(e => areSameExtensions(e, r)));
}
}
if (this.environmentService.disableExtensions) {
const allInstalledExtensions = await this.extensionManagementService.getInstalled();
for (const installedExtension of allInstalledExtensions) {
if (this._isExtensionDisabledInEnvironment(installedExtension)) {
if (!result.some(r => areSameExtensions(r, installedExtension.identifier))) {
result.push(installedExtension.identifier);
}
}
}
}
return result;
}
getEnablementState(extension: IExtension): EnablementState {
if (this._isExtensionDisabledInEnvironment(extension)) {
return EnablementState.Disabled;
}
const identifier = extension.identifier;
if (this.hasWorkspace) {
if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.WorkspaceEnabled;
}
if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.WorkspaceDisabled;
}
}
if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.Disabled;
}
return EnablementState.Enabled;
}
canChangeEnablement(extension: IExtension): boolean {
if (extension.manifest && extension.manifest.contributes && extension.manifest.contributes.localizations && extension.manifest.contributes.localizations.length) {
return false;
}
if (extension.type === ExtensionType.User && this.environmentService.disableExtensions) {
return false;
}
return true;
}
async setEnablement(extensions: IExtension[], newState: EnablementState): Promise<boolean[]> {
const workspace = newState === EnablementState.WorkspaceDisabled || newState === EnablementState.WorkspaceEnabled;
if (workspace && !this.hasWorkspace) {
return Promise.reject(new Error(localize('noWorkspace', "No workspace.")));
}
const result = await Promise.all(extensions.map(e => this._setEnablement(e, newState)));
const changedExtensions = extensions.filter((e, index) => result[index]);
if (changedExtensions.length) {
this._onEnablementChanged.fire(changedExtensions);
}
return result;
}
private _setEnablement(extension: IExtension, newState: EnablementState): Promise<boolean> {
const currentState = this._getEnablementState(extension.identifier);
if (currentState === newState) {
return Promise.resolve(false);
}
switch (newState) {
case EnablementState.Enabled:
this._enableExtension(extension.identifier);
break;
case EnablementState.Disabled:
this._disableExtension(extension.identifier);
break;
case EnablementState.WorkspaceEnabled:
this._enableExtensionInWorkspace(extension.identifier);
break;
case EnablementState.WorkspaceDisabled:
this._disableExtensionInWorkspace(extension.identifier);
break;
}
return Promise.resolve(true);
}
isEnabled(extension: IExtension): boolean {
const enablementState = this.getEnablementState(extension);
return enablementState === EnablementState.WorkspaceEnabled || enablementState === EnablementState.Enabled;
}
private _isExtensionDisabledInEnvironment(extension: IExtension): boolean {
if (this.allUserExtensionsDisabled) {
return extension.type === ExtensionType.User;
}
const disabledExtensions = this.environmentService.disableExtensions;
if (Array.isArray(disabledExtensions)) {
return disabledExtensions.some(id => areSameExtensions({ id }, extension.identifier));
}
return false;
}
private _getEnablementState(identifier: IExtensionIdentifier): EnablementState {
if (this.hasWorkspace) {
if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.WorkspaceEnabled;
}
if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.WorkspaceDisabled;
}
}
if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) {
return EnablementState.Disabled;
}
return EnablementState.Enabled;
}
private _enableExtension(identifier: IExtensionIdentifier): void {
this._removeFromDisabledExtensions(identifier, StorageScope.WORKSPACE);
this._removeFromEnabledExtensions(identifier, StorageScope.WORKSPACE);
this._removeFromDisabledExtensions(identifier, StorageScope.GLOBAL);
}
private _disableExtension(identifier: IExtensionIdentifier): void {
this._removeFromDisabledExtensions(identifier, StorageScope.WORKSPACE);
this._removeFromEnabledExtensions(identifier, StorageScope.WORKSPACE);
this._addToDisabledExtensions(identifier, StorageScope.GLOBAL);
}
private _enableExtensionInWorkspace(identifier: IExtensionIdentifier): void {
this._removeFromDisabledExtensions(identifier, StorageScope.WORKSPACE);
this._addToEnabledExtensions(identifier, StorageScope.WORKSPACE);
}
private _disableExtensionInWorkspace(identifier: IExtensionIdentifier): void {
this._addToDisabledExtensions(identifier, StorageScope.WORKSPACE);
this._removeFromEnabledExtensions(identifier, StorageScope.WORKSPACE);
}
private _addToDisabledExtensions(identifier: IExtensionIdentifier, scope: StorageScope): Promise<boolean> {
if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) {
return Promise.resolve(false);
}
let disabledExtensions = this._getDisabledExtensions(scope);
if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) {
disabledExtensions.push(identifier);
this._setDisabledExtensions(disabledExtensions, scope);
return Promise.resolve(true);
}
return Promise.resolve(false);
}
private _removeFromDisabledExtensions(identifier: IExtensionIdentifier, scope: StorageScope): boolean {
if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) {
return false;
}
let disabledExtensions = this._getDisabledExtensions(scope);
for (let index = 0; index < disabledExtensions.length; index++) {
const disabledExtension = disabledExtensions[index];
if (areSameExtensions(disabledExtension, identifier)) {
disabledExtensions.splice(index, 1);
this._setDisabledExtensions(disabledExtensions, scope);
return true;
}
}
return false;
}
private _addToEnabledExtensions(identifier: IExtensionIdentifier, scope: StorageScope): boolean {
if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) {
return false;
}
let enabledExtensions = this._getEnabledExtensions(scope);
if (enabledExtensions.every(e => !areSameExtensions(e, identifier))) {
enabledExtensions.push(identifier);
this._setEnabledExtensions(enabledExtensions, scope);
return true;
}
return false;
}
private _removeFromEnabledExtensions(identifier: IExtensionIdentifier, scope: StorageScope): boolean {
if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) {
return false;
}
let enabledExtensions = this._getEnabledExtensions(scope);
for (let index = 0; index < enabledExtensions.length; index++) {
const disabledExtension = enabledExtensions[index];
if (areSameExtensions(disabledExtension, identifier)) {
enabledExtensions.splice(index, 1);
this._setEnabledExtensions(enabledExtensions, scope);
return true;
}
}
return false;
}
private _getEnabledExtensions(scope: StorageScope): IExtensionIdentifier[] {
return this._getExtensions(ENABLED_EXTENSIONS_STORAGE_PATH, scope);
}
private _setEnabledExtensions(enabledExtensions: IExtensionIdentifier[], scope: StorageScope): void {
this._setExtensions(ENABLED_EXTENSIONS_STORAGE_PATH, enabledExtensions, scope);
}
private _getDisabledExtensions(scope: StorageScope): IExtensionIdentifier[] {
return this._getExtensions(DISABLED_EXTENSIONS_STORAGE_PATH, scope);
}
private _setDisabledExtensions(disabledExtensions: IExtensionIdentifier[], scope: StorageScope): void {
this._setExtensions(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions, scope);
}
private _getExtensions(storageId: string, scope: StorageScope): IExtensionIdentifier[] {
if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) {
return [];
}
return this.storageManger.get(storageId, scope);
}
private _setExtensions(storageId: string, extensions: IExtensionIdentifier[], scope: StorageScope): void {
this.storageManger.set(storageId, extensions, scope);
}
private async onDidChangeStorage(extensionIdentifiers: IExtensionIdentifier[]): Promise<void> {
const installedExtensions = await this.extensionManagementService.getInstalled();
const extensions = installedExtensions.filter(installedExtension => extensionIdentifiers.some(identifier => areSameExtensions(identifier, installedExtension.identifier)));
this._onEnablementChanged.fire(extensions);
}
private _onDidInstallExtension(event: DidInstallExtensionEvent): void {
if (event.local && event.operation === InstallOperation.Install) {
const wasDisabled = !this.isEnabled(event.local);
this._reset(event.local.identifier);
if (wasDisabled) {
this._onEnablementChanged.fire([event.local]);
}
}
}
private _onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void {
if (!error) {
this._reset(identifier);
}
}
private _reset(extension: IExtensionIdentifier) {
this._removeFromDisabledExtensions(extension, StorageScope.WORKSPACE);
this._removeFromEnabledExtensions(extension, StorageScope.WORKSPACE);
this._removeFromDisabledExtensions(extension, StorageScope.GLOBAL);
}
}
class StorageManager extends Disposable {
private storage: { [key: string]: string } = Object.create(null);
private _onDidChange: Emitter<IExtensionIdentifier[]> = this._register(new Emitter<IExtensionIdentifier[]>());
readonly onDidChange: Event<IExtensionIdentifier[]> = this._onDidChange.event;
constructor(private storageService: IStorageService) {
super();
this._register(storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
}
get(key: string, scope: StorageScope): IExtensionIdentifier[] {
let value: string;
if (scope === StorageScope.GLOBAL) {
if (isUndefinedOrNull(this.storage[key])) {
this.storage[key] = this._get(key, scope);
}
value = this.storage[key];
} else {
value = this._get(key, scope);
}
return JSON.parse(value);
}
set(key: string, value: IExtensionIdentifier[], scope: StorageScope): void {
let newValue: string = JSON.stringify(value.map(({ id, uuid }) => (<IExtensionIdentifier>{ id, uuid })));
const oldValue = this._get(key, scope);
if (oldValue !== newValue) {
if (scope === StorageScope.GLOBAL) {
if (value.length) {
this.storage[key] = newValue;
} else {
delete this.storage[key];
}
}
this._set(key, value.length ? newValue : undefined, scope);
}
}
private onDidStorageChange(workspaceStorageChangeEvent: IWorkspaceStorageChangeEvent): void {
if (workspaceStorageChangeEvent.scope === StorageScope.GLOBAL) {
if (!isUndefinedOrNull(this.storage[workspaceStorageChangeEvent.key])) {
const newValue = this._get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
if (newValue !== this.storage[workspaceStorageChangeEvent.key]) {
const oldValues = this.get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
delete this.storage[workspaceStorageChangeEvent.key];
const newValues = this.get(workspaceStorageChangeEvent.key, workspaceStorageChangeEvent.scope);
const added = oldValues.filter(oldValue => !newValues.some(newValue => areSameExtensions(oldValue, newValue)));
const removed = newValues.filter(newValue => !oldValues.some(oldValue => areSameExtensions(oldValue, newValue)));
if (added.length || removed.length) {
this._onDidChange.fire([...added, ...removed]);
}
}
}
}
}
private _get(key: string, scope: StorageScope): string {
return this.storageService.get(key, scope, '[]');
}
private _set(key: string, value: string | undefined, scope: StorageScope): void {
if (value) {
this.storageService.store(key, value, scope);
} else {
this.storageService.remove(key, scope);
}
}
}

View File

@@ -245,12 +245,6 @@ export interface IExtensionEnablementService {
*/
onEnablementChanged: Event<IExtension[]>;
/**
* Returns all disabled extension identifiers for current workspace
* Returns an empty array if none exist
*/
getDisabledExtensions(): Promise<IExtensionIdentifier[]>;
/**
* Returns the enablement state for the given extension
*/

View File

@@ -1,478 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as sinon from 'sinon';
import { IExtensionManagementService, IExtensionEnablementService, DidUninstallExtensionEvent, EnablementState, ILocalExtension, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { Emitter } from 'vs/base/common/event';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionContributions, ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions';
import { isUndefinedOrNull } from 'vs/base/common/types';
function storageService(instantiationService: TestInstantiationService): IStorageService {
let service = instantiationService.get(IStorageService);
if (!service) {
let workspaceContextService = instantiationService.get(IWorkspaceContextService);
if (!workspaceContextService) {
workspaceContextService = instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{
getWorkbenchState: () => WorkbenchState.FOLDER,
});
}
service = instantiationService.stub(IStorageService, new InMemoryStorageService());
}
return service;
}
export class TestExtensionEnablementService extends ExtensionEnablementService {
constructor(instantiationService: TestInstantiationService) {
super(storageService(instantiationService), instantiationService.get(IWorkspaceContextService),
instantiationService.get(IEnvironmentService) || instantiationService.stub(IEnvironmentService, {} as IEnvironmentService),
instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService,
{ onDidInstallExtension: new Emitter<DidInstallExtensionEvent>().event, onDidUninstallExtension: new Emitter<DidUninstallExtensionEvent>().event } as IExtensionManagementService));
}
public async reset(): Promise<void> {
return this.getDisabledExtensions().then(extensions => extensions.forEach(d => this.setEnablement([aLocalExtension(d.id)], EnablementState.Enabled)));
}
}
suite('ExtensionEnablementService Test', () => {
let instantiationService: TestInstantiationService;
let testObject: IExtensionEnablementService;
const didUninstallEvent = new Emitter<DidUninstallExtensionEvent>();
const didInstallEvent = new Emitter<DidInstallExtensionEvent>();
setup(() => {
instantiationService = new TestInstantiationService();
instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([] as ILocalExtension[]) } as IExtensionManagementService);
testObject = new TestExtensionEnablementService(instantiationService);
});
teardown(() => {
(<ExtensionEnablementService>testObject).dispose();
});
test('test when no extensions are disabled', () => {
return testObject.getDisabledExtensions().then(extensions => assert.deepEqual([], extensions));
});
test('test when no extensions are disabled for workspace when there is no workspace', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => {
instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY);
return testObject.getDisabledExtensions().then(extensions => assert.deepEqual([], extensions));
});
});
test('test disable an extension globally', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([{ id: 'pub.a' }], extensions));
});
test('test disable an extension globally should return truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(value => assert.ok(value));
});
test('test disable an extension globally triggers the change event', () => {
const target = sinon.spy();
testObject.onEnablementChanged(target);
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => {
assert.ok(target.calledOnce);
assert.deepEqual((<IExtension>target.args[0][0][0]).identifier, { id: 'pub.a' });
});
});
test('test disable an extension globally again should return a falsy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(value => assert.ok(!value[0]));
});
test('test state of globally disabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled));
});
test('test state of globally enabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled));
});
test('test disable an extension for workspace', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([{ id: 'pub.a' }], extensions));
});
test('test disable an extension for workspace returns a truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(value => assert.ok(value));
});
test('test disable an extension for workspace again should return a falsy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(value => assert.ok(!value[0]));
});
test('test state of workspace disabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled));
});
test('test state of workspace and globally disabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled));
});
test('test state of workspace enabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled));
});
test('test state of globally disabled and workspace enabled extension', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled));
});
test('test state of an extension when disabled for workspace from workspace enabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled));
});
test('test state of an extension when disabled globally from workspace enabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled));
});
test('test state of an extension when disabled globally from workspace disabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled));
});
test('test state of an extension when enabled globally from workspace enabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled));
});
test('test state of an extension when enabled globally from workspace disabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled));
});
test('test disable an extension for workspace and then globally', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([{ id: 'pub.a' }], extensions));
});
test('test disable an extension for workspace and then globally return a truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(value => assert.ok(value));
});
test('test disable an extension for workspace and then globally trigger the change event', () => {
const target = sinon.spy();
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.onEnablementChanged(target))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => {
assert.ok(target.calledOnce);
assert.deepEqual((<IExtension>target.args[0][0][0]).identifier, { id: 'pub.a' });
});
});
test('test disable an extension globally and then for workspace', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([{ id: 'pub.a' }], extensions));
});
test('test disable an extension globally and then for workspace return a truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(value => assert.ok(value));
});
test('test disable an extension globally and then for workspace triggers the change event', () => {
const target = sinon.spy();
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.onEnablementChanged(target))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled))
.then(() => {
assert.ok(target.calledOnce);
assert.deepEqual((<IExtension>target.args[0][0][0]).identifier, { id: 'pub.a' });
});
});
test('test disable an extension for workspace when there is no workspace throws error', () => {
instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY);
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => assert.fail('should throw an error'), error => assert.ok(error));
});
test('test enable an extension globally', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([], extensions));
});
test('test enable an extension globally return truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(value => assert.ok(value));
});
test('test enable an extension globally triggers change event', () => {
const target = sinon.spy();
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => testObject.onEnablementChanged(target))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => {
assert.ok(target.calledOnce);
assert.deepEqual((<IExtension>target.args[0][0][0]).identifier, { id: 'pub.a' });
});
});
test('test enable an extension globally when already enabled return falsy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)
.then(value => assert.ok(!value[0]));
});
test('test enable an extension for workspace', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([], extensions));
});
test('test enable an extension for workspace return truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(value => assert.ok(value));
});
test('test enable an extension for workspace triggers change event', () => {
const target = sinon.spy();
return testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceDisabled)
.then(() => testObject.onEnablementChanged(target))
.then(() => testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceEnabled))
.then(() => {
assert.ok(target.calledOnce);
assert.deepEqual((<IExtension>target.args[0][0][0]).identifier, { id: 'pub.b' });
});
});
test('test enable an extension for workspace when already enabled return truthy promise', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)
.then(value => assert.ok(value));
});
test('test enable an extension for workspace when disabled in workspace and gloablly', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([], extensions));
});
test('test enable an extension globally when disabled in workspace and gloablly', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([], extensions));
});
test('test installing an extension re-eanbles it when disabled globally', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.Disabled);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install });
const extensions = await testObject.getDisabledExtensions();
assert.deepEqual([], extensions);
});
test('test updating an extension does not re-eanbles it when disabled globally', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.Disabled);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update });
const extensions = await testObject.getDisabledExtensions();
assert.deepEqual([{ id: 'pub.a' }], extensions);
});
test('test installing an extension fires enablement change event when disabled globally', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.Disabled);
return new Promise((c, e) => {
testObject.onEnablementChanged(([e]) => {
if (e.identifier.id === local.identifier.id) {
c();
}
});
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install });
});
});
test('test updating an extension does not fires enablement change event when disabled globally', async () => {
const target = sinon.spy();
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.Disabled);
testObject.onEnablementChanged(target);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update });
assert.ok(!target.called);
});
test('test installing an extension re-eanbles it when workspace disabled', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.WorkspaceDisabled);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install });
const extensions = await testObject.getDisabledExtensions();
assert.deepEqual([], extensions);
});
test('test updating an extension does not re-eanbles it when workspace disabled', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.WorkspaceDisabled);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update });
const extensions = await testObject.getDisabledExtensions();
assert.deepEqual([{ id: 'pub.a' }], extensions);
});
test('test installing an extension fires enablement change event when workspace disabled', async () => {
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.WorkspaceDisabled);
return new Promise((c, e) => {
testObject.onEnablementChanged(([e]) => {
if (e.identifier.id === local.identifier.id) {
c();
}
});
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install });
});
});
test('test updating an extension does not fires enablement change event when workspace disabled', async () => {
const target = sinon.spy();
const local = aLocalExtension('pub.a');
await testObject.setEnablement([local], EnablementState.WorkspaceDisabled);
testObject.onEnablementChanged(target);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update });
assert.ok(!target.called);
});
test('test installing an extension should not fire enablement change event when extension is not disabled', async () => {
const target = sinon.spy();
const local = aLocalExtension('pub.a');
testObject.onEnablementChanged(target);
didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install });
assert.ok(!target.called);
});
test('test remove an extension from disablement list when uninstalled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled))
.then(() => didUninstallEvent.fire({ identifier: { id: 'pub.a' } }))
.then(() => testObject.getDisabledExtensions())
.then(extensions => assert.deepEqual([], extensions));
});
test('test isEnabled return false extension is disabled globally', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)
.then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a'))));
});
test('test isEnabled return false extension is disabled in workspace', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a'))));
});
test('test isEnabled return true extension is not disabled', () => {
return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)
.then(() => testObject.setEnablement([aLocalExtension('pub.c')], EnablementState.Disabled))
.then(() => assert.ok(testObject.isEnabled(aLocalExtension('pub.b'))));
});
test('test canChangeEnablement return false for language packs', () => {
assert.equal(testObject.canChangeEnablement(aLocalExtension('pub.a', { localizations: [{ languageId: 'gr', translations: [{ id: 'vscode', path: 'path' }] }] })), false);
});
test('test canChangeEnablement return false when extensions are disabled in environment', () => {
instantiationService.stub(IEnvironmentService, { disableExtensions: true } as IEnvironmentService);
testObject = new TestExtensionEnablementService(instantiationService);
assert.equal(testObject.canChangeEnablement(aLocalExtension('pub.a')), false);
});
test('test canChangeEnablement return false when the extension is disabled in environment', () => {
instantiationService.stub(IEnvironmentService, { disableExtensions: ['pub.a'] } as IEnvironmentService);
testObject = new TestExtensionEnablementService(instantiationService);
assert.equal(testObject.canChangeEnablement(aLocalExtension('pub.a')), false);
});
test('test canChangeEnablement return true for system extensions when extensions are disabled in environment', () => {
instantiationService.stub(IEnvironmentService, { disableExtensions: true } as IEnvironmentService);
testObject = new TestExtensionEnablementService(instantiationService);
const extension = aLocalExtension('pub.a', undefined, ExtensionType.System);
assert.equal(testObject.canChangeEnablement(extension), true);
});
test('test canChangeEnablement return false for system extensions when extension is disabled in environment', () => {
instantiationService.stub(IEnvironmentService, { disableExtensions: ['pub.a'] } as IEnvironmentService);
testObject = new TestExtensionEnablementService(instantiationService);
const extension = aLocalExtension('pub.a', undefined, ExtensionType.System);
assert.equal(testObject.canChangeEnablement(extension), true);
});
test('test getDisabledExtensions include extensions disabled in enviroment', () => {
instantiationService.stub(IEnvironmentService, { disableExtensions: ['pub.a'] } as IEnvironmentService);
instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([aLocalExtension('pub.a'), aLocalExtension('pub.b')]) } as IExtensionManagementService);
testObject = new TestExtensionEnablementService(instantiationService);
return testObject.getDisabledExtensions()
.then(actual => {
assert.equal(actual.length, 1);
assert.equal(actual[0].id, 'pub.a');
});
});
});
function aLocalExtension(id: string, contributes?: IExtensionContributions, type?: ExtensionType): ILocalExtension {
const [publisher, name] = id.split('.');
type = isUndefinedOrNull(type) ? ExtensionType.User : type;
return <ILocalExtension>Object.create({
identifier: { id },
galleryIdentifier: { id, uuid: undefined },
manifest: {
name,
publisher,
contributes
},
type
});
}

View File

@@ -15,10 +15,11 @@ import { whenDeleted } from 'vs/base/node/pfs';
import { IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { URI, UriComponents } from 'vs/base/common/uri';
import { BrowserWindow } from 'electron';
import { BrowserWindow, ipcMain, Event as IpcEvent } from 'electron';
import { Event } from 'vs/base/common/event';
import { hasArgs } from 'vs/platform/environment/node/argv';
import { coalesce } from 'vs/base/common/arrays';
import { IDiagnosticInfoOptions, IDiagnosticInfo, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService';
export const ID = 'launchService';
export const ILaunchService = createDecorator<ILaunchService>(ID);
@@ -32,6 +33,7 @@ export interface IWindowInfo {
pid: number;
title: string;
folderURIs: UriComponents[];
remoteAuthority?: string;
}
export interface IMainProcessInfo {
@@ -41,6 +43,11 @@ export interface IMainProcessInfo {
windows: IWindowInfo[];
}
export interface IRemoteDiagnosticOptions {
includeProcesses?: boolean;
includeWorkspaceMetadata?: boolean;
}
function parseOpenUrl(args: ParsedArgs): URI[] {
if (args['open-url'] && args._urls && args._urls.length > 0) {
// --open-url must contain -- followed by the url(s)
@@ -64,6 +71,7 @@ export interface ILaunchService {
getMainProcessId(): Promise<number>;
getMainProcessInfo(): Promise<IMainProcessInfo>;
getLogsPath(): Promise<string>;
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]>;
}
export class LaunchChannel implements IServerChannel {
@@ -88,6 +96,9 @@ export class LaunchChannel implements IServerChannel {
case 'get-logs-path':
return this.service.getLogsPath();
case 'get-remote-diagnostics':
return this.service.getRemoteDiagnostics(arg);
}
throw new Error(`Call not found: ${command}`);
@@ -115,6 +126,10 @@ export class LaunchChannelClient implements ILaunchService {
getLogsPath(): Promise<string> {
return this.channel.call('get-logs-path', null);
}
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
return this.channel.call('get-remote-diagnostics', options);
}
}
export class LaunchService implements ILaunchService {
@@ -284,7 +299,45 @@ export class LaunchService implements ILaunchService {
return Promise.resolve(this.environmentService.logsPath);
}
private codeWindowToInfo(window: ICodeWindow): IWindowInfo {
getRemoteDiagnostics(options: IRemoteDiagnosticOptions): Promise<IRemoteDiagnosticInfo[]> {
const windows = this.windowsMainService.getWindows();
const promises: Promise<IDiagnosticInfo | undefined>[] = windows.map(window => {
return new Promise((resolve, reject) => {
if (window.remoteAuthority) {
const replyChannel = `vscode:getDiagnosticInfoResponse${window.id}`;
const args: IDiagnosticInfoOptions = {
includeProcesses: options.includeProcesses,
folders: options.includeWorkspaceMetadata ? this.getFolderURIs(window) : undefined
};
window.sendWhenReady('vscode:getDiagnosticInfo', { replyChannel, args });
ipcMain.once(replyChannel, (_: IpcEvent, data: IRemoteDiagnosticInfo) => {
// No data is returned if getting the connection fails.
if (!data) {
resolve();
}
if (typeof (data) === 'string') {
reject(new Error(data));
}
resolve(data);
});
setTimeout(() => {
resolve();
}, 5000);
} else {
resolve();
}
});
});
return Promise.all(promises).then(diagnostics => diagnostics.filter((x): x is IRemoteDiagnosticInfo => !!x));
}
private getFolderURIs(window: ICodeWindow): URI[] {
const folderURIs: URI[] = [];
if (window.openedFolderUri) {
@@ -303,14 +356,20 @@ export class LaunchService implements ILaunchService {
}
}
return this.browserWindowToInfo(window.win, folderURIs);
return folderURIs;
}
private browserWindowToInfo(win: BrowserWindow, folderURIs: URI[] = []): IWindowInfo {
private codeWindowToInfo(window: ICodeWindow): IWindowInfo {
const folderURIs = this.getFolderURIs(window);
return this.browserWindowToInfo(window.win, folderURIs, window.remoteAuthority);
}
private browserWindowToInfo(win: BrowserWindow, folderURIs: URI[] = [], remoteAuthority?: string): IWindowInfo {
return {
pid: win.webContents.getOSProcessId(),
title: win.getTitle(),
folderURIs
folderURIs,
remoteAuthority
};
}
}

View File

@@ -63,7 +63,6 @@ export interface IRemoteExtensionHostStartParams {
debugId?: string;
break?: boolean;
port?: number | null;
updatePort?: boolean;
}
interface IExtensionHostConnectionResult {

View File

@@ -11,8 +11,6 @@ export interface ResolvedAuthority {
readonly authority: string;
readonly host: string;
readonly port: number;
readonly debugListenPort?: number;
readonly debugConnectPort?: number;
}
export interface IRemoteAuthorityResolverService {

View File

@@ -97,7 +97,7 @@ export interface IWindowsMainService {
enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined>;
closeWorkspace(win: ICodeWindow): void;
open(openConfig: IOpenConfiguration): ICodeWindow[];
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string, openConfig: IOpenConfiguration): void;
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string | string[], openConfig: IOpenConfiguration): void;
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;