From 1f298d54a2ba9cd9de9cac3e604eec2b5bca5b55 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 1 Nov 2016 17:57:14 +0100 Subject: [PATCH] Fix #14763 - Include extension specific properties only - Refactor: Move extensions scanning to MainThreadExtensionService --- .../commands/test/commandService.test.ts | 5 +- .../common/abstractExtensionService.ts | 2 +- .../platform/extensions/common/extensions.ts | 12 +-- .../api/node/mainThreadExtensionService.ts | 52 ++++++++++- .../electron-browser/extensionHost.ts | 2 +- src/vs/workbench/electron-browser/shell.ts | 4 +- src/vs/workbench/node/extensionPoints.ts | 9 +- .../debug/electron-browser/debugService.ts | 2 +- .../electron-browser/extensionsActions.ts | 6 +- .../electron-browser/extensionsList.ts | 6 +- .../electron-browser/extensionsViewlet.ts | 8 +- .../extensionRuntimeService.ts | 87 +------------------ 12 files changed, 86 insertions(+), 109 deletions(-) rename src/vs/workbench/{services/extensions => }/electron-browser/extensionHost.ts (99%) rename src/vs/workbench/services/extensions/{electron-browser => common}/extensionRuntimeService.ts (55%) diff --git a/src/vs/platform/commands/test/commandService.test.ts b/src/vs/platform/commands/test/commandService.test.ts index 3ef879a5d8f..7496b53b4a2 100644 --- a/src/vs/platform/commands/test/commandService.test.ts +++ b/src/vs/platform/commands/test/commandService.test.ts @@ -9,7 +9,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/platform/commands/common/commandService'; -import { IExtensionService, ExtensionPointContribution } from 'vs/platform/extensions/common/extensions'; +import { IExtensionService, ExtensionPointContribution, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry'; @@ -27,6 +27,9 @@ class SimpleExtensionService implements IExtensionService { getExtensionsStatus() { return undefined; } + getExtensions() : TPromise { + return TPromise.wrap([]); + } } suite('CommandService', function () { diff --git a/src/vs/platform/extensions/common/abstractExtensionService.ts b/src/vs/platform/extensions/common/abstractExtensionService.ts index b6b9f4fca70..f0214d5ef1f 100644 --- a/src/vs/platform/extensions/common/abstractExtensionService.ts +++ b/src/vs/platform/extensions/common/abstractExtensionService.ts @@ -78,7 +78,7 @@ export abstract class AbstractExtensionService imp }); } - public readExtensions(): TPromise { + public getExtensions(): TPromise { return this.onReady().then(() => { return this._registry.getAllExtensionDescriptions(); }); diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index c8cab740e5d..71e00c84e5e 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -9,6 +9,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry'; +export const ExtensionProperties = ['id', 'name', 'version', 'publisher', 'isBuiltin', 'extensionFolderPath', 'extensionDependencies', 'activationEvents', 'engines', 'main', 'contributes', 'enableProposedApi']; + export interface IExtensionDescription { readonly id: string; readonly name: string; @@ -61,6 +63,11 @@ export interface IExtensionService { */ onReady(): TPromise; + /** + * Return all registered extensions + */ + getExtensions(): TPromise; + /** * Read all contributions to an extension point. */ @@ -77,11 +84,6 @@ export const IExtensionRuntimeService = createDecorator; - /** * Returns all globally disabled extension identifiers. * Returns an empty array if none exist. diff --git a/src/vs/workbench/api/node/mainThreadExtensionService.ts b/src/vs/workbench/api/node/mainThreadExtensionService.ts index 10592a85731..2521594f6fe 100644 --- a/src/vs/workbench/api/node/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/node/mainThreadExtensionService.ts @@ -6,14 +6,21 @@ import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; +import pkg from 'vs/platform/package'; +import { localize } from 'vs/nls'; +import * as path from 'path'; +import URI from 'vs/base/common/uri'; import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService'; import { IExtensionRuntimeService, IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints'; import { IMessageService } from 'vs/platform/message/common/message'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ExtHostContext, ExtHostExtensionServiceShape } from './extHost.protocol'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions')); + /** * Represents a failed extension in the ext host. */ @@ -64,7 +71,10 @@ export class MainProcessExtensionService extends AbstractExtensionService this._onExtensionDescriptions(extensionDescriptions)); + const disabledExtensions = [...extensionsRuntimeService.getGloballyDisabledExtensions(), ...extensionsRuntimeService.getWorkspaceDisabledExtensions()]; + this.scanExtensions().done(extensionDescriptions => { + this._onExtensionDescriptions(disabledExtensions.length ? extensionDescriptions.filter(e => disabledExtensions.indexOf(`${e.publisher}.${e.name}`) === -1) : extensionDescriptions); + }); } private _handleMessage(msg: IMessage) { @@ -166,4 +176,44 @@ export class MainProcessExtensionService extends AbstractExtensionService { + const collector = new MessagesCollector(); + const version = pkg.version; + const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, SystemExtensionsRoot, true); + const userExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, this.environmentService.extensionsPath, false); + const developedExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionDevelopmentPath ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, this.environmentService.extensionDevelopmentPath, false); + + return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => { + let builtinExtensions = extensionDescriptions[0]; + let userExtensions = extensionDescriptions[1]; + let developedExtensions = extensionDescriptions[2]; + + let result: { [extensionId: string]: IExtensionDescription; } = {}; + builtinExtensions.forEach((builtinExtension) => { + result[builtinExtension.id] = builtinExtension; + }); + userExtensions.forEach((userExtension) => { + if (result.hasOwnProperty(userExtension.id)) { + collector.warn(userExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); + } + result[userExtension.id] = userExtension; + }); + developedExtensions.forEach(developedExtension => { + collector.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); + if (result.hasOwnProperty(developedExtension.id)) { + collector.warn(developedExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); + } + result[developedExtension.id] = developedExtension; + }); + + return Object.keys(result).map(name => result[name]); + }).then(null, err => { + collector.error('', err); + return []; + }).then(extensions => { + collector.getMessages().forEach(entry => this.$localShowMessage(entry.type, this._isDev ? (entry.source ? '[' + entry.source + ']: ' : '') + entry.message : entry.message)); + return extensions; + }); + } } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/electron-browser/extensionHost.ts similarity index 99% rename from src/vs/workbench/services/extensions/electron-browser/extensionHost.ts rename to src/vs/workbench/electron-browser/extensionHost.ts index 650ccd8cb60..0fab91fa5c4 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/electron-browser/extensionHost.ts @@ -209,7 +209,7 @@ export class ExtensionHostProcessWorker { TPromise.join([ this.telemetryService.getTelemetryInfo(), - this.extensionService.readExtensions() + this.extensionService.getExtensions() ]).then(([telemetryInfo, extensionDescriptions]) => { let initData: IInitData = { parentPid: process.pid, diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index a5b8ed2c12e..ea79d3c3d65 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -81,8 +81,8 @@ import { URLChannelClient } from 'vs/platform/url/common/urlIpc'; import { IURLService } from 'vs/platform/url/common/url'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { WorkspaceConfigurationService } from 'vs/workbench/services/configuration/node/configurationService'; -import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; -import { ExtensionRuntimeService } from 'vs/workbench/services/extensions/electron-browser/extensionRuntimeService'; +import { ExtensionHostProcessWorker } from 'vs/workbench/electron-browser/extensionHost'; +import { ExtensionRuntimeService } from 'vs/workbench/services/extensions/common/extensionRuntimeService'; // self registering services import 'vs/platform/opener/browser/opener.contribution'; diff --git a/src/vs/workbench/node/extensionPoints.ts b/src/vs/workbench/node/extensionPoints.ts index 6b47f5be174..f318fd69315 100644 --- a/src/vs/workbench/node/extensionPoints.ts +++ b/src/vs/workbench/node/extensionPoints.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import * as Platform from 'vs/base/common/platform'; import pfs = require('vs/base/node/pfs'); -import { IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, IMessage, ExtensionProperties } from 'vs/platform/extensions/common/extensions'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; import { groupBy, values } from 'vs/base/common/collections'; @@ -81,16 +81,21 @@ abstract class ExtensionManifestHandler { } class ExtensionManifestParser extends ExtensionManifestHandler { + public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { let errors: json.ParseError[] = []; - let extensionDescription: IExtensionDescription = json.parse(manifestContents.toString(), errors); + const parsed = json.parse(manifestContents.toString(), errors); if (errors.length > 0) { errors.forEach((error) => { this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, json.getParseErrorMessage(error.error))); }); return null; } + const extensionDescription = ExtensionProperties.reduce((previousValue, currentValue) => { + previousValue[currentValue] = parsed[currentValue]; + return previousValue; + }, {}); return extensionDescription; }, (err) => { this._collector.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", this._absoluteManifestPath, err.message)); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index b9380518dcb..5d2b63d3b1a 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -53,7 +53,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWindowService, IBroadcast } from 'vs/workbench/services/window/electron-browser/windowService'; -import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; +import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/workbench/electron-browser/extensionHost'; import { ipcRenderer as ipc } from 'electron'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index bdb8649c3a3..8ef86d5cb5b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -30,7 +30,7 @@ import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extens import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import URI from 'vs/base/common/uri'; -import { IExtensionRuntimeService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IExtensionService, IExtensionRuntimeService, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { IWindowService } from 'vs/workbench/services/window/electron-browser/windowService'; const dialog = remote.dialog; @@ -689,7 +689,7 @@ export class ReloadAction extends Action { @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, @IMessageService private messageService: IMessageService, @IInstantiationService private instantiationService: IInstantiationService, - @IExtensionRuntimeService private extensionRuntimeService: IExtensionRuntimeService + @IExtensionService private extensionService: IExtensionService ) { super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false); this.throttler = new Throttler(); @@ -710,7 +710,7 @@ export class ReloadAction extends Action { if (state === ExtensionState.Installing || state === ExtensionState.Uninstalling) { return TPromise.wrap(null); } - return this.extensionRuntimeService.getEnabledExtensions() + return this.extensionService.getExtensions() .then(runningExtensions => this.computeReloadState(runningExtensions)); }).done(() => { this.class = this.enabled ? ReloadAction.EnabledClass : ReloadAction.DisabledClass; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts index 77d7c85fc6c..d4bd7444441 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsList.ts @@ -20,7 +20,7 @@ import { InstallAction, UpdateAction, BuiltinStatusLabelAction, ReloadAction, Ma import { Label, RatingsWidget, InstallWidget } from './extensionsWidgets'; import { EventType } from 'vs/base/common/events'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IExtensionRuntimeService } from 'vs/platform/extensions/common/extensions'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; export interface ITemplateData { element: HTMLElement; @@ -49,7 +49,7 @@ export class Renderer implements IPagedRenderer { @IContextMenuService private contextMenuService: IContextMenuService, @IMessageService private messageService: IMessageService, @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionRuntimeService private extensionRuntimeService: IExtensionRuntimeService + @IExtensionService private extensionService: IExtensionService ) { } get templateId() { return 'extension'; } @@ -125,7 +125,7 @@ export class Renderer implements IPagedRenderer { data.extensionDisposables = dispose(data.extensionDisposables); - this.extensionRuntimeService.getEnabledExtensions().then(enabledExtensions => { + this.extensionService.getExtensions().then(enabledExtensions => { const isExtensionRunning = enabledExtensions.some(e => e.id === extension.identifier); const isInstalled = this.extensionsWorkbenchService.local.some(e => e.identifier === extension.identifier); toggleClass(data.element, 'disabled', isInstalled && !isExtensionRunning); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 172722a8d7e..05052c5a8bf 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -44,7 +44,7 @@ import { IEditorGroupService } from 'vs/workbench/services/group/common/groupSer import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityService'; -import { IExtensionRuntimeService } from 'vs/platform/extensions/common/extensions'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; interface SearchInputEvent extends Event { target: HTMLInputElement; @@ -67,7 +67,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { constructor( @ITelemetryService telemetryService: ITelemetryService, @IExtensionGalleryService private galleryService: IExtensionGalleryService, - @IExtensionManagementService private extensionService: IExtensionManagementService, + @IExtensionManagementService private extensionManagementService: IExtensionManagementService, @IProgressService private progressService: IProgressService, @IInstantiationService private instantiationService: IInstantiationService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -76,7 +76,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { @IExtensionTipsService private tipsService: IExtensionTipsService, @IMessageService private messageService: IMessageService, @IViewletService private viewletService: IViewletService, - @IExtensionRuntimeService private extensionRuntimeService: IExtensionRuntimeService + @IExtensionService private extensionService: IExtensionService ) { super(VIEWLET_ID, telemetryService); this.searchDelayer = new ThrottledDelayer(500); @@ -242,7 +242,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { if (/@disabled/i.test(value)) { return this.extensionsWorkbenchService.queryLocal() .then(result => result.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName))) - .then(result => this.extensionRuntimeService.getEnabledExtensions() + .then(result => this.extensionService.getExtensions() .then(runningExtensions => result.filter(e => runningExtensions.every(r => r.id !== e.identifier)))) .then(result => new PagedModel(result)); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionRuntimeService.ts b/src/vs/workbench/services/extensions/common/extensionRuntimeService.ts similarity index 55% rename from src/vs/workbench/services/extensions/electron-browser/extensionRuntimeService.ts rename to src/vs/workbench/services/extensions/common/extensionRuntimeService.ts index 98abd835dc1..3712951dfdb 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionRuntimeService.ts +++ b/src/vs/workbench/services/extensions/common/extensionRuntimeService.ts @@ -3,25 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import pkg from 'vs/platform/package'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; import { distinct } from 'vs/base/common/arrays'; -import * as paths from 'vs/base/common/paths'; -import URI from 'vs/base/common/uri'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints'; import { IExtensionManagementService, DidUninstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace'; -import { IExtensionRuntimeService, IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions'; +import { IExtensionRuntimeService } from 'vs/platform/extensions/common/extensions'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { Severity, IMessageService } from 'vs/platform/message/common/message'; +import { IMessageService } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; - -const DIRNAME = URI.parse(require.toUrl('./')).fsPath; -const BASE_PATH = paths.normalize(paths.join(DIRNAME, '../../../../../..')); -const BUILTIN_EXTENSIONS_PATH = paths.join(BASE_PATH, 'extensions'); const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensions/disabled'; export class ExtensionRuntimeService implements IExtensionRuntimeService { @@ -29,7 +21,6 @@ export class ExtensionRuntimeService implements IExtensionRuntimeService { _serviceBrand: any; private workspace: IWorkspace; - private enabledExtensions: TPromise; private disposables: IDisposable[] = []; constructor( @@ -40,19 +31,9 @@ export class ExtensionRuntimeService implements IExtensionRuntimeService { @IExtensionManagementService private extensionManagementService: IExtensionManagementService ) { this.workspace = contextService.getWorkspace(); - - const disabledExtensions = this.getDisabledExtensions(); - this.enabledExtensions = this.scanExtensions().then(extensionDescriptions => { - return disabledExtensions.length ? extensionDescriptions.filter(e => disabledExtensions.indexOf(`${e.publisher}.${e.name}`) === -1) : extensionDescriptions; - }); - extensionManagementService.onDidUninstallExtension(this.onDidUninstallExtension, this, this.disposables); } - public getEnabledExtensions(): TPromise { - return this.enabledExtensions; - } - public getGloballyDisabledExtensions(): string[] { return this.getDisabledExtensionsFromStorage(StorageScope.GLOBAL); } @@ -153,70 +134,6 @@ export class ExtensionRuntimeService implements IExtensionRuntimeService { } } - private scanExtensions(): TPromise { - const collector = new MessagesCollector(); - const version = pkg.version; - const builtinExtensions = ExtensionScanner.scanExtensions(version, collector, BUILTIN_EXTENSIONS_PATH, true); - const userExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionsPath ? TPromise.as([]) : ExtensionScanner.scanExtensions(version, collector, this.environmentService.extensionsPath, false); - const developedExtensions = this.environmentService.disableExtensions || !this.environmentService.extensionDevelopmentPath ? TPromise.as([]) : ExtensionScanner.scanOneOrMultipleExtensions(version, collector, this.environmentService.extensionDevelopmentPath, false); - const isDev = !this.environmentService.isBuilt || !!this.environmentService.extensionDevelopmentPath; - - return TPromise.join([builtinExtensions, userExtensions, developedExtensions]).then((extensionDescriptions: IExtensionDescription[][]) => { - let builtinExtensions = extensionDescriptions[0]; - let userExtensions = extensionDescriptions[1]; - let developedExtensions = extensionDescriptions[2]; - - let result: { [extensionId: string]: IExtensionDescription; } = {}; - builtinExtensions.forEach((builtinExtension) => { - result[builtinExtension.id] = builtinExtension; - }); - userExtensions.forEach((userExtension) => { - if (result.hasOwnProperty(userExtension.id)) { - collector.warn(userExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[userExtension.id].extensionFolderPath, userExtension.extensionFolderPath)); - } - result[userExtension.id] = userExtension; - }); - developedExtensions.forEach(developedExtension => { - collector.info('', localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionFolderPath)); - if (result.hasOwnProperty(developedExtension.id)) { - collector.warn(developedExtension.extensionFolderPath, localize('overwritingExtension', "Overwriting extension {0} with {1}.", result[developedExtension.id].extensionFolderPath, developedExtension.extensionFolderPath)); - } - result[developedExtension.id] = developedExtension; - }); - - return Object.keys(result).map(name => result[name]); - }).then(null, err => { - collector.error('', err); - return []; - }).then(extensions => { - collector.getMessages().forEach(entry => this._handleMessage(entry, isDev)); - return extensions; - }); - } - - private _handleMessage(message: IMessage, isDev: boolean): void { - let messageShown = false; - if (message.type === Severity.Error || message.type === Severity.Warning) { - if (isDev) { - // Only show nasty intrusive messages if doing extension development. - this.messageService.show(message.type, (message.source ? '[' + message.source + ']: ' : '') + message.message); - messageShown = true; - } - } - if (!messageShown) { - switch (message.type) { - case Severity.Error: - console.error(message); - break; - case Severity.Warning: - console.warn(message); - break; - default: - console.log(message); - } - } - } - dispose(): void { this.disposables = dispose(this.disposables); }