diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index 65348d5095cb5..9d5bc92457049 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -5,16 +5,16 @@ import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { distinct } from 'vs/base/common/arrays'; +import { distinct, coalesce } from 'vs/base/common/arrays'; import Event, { Emitter } from 'vs/base/common/event'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { adoptToGalleryExtensionId, getIdAndVersionFromLocalExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensions/disabled'; +const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled'; export class ExtensionEnablementService implements IExtensionEnablementService { @@ -22,8 +22,8 @@ export class ExtensionEnablementService implements IExtensionEnablementService { private disposables: IDisposable[] = []; - private _onEnablementChanged = new Emitter(); - public onEnablementChanged: Event = this._onEnablementChanged.event; + private _onEnablementChanged = new Emitter(); + public onEnablementChanged: Event = this._onEnablementChanged.event; constructor( @IStorageService private storageService: IStorageService, @@ -38,28 +38,28 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY; } - public getGloballyDisabledExtensions(): string[] { + getGloballyDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.GLOBAL); } - public getWorkspaceDisabledExtensions(): string[] { + getWorkspaceDisabledExtensions(): IExtensionIdentifier[] { return this.getDisabledExtensions(StorageScope.WORKSPACE); } - public canEnable(identifier: string): boolean { + canEnable(identifier: IExtensionIdentifier): boolean { if (this.environmentService.disableExtensions) { return false; } - if (this.getGloballyDisabledExtensions().indexOf(identifier) !== -1) { + if (this.getGloballyDisabledExtensions().some(d => areSameExtensions(d, identifier))) { return true; } - if (this.getWorkspaceDisabledExtensions().indexOf(identifier) !== -1) { + if (this.getWorkspaceDisabledExtensions().some(d => areSameExtensions(d, identifier))) { return true; } return false; } - public setEnablement(identifier: string, enable: boolean, workspace: boolean = false): TPromise { + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace: boolean = false): TPromise { if (workspace && !this.hasWorkspace) { return TPromise.wrapError(new Error(localize('noWorkspace', "No workspace."))); } @@ -83,10 +83,16 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private disableExtension(identifier: string, scope: StorageScope): TPromise { + migrateToIdentifiers(installed: IExtensionIdentifier[]): void { + this.migrateDisabledExtensions(installed, StorageScope.GLOBAL); + if (this.hasWorkspace) { + this.migrateDisabledExtensions(installed, StorageScope.WORKSPACE); + } + } + + private disableExtension(identifier: IExtensionIdentifier, scope: StorageScope): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index === -1) { + if (disabledExtensions.every(e => !areSameExtensions(e, identifier))) { disabledExtensions.push(identifier); this.setDisabledExtensions(disabledExtensions, scope, identifier); return TPromise.wrap(true); @@ -94,28 +100,30 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return TPromise.wrap(false); } - private enableExtension(identifier: string, scope: StorageScope, fireEvent = true): TPromise { + private enableExtension(identifier: IExtensionIdentifier, scope: StorageScope, fireEvent = true): TPromise { let disabledExtensions = this.getDisabledExtensions(scope); - const index = disabledExtensions.indexOf(identifier); - if (index !== -1) { - disabledExtensions.splice(index, 1); - this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); - return TPromise.wrap(true); + for (let index = 0; index < disabledExtensions.length; index++) { + const disabledExtension = disabledExtensions[index]; + if (areSameExtensions(disabledExtension, identifier)) { + disabledExtensions.splice(index, 1); + this.setDisabledExtensions(disabledExtensions, scope, identifier, fireEvent); + return TPromise.wrap(true); + } } return TPromise.wrap(false); } - private getDisabledExtensions(scope: StorageScope): string[] { + private getDisabledExtensions(scope: StorageScope): IExtensionIdentifier[] { if (scope === StorageScope.WORKSPACE && !this.hasWorkspace) { return []; } const value = this.storageService.get(DISABLED_EXTENSIONS_STORAGE_PATH, scope, ''); - return value ? distinct(value.split(',')).map(id => adoptToGalleryExtensionId(id)) : []; + return value ? JSON.parse(value) : []; } - private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string, fireEvent = true): void { + private setDisabledExtensions(disabledExtensions: IExtensionIdentifier[], scope: StorageScope, extension: IExtensionIdentifier, fireEvent = true): void { if (disabledExtensions.length) { - this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions.join(','), scope); + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(disabledExtensions.map(({ id, uuid }) => ({ id, uuid }))), scope); } else { this.storageService.remove(DISABLED_EXTENSIONS_STORAGE_PATH, scope); } @@ -124,12 +132,28 @@ export class ExtensionEnablementService implements IExtensionEnablementService { } } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private migrateDisabledExtensions(installedExtensions: IExtensionIdentifier[], scope: StorageScope): void { + const oldValue = this.storageService.get('extensions/disabled', scope, ''); + if (oldValue) { + const extensionIdentifiers = coalesce(distinct(oldValue.split(',')).map(id => { + id = adoptToGalleryExtensionId(id); + const matched = installedExtensions.filter(installed => areSameExtensions({ id }, { id: installed.id }))[0]; + return matched ? { id: matched.id, uuid: matched.uuid } : null; + })); + if (extensionIdentifiers.length) { + this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, JSON.stringify(extensionIdentifiers), scope); + } + } + this.storageService.remove('extensions/disabled', scope); + } + + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { if (!error) { - id = getIdAndVersionFromLocalExtensionId(id).id; + const id = getIdAndVersionFromLocalExtensionId(identifier.id).id; if (id) { - this.enableExtension(id, StorageScope.WORKSPACE, false); - this.enableExtension(id, StorageScope.GLOBAL, false); + const extension = { id, uuid: identifier.uuid }; + this.enableExtension(extension, StorageScope.WORKSPACE, false); + this.enableExtension(extension, StorageScope.GLOBAL, false); } } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index aa16e8e0f05c6..669d4bab78ea8 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -135,10 +135,14 @@ export interface IGalleryExtensionAssets { license: IGalleryExtensionAsset; } -export interface IGalleryExtension { - uuid: string; +export interface IExtensionIdentifier { id: string; + uuid?: string; +} + +export interface IGalleryExtension { name: string; + identifier: IExtensionIdentifier; version: string; date: string; displayName: string; @@ -167,7 +171,7 @@ export enum LocalExtensionType { export interface ILocalExtension { type: LocalExtensionType; - id: string; + identifier: IExtensionIdentifier; manifest: IExtensionManifest; metadata: IGalleryMetadata; path: string; @@ -217,19 +221,19 @@ export interface IExtensionGalleryService { reportStatistic(publisher: string, name: string, version: string, type: StatisticType): TPromise; getReadme(extension: IGalleryExtension): TPromise; getManifest(extension: IGalleryExtension): TPromise; - getChangelog(extension: IGalleryMetadata): TPromise; + getChangelog(extension: IGalleryExtension): TPromise; loadCompatibleVersion(extension: IGalleryExtension): TPromise; getAllDependencies(extension: IGalleryExtension): TPromise; } export interface InstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; } export interface DidInstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; zipPath?: string; gallery?: IGalleryExtension; local?: ILocalExtension; @@ -237,7 +241,7 @@ export interface DidInstallExtensionEvent { } export interface DidUninstallExtensionEvent { - id: string; + identifier: IExtensionIdentifier; error?: string; } @@ -246,7 +250,7 @@ export interface IExtensionManagementService { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; install(zipPath: string): TPromise; @@ -264,24 +268,24 @@ export interface IExtensionEnablementService { /** * Event to listen on for extension enablement changes */ - onEnablementChanged: Event; + onEnablementChanged: Event; /** * Returns all globally disabled extension identifiers. * Returns an empty array if none exist. */ - getGloballyDisabledExtensions(): string[]; + getGloballyDisabledExtensions(): IExtensionIdentifier[]; /** * Returns all workspace disabled extension identifiers. * Returns an empty array if none exist or workspace does not exist. */ - getWorkspaceDisabledExtensions(): string[]; + getWorkspaceDisabledExtensions(): IExtensionIdentifier[]; /** * Returns `true` if given extension can be enabled by calling `setEnablement`, otherwise false`. */ - canEnable(identifier: string): boolean; + canEnable(identifier: IExtensionIdentifier): boolean; /** * Enable or disable the given extension. @@ -292,7 +296,9 @@ export interface IExtensionEnablementService { * * Throws error if enablement is requested for workspace and there is no workspace */ - setEnablement(identifier: string, enable: boolean, workspace?: boolean): TPromise; + setEnablement(identifier: IExtensionIdentifier, enable: boolean, workspace?: boolean): TPromise; + + migrateToIdentifiers(installed: IExtensionIdentifier[]): void; } export const IExtensionTipsService = createDecorator('extensionTipsService'); diff --git a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts index d0acbb8034041..5f5a8c39e747c 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementIpc.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent } from './extensionManagement'; +import { IExtensionManagementService, ILocalExtension, InstallExtensionEvent, DidInstallExtensionEvent, IGalleryExtension, LocalExtensionType, DidUninstallExtensionEvent, IExtensionIdentifier } from './extensionManagement'; import Event, { buffer } from 'vs/base/common/event'; export interface IExtensionManagementChannel extends IChannel { @@ -26,7 +26,7 @@ export class ExtensionManagementChannel implements IExtensionManagementChannel { onInstallExtension: Event; onDidInstallExtension: Event; - onUninstallExtension: Event; + onUninstallExtension: Event; onDidUninstallExtension: Event; constructor(private service: IExtensionManagementService) { @@ -63,8 +63,8 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer private _onDidInstallExtension = eventFromCall(this.channel, 'event:onDidInstallExtension'); get onDidInstallExtension(): Event { return this._onDidInstallExtension; } - private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); - get onUninstallExtension(): Event { return this._onUninstallExtension; } + private _onUninstallExtension = eventFromCall(this.channel, 'event:onUninstallExtension'); + get onUninstallExtension(): Event { return this._onUninstallExtension; } private _onDidUninstallExtension = eventFromCall(this.channel, 'event:onDidUninstallExtension'); get onDidUninstallExtension(): Event { return this._onDidUninstallExtension; } diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index f8684f13156c6..23945ed58fb35 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -5,10 +5,13 @@ 'use strict'; -import { ILocalExtension, IGalleryExtension, IExtensionManifest, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ILocalExtension, IGalleryExtension, EXTENSION_IDENTIFIER_REGEX, IExtensionEnablementService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -export function areSameExtensions(a: { id: string }, b: { id: string }): boolean { +export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean { + if (a.uuid && b.uuid) { + return a.uuid === b.uuid; + } if (a.id === b.id) { return true; } @@ -19,14 +22,6 @@ export function getGalleryExtensionId(publisher: string, name: string): string { return `${publisher}.${name.toLocaleLowerCase()}`; } -export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { - return getLocalExtensionId(extension.id, version); -} - -export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { - return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); -} - export function getGalleryExtensionIdFromLocal(local: ILocalExtension): string { return getGalleryExtensionId(local.manifest.publisher, local.manifest.name); } @@ -46,10 +41,6 @@ export function adoptToGalleryExtensionId(id: string): string { return id.replace(EXTENSION_IDENTIFIER_REGEX, (match, publisher: string, name: string) => getGalleryExtensionId(publisher, name)); } -function getLocalExtensionId(id: string, version: string): string { - return `${id}-${version}`; -} - export function getLocalExtensionTelemetryData(extension: ILocalExtension): any { return { id: getGalleryExtensionIdFromLocal(extension), @@ -79,9 +70,9 @@ export function getLocalExtensionTelemetryData(extension: ILocalExtension): any */ export function getGalleryExtensionTelemetryData(extension: IGalleryExtension): any { return { - id: extension.id, + id: extension.identifier.id, name: extension.name, - galleryId: extension.uuid, + galleryId: extension.identifier.uuid, publisherId: extension.publisherId, publisherName: extension.publisher, publisherDisplayName: extension.publisherDisplayName, @@ -102,9 +93,9 @@ export function getGloballyDisabledExtensions(extensionEnablementService: IExten const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); if (!storageService.getBoolean(BetterMergeCheckKey, StorageScope.GLOBAL, false)) { storageService.store(BetterMergeCheckKey, true); - if (globallyDisabled.indexOf(BetterMergeId) === -1 && installedExtensions.some(d => d.id === BetterMergeId)) { - globallyDisabled.push(BetterMergeId); - extensionEnablementService.setEnablement(BetterMergeId, false); + if (globallyDisabled.every(disabled => disabled.id !== BetterMergeId) && installedExtensions.some(d => d.id === BetterMergeId)) { + globallyDisabled.push({ id: BetterMergeId }); + extensionEnablementService.setEnablement({ id: BetterMergeId }, false); storageService.store(BetterMergeDisabledNowKey, true); } } diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 4453efbc64d0a..f6e62fd8592c3 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -245,8 +245,10 @@ function toExtension(galleryExtension: IRawGalleryExtension, extensionsGalleryUr }; return { - uuid: galleryExtension.extensionId, - id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + identifier: { + id: getGalleryExtensionId(galleryExtension.publisher.publisherName, galleryExtension.extensionName), + uuid: galleryExtension.extensionId + }, name: galleryExtension.extensionName, version: version.version, date: version.lastUpdated, @@ -488,7 +490,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code') .withFilter(FilterType.ExcludeWithFlags, flagsToString(Flags.Unpublished)) .withAssetTypes(AssetType.Manifest, AssetType.VSIX) - .withFilter(FilterType.ExtensionId, extension.uuid); + .withFilter(FilterType.ExtensionId, extension.identifier.uuid); return this.queryGallery(query).then(({ galleryExtensions }) => { const [rawExtension] = galleryExtensions; @@ -556,7 +558,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { dep.properties.dependencies.forEach(d => dependenciesSet.add(d)); } } - result = distinct(result.concat(loadedDependencies), d => d.uuid); + result = distinct(result.concat(loadedDependencies), d => d.identifier.uuid); const dependencies: string[] = []; dependenciesSet.forEach(d => !ExtensionGalleryService.hasExtensionByName(result, d) && dependencies.push(d)); return this.getDependenciesReccursively(dependencies, result, root); diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 58c2a51420584..ff9dd9a00167a 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -18,9 +18,10 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IExtensionManifest, IGalleryMetadata, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, LocalExtensionType, - StatisticType + StatisticType, + IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest, getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getIdAndVersionFromLocalExtensionId, adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localizeManifest } from '../common/extensionNls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter } from 'vs/base/common/async'; @@ -75,6 +76,7 @@ interface InstallableExtension { zipPath: string; id: string; metadata: IGalleryMetadata; + current?: ILocalExtension; } export class ExtensionManagementService implements IExtensionManagementService { @@ -92,8 +94,8 @@ export class ExtensionManagementService implements IExtensionManagementService { private _onDidInstallExtension = new Emitter(); onDidInstallExtension: Event = this._onDidInstallExtension.event; - private _onUninstallExtension = new Emitter(); - onUninstallExtension: Event = this._onUninstallExtension.event; + private _onUninstallExtension = new Emitter(); + onUninstallExtension: Event = this._onUninstallExtension.event; private _onDidUninstallExtension = new Emitter(); onDidUninstallExtension: Event = this._onDidUninstallExtension.event; @@ -112,19 +114,19 @@ export class ExtensionManagementService implements IExtensionManagementService { zipPath = path.resolve(zipPath); return validate(zipPath).then(manifest => { - const id = getLocalExtensionIdFromManifest(manifest); + const identifier = { id: getLocalExtensionIdFromManifest(manifest) }; - return this.isObsolete(id).then(isObsolete => { + return this.isObsolete(identifier.id).then(isObsolete => { if (isObsolete) { return TPromise.wrapError(new Error(nls.localize('restartCodeLocal', "Please restart Code before reinstalling {0}.", manifest.displayName || manifest.name))); } - this._onInstallExtension.fire({ id, zipPath }); + this._onInstallExtension.fire({ identifier, zipPath }); - return this.installExtension({ zipPath, id, metadata: null }) + return this.installExtension({ zipPath, id: identifier.id, metadata: null }) .then( - local => this._onDidInstallExtension.fire({ id, zipPath, local }), - error => { this._onDidInstallExtension.fire({ id, zipPath, error }); return TPromise.wrapError(error); } + local => this._onDidInstallExtension.fire({ identifier, zipPath, local }), + error => { this._onDidInstallExtension.fire({ identifier, zipPath, error }); return TPromise.wrapError(error); } ); }); }); @@ -155,11 +157,12 @@ export class ExtensionManagementService implements IExtensionManagementService { } private downloadAndInstallExtensions(extensions: IGalleryExtension[]): TPromise { - return TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall))) - .then( - installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) - .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_LOCAL, error))), - error => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_GALLERY, error)); + return this.getInstalled(LocalExtensionType.User) + .then(installed => TPromise.join(extensions.map(extensionToInstall => this.downloadInstallableExtension(extensionToInstall, installed))) + .then( + installableExtensions => TPromise.join(installableExtensions.map(installableExtension => this.installExtension(installableExtension))) + .then(null, error => this.rollback(extensions).then(() => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_LOCAL, error))), + error => this.onDidInstallExtensions(extensions, null, INSTALL_ERROR_GALLERY, error))); } private collectExtensionsToInstall(extension: IGalleryExtension): TPromise { @@ -174,37 +177,38 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(obsolete => obsolete.length ? TPromise.wrapError(new Error(nls.localize('restartCodeGallery', "Please restart Code before reinstalling."))) : extensionsToInstall); } - private downloadInstallableExtension(extension: IGalleryExtension): TPromise { + private downloadInstallableExtension(extension: IGalleryExtension, installed: ILocalExtension[]): TPromise { + const current = installed.filter(i => i.identifier.uuid === extension.identifier.uuid)[0]; const id = getLocalExtensionIdFromGallery(extension, extension.version); const metadata = { - id: extension.uuid, + id: extension.identifier.uuid, publisherId: extension.publisherId, publisherDisplayName: extension.publisherDisplayName, }; return this.galleryService.download(extension) - .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata }))); + .then(zipPath => validate(zipPath).then(() => ({ zipPath, id, metadata, current }))); } private rollback(extensions: IGalleryExtension[]): TPromise { return this.filterOutUninstalled(extensions) - .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.id)))) + .then(installed => TPromise.join(installed.map(local => this.uninstallExtension(local.identifier)))) .then(() => null, () => null); } private onInstallExtensions(extensions: IGalleryExtension[]): void { for (const extension of extensions) { const id = getLocalExtensionIdFromGallery(extension, extension.version); - this._onInstallExtension.fire({ id, gallery: extension }); + this._onInstallExtension.fire({ identifier: { id, uuid: extension.identifier.uuid }, gallery: extension }); } } private onDidInstallExtensions(extensions: IGalleryExtension[], local: ILocalExtension[], errorCode?: string, error?: any): TPromise { extensions.forEach((gallery, index) => { - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version), uuid: gallery.identifier.uuid }; if (errorCode) { - this._onDidInstallExtension.fire({ id, gallery, error: errorCode }); + this._onDidInstallExtension.fire({ identifier, gallery, error: errorCode }); } else { - this._onDidInstallExtension.fire({ id, gallery, local: local[index] }); + this._onDidInstallExtension.fire({ identifier, gallery, local: local[index] }); } }); return error ? TPromise.wrapError(Array.isArray(error) ? this.joinErrors(error) : error) : TPromise.as(null); @@ -214,11 +218,11 @@ export class ExtensionManagementService implements IExtensionManagementService { return this.getInstalled() .then(local => { return dependencies.filter(d => { - if (extension.uuid === d.uuid) { + if (extension.identifier.uuid === d.identifier.uuid) { return false; } const extensionId = getLocalExtensionIdFromGallery(d, d.version); - return local.every(local => local.id !== extensionId); + return local.every(({ identifier }) => identifier.id !== extensionId); }); }); } @@ -229,11 +233,11 @@ export class ExtensionManagementService implements IExtensionManagementService { } private getGalleryExtensionForLocalExtension(galleryExtensions: IGalleryExtension[], localExtension: ILocalExtension): IGalleryExtension { - const filtered = galleryExtensions.filter(galleryExtension => getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version) === localExtension.id); + const filtered = galleryExtensions.filter(galleryExtension => areSameExtensions(localExtension.identifier, { id: getLocalExtensionIdFromGallery(galleryExtension, galleryExtension.version), uuid: galleryExtension.identifier.uuid })); return filtered.length ? filtered[0] : null; } - private installExtension({ zipPath, id, metadata }: InstallableExtension): TPromise { + private installExtension({ zipPath, id, metadata, current }: InstallableExtension): TPromise { const extensionPath = path.join(this.extensionsPath, id); return pfs.rimraf(extensionPath).then(() => { @@ -246,14 +250,16 @@ export class ExtensionManagementService implements IExtensionManagementService { const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)).toString() : null; const type = LocalExtensionType.User; + const identifier = { id, uuid: metadata ? metadata.id : null }; - const local: ILocalExtension = { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; + const local: ILocalExtension = { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; const manifestPath = path.join(extensionPath, 'package.json'); return pfs.readFile(manifestPath, 'utf8') .then(raw => parseManifest(raw)) .then(({ manifest }) => assign(manifest, { __metadata: metadata })) .then(manifest => pfs.writeFile(manifestPath, JSON.stringify(manifest, null, '\t'))) + .then(() => this.checkForRename(current, local)) .then(() => local); }); }); @@ -273,6 +279,15 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => { /* drop resolved value */ }); } + private checkForRename(currentExtension: ILocalExtension, newExtension: ILocalExtension): TPromise { + // Check if the gallery id for current and new exensions are same, if not, remove the current one. + if (currentExtension && getGalleryExtensionIdFromLocal(currentExtension) !== getGalleryExtensionIdFromLocal(newExtension)) { + // return this.uninstallExtension(currentExtension.identifier); + return this.setObsolete(currentExtension.identifier.id); + } + return TPromise.as(null); + } + private joinErrors(errors: (Error | string)[]): Error { if (errors.length === 1) { return errors[0] instanceof Error ? errors[0] : new Error(errors[0]); @@ -350,7 +365,7 @@ export class ExtensionManagementService implements IExtensionManagementService { if (dependents.length) { return TPromise.wrapError(new Error(this.getDependentsErrorMessage(extension, dependents))); } - return TPromise.join([this.uninstallExtension(extension.id), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); + return TPromise.join([this.uninstallExtension(extension.identifier), ...dependenciesToUninstall.map(d => this.doUninstall(d))]).then(() => null); } private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string { @@ -401,7 +416,7 @@ export class ExtensionManagementService implements IExtensionManagementService { private doUninstall(extension: ILocalExtension): TPromise { return this.preUninstallExtension(extension) - .then(() => this.uninstallExtension(extension.id)) + .then(() => this.uninstallExtension(extension.identifier)) .then(() => this.postUninstallExtension(extension), error => { this.postUninstallExtension(extension, INSTALL_ERROR_LOCAL); @@ -410,13 +425,13 @@ export class ExtensionManagementService implements IExtensionManagementService { } private preUninstallExtension(extension: ILocalExtension): TPromise { - const extensionPath = path.join(this.extensionsPath, extension.id); + const extensionPath = path.join(this.extensionsPath, extension.identifier.id); return pfs.exists(extensionPath) .then(exists => exists ? null : TPromise.wrapError(new Error(nls.localize('notExists', "Could not find extension")))) - .then(() => this._onUninstallExtension.fire(extension.id)); + .then(() => this._onUninstallExtension.fire(extension.identifier)); } - private uninstallExtension(id: string): TPromise { + private uninstallExtension({ id }: IExtensionIdentifier): TPromise { const extensionPath = path.join(this.extensionsPath, id); return this.setObsolete(id) .then(() => pfs.rimraf(extensionPath)) @@ -428,7 +443,7 @@ export class ExtensionManagementService implements IExtensionManagementService { await this.galleryService.reportStatistic(extension.manifest.publisher, extension.manifest.name, extension.manifest.version, StatisticType.Uninstall); } - this._onDidUninstallExtension.fire({ id: extension.id, error }); + this._onDidUninstallExtension.fire({ identifier: extension.identifier, error }); } getInstalled(type: LocalExtensionType = null): TPromise { @@ -474,7 +489,8 @@ export class ExtensionManagementService implements IExtensionManagementService { if (manifest.extensionDependencies) { manifest.extensionDependencies = manifest.extensionDependencies.map(id => adoptToGalleryExtensionId(id)); } - return { type, id, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; + const identifier = { id, uuid: metadata ? metadata.id : null }; + return { type, identifier, manifest, metadata, path: extensionPath, readmeUrl, changelogUrl }; }); }).then(null, () => null); @@ -578,3 +594,15 @@ export class ExtensionManagementService implements IExtensionManagementService { this.disposables = dispose(this.disposables); } } + +export function getLocalExtensionIdFromGallery(extension: IGalleryExtension, version: string): string { + return getLocalExtensionId(extension.identifier.id, version); +} + +export function getLocalExtensionIdFromManifest(manifest: IExtensionManifest): string { + return getLocalExtensionId(getGalleryExtensionId(manifest.publisher, manifest.name), manifest.version); +} + +function getLocalExtensionId(id: string, version: string): string { + return `${id}-${version}`; +} \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts index e35a98d864ca2..bcc48a9223275 100644 --- a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts +++ b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts @@ -69,7 +69,7 @@ suite('ExtensionEnablementService Test', () => { }); test('test when no extensions are disabled for workspace when there is no workspace', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); @@ -78,13 +78,13 @@ suite('ExtensionEnablementService Test', () => { }); test('test disable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test disable an extension globally should return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(value => assert.ok(value)) .then(done, done); }); @@ -92,180 +92,180 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally triggers the change event', (done) => { const target = sinon.spy(); testObject.onEnablementChanged(target); - testObject.setEnablement('pub.a', false) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions())) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test disable an extension for workspace returns a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace again should return a falsy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(!value)) .then(done, done); }); test('test disable an extension for workspace and then globally', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension for workspace and then globally return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension for workspace and then globally triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension globally and then for workspace', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test disable an extension globally and then for workspace return a truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', false, true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test disable an extension globally and then for workspace triggers the change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', false, true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test disable an extension for workspace when there is no workspace throws error', (done) => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); - testObject.setEnablement('pub.a', false, true) + testObject.setEnablement({ id: 'pub.a' }, false, true) .then(() => assert.fail('should throw an error'), error => assert.ok(error)) .then(done, done); }); test('test enable an extension globally', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => assert.deepEqual([], testObject.getGloballyDisabledExtensions())) .then(done, done); }); test('test enable an extension globally return truthy promise', (done) => { - testObject.setEnablement('pub.a', false) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension globally triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.a', false) + testObject.setEnablement({ id: 'pub.a' }, false) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.a', true)) - .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.a' }))) .then(done, done); }); test('test enable an extension globally when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true) + testObject.setEnablement({ id: 'pub.a' }, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => assert.deepEqual([], testObject.getWorkspaceDisabledExtensions())) .then(done, done); }); test('test enable an extension for workspace return truthy promise', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(value => assert.ok(value)) .then(done, done); }); test('test enable an extension for workspace triggers change event', (done) => { const target = sinon.spy(); - testObject.setEnablement('pub.b', false, true) + testObject.setEnablement({ id: 'pub.b' }, false, true) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement('pub.b', true, true)) - .then(() => assert.ok(target.calledWithExactly('pub.b'))) + .then(() => testObject.setEnablement({ id: 'pub.b' }, true, true)) + .then(() => assert.ok(target.calledWithExactly({ id: 'pub.b' }))) .then(done, done); }); test('test enable an extension for workspace when already enabled return falsy promise', (done) => { - testObject.setEnablement('pub.a', true, true) + testObject.setEnablement({ id: 'pub.a' }, true, true) .then(value => assert.ok(!value)) .then(done, done); }); test('test enable an extension for workspace when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true, true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getGloballyDisabledExtensions()); assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); }) .then(done, done); }); test('test enable an extension globally when disabled in workspace and gloablly', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => testObject.setEnablement('pub.a', true)) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => testObject.setEnablement({ id: 'pub.a' }, true)) .then(() => { - assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([{ id: 'pub.a' }], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); }) .then(done, done); }); test('test remove an extension from disablement list when uninstalled', (done) => { - testObject.setEnablement('pub.a', false, true) - .then(() => testObject.setEnablement('pub.a', false)) - .then(() => didUninstallEvent.fire({ id: 'pub.a-1.0.0' })) + testObject.setEnablement({ id: 'pub.a' }, false, true) + .then(() => testObject.setEnablement({ id: 'pub.a' }, false)) + .then(() => didUninstallEvent.fire({ identifier: { id: 'pub.a-1.0.0' } })) .then(() => { assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); assert.deepEqual([], testObject.getGloballyDisabledExtensions()); diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index d8f1a0c5c8251..b125ab5eff129 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -12,6 +12,7 @@ import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistr export interface IExtensionDescription { readonly id: string; readonly name: string; + readonly uuid?: string; readonly displayName?: string; readonly version: string; readonly publisher: string; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 9fe32c3653940..d3b00f3c3d7e9 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -436,7 +436,7 @@ export class EnableForWorkspaceAction extends Action implements IExtensionAction private update(): void { this.enabled = false; if (this.extension) { - this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = !this.extension.disabledGlobally && this.extension.disabledForWorkspace && this.extensionEnablementService.canEnable(this.extension); } } @@ -475,7 +475,7 @@ export class EnableGloballyAction extends Action implements IExtensionAction { private update(): void { this.enabled = false; if (this.extension) { - this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.disabledGlobally && this.extensionEnablementService.canEnable(this.extension); } } @@ -531,7 +531,7 @@ export class EnableAction extends Action { return; } - this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension.id); + this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.disabledGlobally || this.extension.disabledForWorkspace) && this.extensionEnablementService.canEnable(this.extension); this.class = this.enabled ? EnableAction.EnabledClass : EnableAction.DisabledClass; } @@ -1536,7 +1536,7 @@ export class EnableAllAction extends Action { } private update(): void { - this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && e.disabledGlobally); + this.enabled = this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && e.disabledGlobally); } run(): TPromise { @@ -1569,7 +1569,7 @@ export class EnableAllWorkpsaceAction extends Action { } private update(): void { - this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e.id) && !e.disabledGlobally && e.disabledForWorkspace); + this.enabled = this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY && this.extensionsWorkbenchService.local.some(e => this.extensionEnablementService.canEnable(e) && !e.disabledGlobally && e.disabledForWorkspace); } run(): TPromise { diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index c19f4aba5be0f..3327da7f2c9c7 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -29,6 +29,7 @@ export interface IExtension { name: string; displayName: string; id: string; + uuid: string; publisher: string; publisherDisplayName: string; version: string; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts index 72e3aae237b6c..562531b19930d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsUtils.ts @@ -12,7 +12,7 @@ import { onUnexpectedError, canceled } from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, LocalExtensionType, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; @@ -20,10 +20,10 @@ import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiati import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IMessageService, Severity, IChoiceService } from 'vs/platform/message/common/message'; import { Action } from 'vs/base/common/actions'; -import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { BetterMergeDisabledNowKey, BetterMergeId, getIdAndVersionFromLocalExtensionId, areSameExtensions, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; export interface IExtensionStatus { - identifier: string; + identifier: IExtensionIdentifier; local: ILocalExtension; globallyEnabled: boolean; } @@ -42,8 +42,8 @@ export class KeymapExtensions implements IWorkbenchContribution { ) { this.disposables.push( lifecycleService.onShutdown(() => this.dispose()), - instantiationService.invokeFunction(onExtensionChanged)((ids => { - TPromise.join(ids.map(id => this.checkForOtherKeymaps(id))) + instantiationService.invokeFunction(onExtensionChanged)((identifiers => { + TPromise.join(identifiers.map(identifier => this.checkForOtherKeymaps(identifier))) .then(null, onUnexpectedError); })) ); @@ -53,12 +53,12 @@ export class KeymapExtensions implements IWorkbenchContribution { return 'vs.extensions.keymapExtensions'; } - private checkForOtherKeymaps(extensionId: string): TPromise { + private checkForOtherKeymaps(extensionIdentifier: IExtensionIdentifier): TPromise { return this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { const keymaps = extensions.filter(extension => isKeymapExtension(this.tipsService, extension)); - const extension = arrays.first(keymaps, extension => extension.identifier === extensionId); + const extension = arrays.first(keymaps, extension => extension.identifier.id === extensionIdentifier.id); if (extension && extension.globallyEnabled) { - const otherKeymaps = keymaps.filter(extension => extension.identifier !== extensionId && extension.globallyEnabled); + const otherKeymaps = keymaps.filter(extension => extension.identifier.id !== extensionIdentifier.id && extension.globallyEnabled); if (otherKeymaps.length) { return this.promptForDisablingOtherKeymaps(extension, otherKeymaps); } @@ -107,7 +107,7 @@ export class KeymapExtensions implements IWorkbenchContribution { this.telemetryService.publicLog('disableOtherKeymaps', telemetryData); if (confirmed) { return TPromise.join(oldKeymaps.map(keymap => { - return this.extensionEnablementService.setEnablement(keymap.identifier, false); + return this.extensionEnablementService.setEnablement(keymap.local.identifier, false); })); } return undefined; @@ -120,18 +120,18 @@ export class KeymapExtensions implements IWorkbenchContribution { } } -export function onExtensionChanged(accessor: ServicesAccessor): Event { +export function onExtensionChanged(accessor: ServicesAccessor): Event { const extensionService = accessor.get(IExtensionManagementService); const extensionEnablementService = accessor.get(IExtensionEnablementService); - return debounceEvent(anyEvent( + return debounceEvent(anyEvent( chain(anyEvent(extensionService.onDidInstallExtension, extensionService.onDidUninstallExtension)) - .map(e => stripVersion(e.id)) + .map(e => ({ id: stripVersion(e.identifier.id), uuid: e.identifier.uuid })) .event, extensionEnablementService.onEnablementChanged ), (list, id) => { if (!list) { return [id]; - } else if (list.indexOf(id) === -1) { + } else if (list.some(l => !areSameExtensions(l, id))) { list.push(id); } return list; @@ -144,11 +144,10 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { const globallyDisabled = extensionEnablementService.getGloballyDisabledExtensions(); return extensions.map(extension => { - const identifier = stripVersion(extension.id); return { - identifier, + identifier: { id: adoptToGalleryExtensionId(extension.identifier.id), uuid: extension.identifier.uuid }, local: extension, - globallyEnabled: globallyDisabled.indexOf(identifier) === -1 + globallyEnabled: globallyDisabled.every(disabled => !areSameExtensions(disabled, extension.identifier)) }; }); }); @@ -156,7 +155,7 @@ export function getInstalledExtensions(accessor: ServicesAccessor): TPromise { - return Promise.all(extensions.filter(e => stripVersion(e.id) === BetterMergeId) + return Promise.all(extensions.filter(e => stripVersion(e.identifier.id) === BetterMergeId) .map(e => extensionManagementService.uninstall(e, true))); }); }), diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index b21a040cde013..5ff2eb89af6a7 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -20,9 +20,9 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, IExtensionManifest, - InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService + InstallExtensionEvent, DidInstallExtensionEvent, LocalExtensionType, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionTipsService, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionIdFromLocal, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -71,11 +71,15 @@ class Extension implements IExtension { get id(): string { if (this.gallery) { - return this.gallery.id; + return this.gallery.identifier.id; } return getGalleryExtensionIdFromLocal(this.local); } + get uuid(): string { + return this.gallery ? this.gallery.identifier.uuid : this.local.identifier.uuid; + } + get publisher(): string { return this.gallery ? this.gallery.publisher : this.local.manifest.publisher; } @@ -365,14 +369,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { queryLocal(): TPromise { return this.extensionService.getInstalled().then(result => { - const installedById = index(this.installed, e => e.local.id); + const installedById = index(this.installed, e => e.local.identifier.id); const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); this.installed = result.map(local => { - const extension = installedById[local.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService); + const extension = installedById[local.identifier.id] || new Extension(this.galleryService, this.stateProvider, local, null, this.telemetryService); extension.local = local; - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(d => areSameExtensions(d, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(d => areSameExtensions(d, extension)); return extension; }); @@ -423,7 +427,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private fromGallery(gallery: IGalleryExtension): Extension { - const installed = this.installed.filter(installed => installed.id === gallery.id)[0]; + const installed = this.getInstalledExtensionMatchingGallery(gallery); if (installed) { // Loading the compatible version only there is an engine property @@ -439,6 +443,21 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); } + private getInstalledExtensionMatchingGallery(gallery: IGalleryExtension): Extension { + for (const installed of this.installed) { + if (installed.uuid) { // Installed from Gallery + if (installed.uuid === gallery.identifier.uuid) { + return installed; + } + } else { + if (installed.id === gallery.identifier.id) { // Installed from other sources + return installed; + } + } + } + return null; + } + private syncLocalWithGalleryExtension(local: Extension, gallery: IGalleryExtension) { local.gallery = gallery; this._onChange.fire(); @@ -462,15 +481,26 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } private syncWithGallery(): TPromise { - const names = this.installed - .filter(e => e.type === LocalExtensionType.User) - .map(e => e.id); + const ids = [], names = []; + for (const installed of this.installed) { + if (installed.type === LocalExtensionType.User) { + if (installed.uuid) { + ids.push(installed.uuid); + } else { + names.push(installed.id); + } + } + } - if (names.length === 0) { - return TPromise.as(null); + const promises = []; + if (ids.length) { + promises.push(this.queryGallery({ ids, pageSize: ids.length })); + } + if (names.length) { + promises.push(this.queryGallery({ names, pageSize: names.length })); } - return this.queryGallery({ names, pageSize: names.length }) as TPromise; + return TPromise.join(promises) as TPromise; } private eventuallyAutoUpdateExtensions(): void { @@ -670,12 +700,12 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private doSetEnablement(extension: IExtension, enable: boolean, workspace: boolean): TPromise { if (workspace) { - return this.extensionEnablementService.setEnablement(extension.id, enable, workspace); + return this.extensionEnablementService.setEnablement(extension, enable, workspace); } - const globalElablement = this.extensionEnablementService.setEnablement(extension.id, enable, false); + const globalElablement = this.extensionEnablementService.setEnablement(extension, enable, false); if (enable && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY) { - const workspaceEnablement = this.extensionEnablementService.setEnablement(extension.id, enable, true); + const workspaceEnablement = this.extensionEnablementService.setEnablement(extension, enable, true); return TPromise.join([globalElablement, workspaceEnablement]).then(values => values[0] || values[1]); } return globalElablement; @@ -695,7 +725,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return; } - let extension = this.installed.filter(e => e.id === gallery.id)[0]; + let extension = this.installed.filter(e => areSameExtensions(e, gallery.identifier))[0]; if (!extension) { extension = new Extension(this.galleryService, this.stateProvider, null, gallery, this.telemetryService); @@ -712,7 +742,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { private onDidInstallExtension(event: DidInstallExtensionEvent): void { const { local, zipPath, error, gallery } = event; - const installing = gallery ? this.installing.filter(e => e.extension.id === gallery.id)[0] : null; + const installing = gallery ? this.installing.filter(e => areSameExtensions(e.extension, gallery.identifier))[0] : null; const extension: Extension = installing ? installing.extension : zipPath ? new Extension(this.galleryService, this.stateProvider, null, null, this.telemetryService) : null; if (extension) { this.installing = installing ? this.installing.filter(e => e !== installing) : this.installing; @@ -738,9 +768,9 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { this._onChange.fire(); } - private onUninstallExtension(id: string): void { - const extension = this.installed.filter(e => e.local.id === id)[0]; - const newLength = this.installed.filter(e => e.local.id !== id).length; + private onUninstallExtension({ id }: IExtensionIdentifier): void { + const extension = this.installed.filter(e => e.local.identifier.id === id)[0]; + const newLength = this.installed.filter(e => e.local.identifier.id !== id).length; // TODO: Ask @Joao why is this? if (newLength === this.installed.length) { return; @@ -748,19 +778,20 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { const start = new Date(); const operation = Operation.Uninstalling; - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0] || { id, operation, extension, start }; - this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.id !== id)]; + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0] || { id, operation, extension, start }; + this.uninstalling = [uninstalling, ...this.uninstalling.filter(e => e.extension.local.identifier.id !== id)]; this._onChange.fire(); } - private onDidUninstallExtension({ id, error }: DidUninstallExtensionEvent): void { + private onDidUninstallExtension({ identifier, error }: DidUninstallExtensionEvent): void { + const id = identifier.id; if (!error) { - this.installed = this.installed.filter(e => e.local.id !== id); + this.installed = this.installed.filter(e => e.local.identifier.id !== id); } - const uninstalling = this.uninstalling.filter(e => e.extension.local.id === id)[0]; - this.uninstalling = this.uninstalling.filter(e => e.extension.local.id !== id); + const uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id === id)[0]; + this.uninstalling = this.uninstalling.filter(e => e.extension.local.identifier.id !== id); if (!uninstalling) { return; } @@ -772,19 +803,19 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { this._onChange.fire(); } - private onEnablementChanged(extensionIdentifier: string) { - const [extension] = this.local.filter(e => e.id === extensionIdentifier); + private onEnablementChanged(extensionIdentifier: IExtensionIdentifier) { + const [extension] = this.local.filter(e => areSameExtensions(e, extensionIdentifier)); if (extension) { const globallyDisabledExtensions = this.extensionEnablementService.getGloballyDisabledExtensions(); const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); - extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.id) !== -1; - extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.id) !== -1; + extension.disabledGlobally = globallyDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); + extension.disabledForWorkspace = workspaceDisabledExtensions.some(disabled => areSameExtensions(disabled, extension)); this._onChange.fire(); } } private getExtensionState(extension: Extension): ExtensionState { - if (extension.gallery && this.installing.some(e => e.extension.gallery && e.extension.gallery.id === extension.gallery.id)) { + if (extension.gallery && this.installing.some(e => e.extension.gallery && areSameExtensions(e.extension.gallery.identifier, extension.gallery.identifier))) { return ExtensionState.Installing; } @@ -792,7 +823,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return ExtensionState.Uninstalling; } - const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && e.gallery.id === extension.gallery.id))[0]; + const local = this.installed.filter(e => e === extension || (e.gallery && extension.gallery && areSameExtensions(e.gallery.identifier, extension.gallery.identifier)))[0]; return local ? ExtensionState.Installed : ExtensionState.Uninstalled; } diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts index 17f180eedc120..518df124a0eec 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsActions.test.ts @@ -14,10 +14,10 @@ import * as ExtensionsActions from 'vs/workbench/parts/extensions/browser/extens import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -38,14 +38,14 @@ suite('ExtensionsActions Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -94,7 +94,7 @@ suite('ExtensionsActions Test', () => { const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier }))); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; assert.ok(!testObject.enabled); @@ -112,7 +112,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -140,8 +140,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -154,8 +154,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); testObject.extension = extensions[0]; assert.ok(!testObject.enabled); done(); @@ -175,7 +175,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -219,8 +219,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(paged => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Uninstall', testObject.label); @@ -285,7 +285,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('Installing', testObject.label); @@ -301,7 +301,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('Uninstalling', testObject.label); assert.equal('extension-action uninstall uninstalling', testObject.class); @@ -333,7 +333,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: local.manifest.version }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: local.manifest.version }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -348,7 +348,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(!testObject.enabled); done(); @@ -363,7 +363,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }))); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { assert.ok(testObject.enabled); done(); @@ -378,10 +378,10 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.1' }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.1' }); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { - installEvent.fire({ id: local.id, gallery }); + installEvent.fire({ identifier: local.identifier, gallery }); assert.ok(!testObject.enabled); done(); }); @@ -432,7 +432,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); assert.equal('extension-action manage hide', testObject.class); assert.equal('', testObject.tooltip); @@ -448,8 +448,8 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -481,7 +481,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); assert.equal('extension-action manage', testObject.class); @@ -510,7 +510,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when there extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -523,7 +523,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -536,8 +536,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableForWorkspaceAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -568,7 +568,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -581,7 +581,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -594,8 +594,8 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableGloballyAction when the extension is disabled in both', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -626,7 +626,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -639,7 +639,7 @@ suite('ExtensionsActions Test', () => { }); test('Test EnableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -671,7 +671,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -685,7 +685,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -698,7 +698,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -711,7 +711,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableForWorkspaceAction when the extension is disabled workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -742,7 +742,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -755,7 +755,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableGloballyAction when the extension is disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -798,7 +798,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled globally', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -811,7 +811,7 @@ suite('ExtensionsActions Test', () => { }); test('Test DisableAction when extension is installed and disabled for workspace', (done) => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); const local = aLocalExtension('a'); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); @@ -843,7 +843,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { testObject.extension = page.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -857,7 +857,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -884,7 +884,7 @@ suite('ExtensionsActions Test', () => { const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest))); workbenchService.queryGallery().done(() => { assert.ok(testObject.enabled); done(); @@ -895,13 +895,13 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and some outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); assert.ok(testObject.enabled); done(); }); @@ -911,14 +911,14 @@ suite('ExtensionsActions Test', () => { test('Test UpdateAllAction when some installed extensions are outdated and all outdated are being installed', (done) => { const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; - const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; + const gallery = [aGalleryExtension('a', { identifier: local[0].identifier, version: '1.0.2' }), aGalleryExtension('b', { identifier: local[1].identifier, version: '1.0.2' }), aGalleryExtension('c', local[2].manifest)]; const workbenchService = instantiationService.get(IExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); workbenchService.queryLocal().done(() => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); workbenchService.queryGallery().done(() => { - installEvent.fire({ id: local[0].id, gallery: gallery[0] }); - installEvent.fire({ id: local[1].id, gallery: gallery[1] }); + installEvent.fire({ identifier: local[0].identifier, gallery: gallery[0] }); + installEvent.fire({ identifier: local[1].identifier, gallery: gallery[1] }); assert.ok(!testObject.enabled); done(); }); @@ -938,7 +938,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); workbenchService.queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(!testObject.enabled); done(); @@ -952,7 +952,7 @@ suite('ExtensionsActions Test', () => { instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(!testObject.enabled); done(); }); @@ -965,8 +965,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to activate', testObject.tooltip); @@ -982,11 +982,11 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { testObject.extension = paged.firstPage[0]; - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local: aLocalExtension('a', gallery, { id }) }); - uninstallEvent.fire(id); - didUninstallEvent.fire({ id }); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; + installEvent.fire({ identifier: identifier, gallery }); + didInstallEvent.fire({ identifier: identifier, gallery, local: aLocalExtension('a', gallery, { identifier }) }); + uninstallEvent.fire(identifier); + didUninstallEvent.fire({ identifier: identifier }); assert.ok(!testObject.enabled); done(); @@ -1000,8 +1000,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(testObject.enabled); assert.equal('Reload to deactivate', testObject.tooltip); @@ -1017,13 +1017,13 @@ suite('ExtensionsActions Test', () => { instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { testObject.extension = extensions[0]; - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); const gallery = aGalleryExtension('a'); const id = getLocalExtensionIdFromGallery(gallery, gallery.version); - installEvent.fire({ id, gallery }); - didInstallEvent.fire({ id, gallery, local }); + installEvent.fire({ identifier: { id }, gallery }); + didInstallEvent.fire({ identifier: { id }, gallery, local }); assert.ok(!testObject.enabled); done(); @@ -1039,9 +1039,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { uuid: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { uuid: local.identifier.id, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(testObject.enabled); assert.equal('Reload to update', testObject.tooltip); @@ -1053,7 +1053,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1061,9 +1061,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); assert.ok(!testObject.enabled); done(); @@ -1105,7 +1105,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is enabled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1123,7 +1123,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension enablement is toggled when not running', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a'); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1140,7 +1140,7 @@ suite('ExtensionsActions Test', () => { test('Test ReloadAction when extension is updated when not running and enabled', (done) => { instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); const local = aLocalExtension('a', { version: '1.0.1' }); const workbenchService = instantiationService.get(IExtensionsWorkbenchService); @@ -1148,9 +1148,9 @@ suite('ExtensionsActions Test', () => { workbenchService.queryLocal().done(extensions => { testObject.extension = extensions[0]; - const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); - installEvent.fire({ id: gallery.uuid, gallery }); - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension('a', gallery, gallery) }); + const gallery = aGalleryExtension('a', { identifier: local.identifier, version: '1.0.2' }); + installEvent.fire({ identifier: gallery.identifier, gallery }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension('a', gallery, gallery) }); workbenchService.setEnablement(extensions[0], true); assert.ok(testObject.enabled); @@ -1164,17 +1164,17 @@ suite('ExtensionsActions Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } diff --git a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 2fad5c275f03d..d7c1978b71302 100644 --- a/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/parts/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -15,10 +15,10 @@ import { IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/parts/ import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, IExtensionTipsService, ILocalExtension, LocalExtensionType, IGalleryExtension, - DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent, IGalleryExtensionAssets, IExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getLocalExtensionIdFromManifest, getGalleryExtensionId, getLocalExtensionIdFromGallery } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ExtensionManagementService, getLocalExtensionIdFromGallery, getLocalExtensionIdFromManifest } from 'vs/platform/extensionManagement/node/extensionManagementService'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; @@ -40,13 +40,13 @@ suite('ExtensionsWorkbenchService Test', () => { let installEvent: Emitter, didInstallEvent: Emitter, - uninstallEvent: Emitter, + uninstallEvent: Emitter, didUninstallEvent: Emitter; suiteSetup(() => { installEvent = new Emitter(); didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); + uninstallEvent = new Emitter(); didUninstallEvent = new Emitter(); instantiationService = new TestInstantiationService(); @@ -232,7 +232,7 @@ suite('ExtensionsWorkbenchService Test', () => { changelogUrl: 'localChangelogUrl2', }); const gallery1 = aGalleryExtension(local1.manifest.name, { - id: local1.id, + identifier: local1.identifier, displayName: 'expectedDisplayName', version: '1.5.0', publisherId: 'expectedPublisherId', @@ -309,10 +309,10 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - const id = getLocalExtensionIdFromGallery(gallery, gallery.version); + const identifier = { id: getLocalExtensionIdFromGallery(gallery, gallery.version) }; // Installing - installEvent.fire({ id, gallery }); + installEvent.fire({ identifier, gallery }); let local = testObject.local; assert.equal(1, local.length); const actual = local[0]; @@ -320,18 +320,18 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Installing, actual.state); // Installed - didInstallEvent.fire({ id, gallery, local: aLocalExtension(gallery.name, gallery, { id }) }); + didInstallEvent.fire({ identifier, gallery, local: aLocalExtension(gallery.name, gallery, { identifier }) }); assert.equal(ExtensionState.Installed, actual.state); assert.equal(1, testObject.local.length); testObject.uninstall(actual); // Uninstalling - uninstallEvent.fire(id); + uninstallEvent.fire(identifier); assert.equal(ExtensionState.Uninstalling, actual.state); // Uninstalled - didUninstallEvent.fire({ id }); + didUninstallEvent.fire({ identifier }); assert.equal(ExtensionState.Uninstalled, actual.state); assert.equal(0, testObject.local.length); @@ -341,7 +341,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test extension doesnot show outdated for system extensions', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id, version: '1.0.2' }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier, version: '1.0.2' }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); assert.ok(!testObject.local[0].outdated); @@ -353,8 +353,8 @@ suite('ExtensionsWorkbenchService Test', () => { testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; testObject.uninstall(target); - uninstallEvent.fire(local.id); - didUninstallEvent.fire({ id: local.id }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(!testObject.canInstall(target)); }); @@ -362,7 +362,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns false for a system extension', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -372,7 +372,7 @@ suite('ExtensionsWorkbenchService Test', () => { test('test canInstall returns true for extensions with gallery', () => { const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.User }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { identifier: local.identifier }))); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = testObject.local[0]; @@ -392,11 +392,11 @@ suite('ExtensionsWorkbenchService Test', () => { assert.equal(ExtensionState.Uninstalled, extension.state); testObject.install(extension); - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); testObject.onChange(target); // Installed - didInstallEvent.fire({ id: gallery.uuid, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); + didInstallEvent.fire({ identifier: gallery.identifier, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); assert.ok(target.calledOnce); }); @@ -416,7 +416,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.onChange(target); // Installing - installEvent.fire({ id: gallery.uuid, gallery }); + installEvent.fire({ identifier: gallery.identifier, gallery }); assert.ok(target.calledOnce); }); @@ -430,7 +430,7 @@ suite('ExtensionsWorkbenchService Test', () => { testObject.uninstall(testObject.local[0]); testObject.onChange(target); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); assert.ok(target.calledOnce); }); @@ -442,9 +442,9 @@ suite('ExtensionsWorkbenchService Test', () => { const target = sinon.spy(); testObject.uninstall(testObject.local[0]); - uninstallEvent.fire(local.id); + uninstallEvent.fire(local.identifier); testObject.onChange(target); - didUninstallEvent.fire({ id: local.id }); + didUninstallEvent.fire({ identifier: local.identifier }); assert.ok(target.calledOnce); }); @@ -692,8 +692,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for uninstalled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); return testObject.queryGallery().then(pagedResponse => { @@ -705,8 +705,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are false for installed enabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -717,10 +717,10 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled for workspace is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.e', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.e' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -732,9 +732,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled globally is set', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.d' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -746,8 +746,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable flags are updated for user extensions', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -759,7 +759,7 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension globally when extension is disabled for workspace', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -793,12 +793,12 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disabled flags are updated on change from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); const actual = testObject.local[0]; assert.ok(!actual.disabledForWorkspace); @@ -806,9 +806,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -819,9 +819,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with dependencies disable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -833,9 +833,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if extension is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -843,9 +843,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension does not fail if its dependency is a dependent of other but chosen to disable only itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -856,9 +856,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension fails if its dependency is a dependent of other', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -868,9 +868,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is a dependent of other disabled extension', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -883,9 +883,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependencys dependency is itself', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.a'] }), aLocalExtension('c')]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -898,9 +898,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension if its dependency is dependent and is disabled', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c', { extensionDependencies: ['pub.b'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -912,9 +912,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test disable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', true); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); instantiationService.stubPromise(IChoiceService, 'choose', 1); @@ -928,9 +928,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with dependencies enable all', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b'), aLocalExtension('c')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -941,9 +941,9 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test enable extension with cyclic dependencies', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', { extensionDependencies: ['pub.b'] }), aLocalExtension('b', { extensionDependencies: ['pub.c'] }), aLocalExtension('c', { extensionDependencies: ['pub.a'] })]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); @@ -956,8 +956,8 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); @@ -969,14 +969,14 @@ suite('ExtensionsWorkbenchService Test', () => { }); test('test change event is fired when disablement flags are changed from outside', () => { - instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.c' }, false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.b' }, false, true); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); testObject = instantiationService.createInstance(ExtensionsWorkbenchService); const target = sinon.spy(); testObject.onChange(target); - instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement({ id: 'pub.a' }, false); assert.ok(target.calledOnce); }); @@ -985,8 +985,8 @@ suite('ExtensionsWorkbenchService Test', () => { const localExtension = Object.create({ manifest: {} }); assign(localExtension, { type: LocalExtensionType.User, manifest: {} }, properties); assign(localExtension.manifest, { name, publisher: 'pub', version: '1.0.0' }, manifest); - localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; - localExtension.id = getLocalExtensionIdFromManifest(localExtension.manifest); + localExtension.identifier = { id: getLocalExtensionIdFromManifest(localExtension.manifest) }; + localExtension.metadata = { id: localExtension.identifier.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; return localExtension; } @@ -1001,10 +1001,10 @@ suite('ExtensionsWorkbenchService Test', () => { function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: IGalleryExtensionAssets = noAssets): IGalleryExtension { const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', uuid: generateUuid(), version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); assign(galleryExtension.assets, assets); - galleryExtension.id = getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; return galleryExtension; } diff --git a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts index dff17826c3b1d..72d281c079ac8 100644 --- a/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts +++ b/src/vs/workbench/parts/welcome/page/electron-browser/welcomePage.ts @@ -417,7 +417,7 @@ class WelcomePage { extensionId: extensionSuggestion.id, }); this.instantiationService.invokeFunction(getInstalledExtensions).then(extensions => { - const installedExtension = arrays.first(extensions, extension => extension.identifier === extensionSuggestion.id); + const installedExtension = arrays.first(extensions, extension => extension.identifier.id === extensionSuggestion.id); if (installedExtension && installedExtension.globallyEnabled) { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-1" : { @@ -443,7 +443,7 @@ class WelcomePage { return this.extensionManagementService.installFromGallery(extension) .then(() => { // TODO: Do this as part of the install to avoid multiple events. - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, false); + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, false); }).then(() => { return true; }); @@ -466,7 +466,7 @@ class WelcomePage { return foundAndInstalled.then(found => { messageDelay.cancel(); if (found) { - return this.extensionEnablementService.setEnablement(extensionSuggestion.id, true) + return this.extensionEnablementService.setEnablement({ id: extensionSuggestion.id }, true) .then(() => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-2" : { diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts index 60261ce5e0df5..7e08926c197e0 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionPoints.ts @@ -59,7 +59,12 @@ class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { try { - return JSON.parse(manifestContents.toString()); + const manifest = JSON.parse(manifestContents.toString()); + if (manifest.__metadata) { + manifest.uuid = manifest.__metadata.id; + } + delete manifest.__metadata; + return manifest; } catch (e) { this._log.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, getParseErrorMessage(e.message))); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 46852ac790765..aaff127a4b96e 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -295,6 +295,10 @@ export class ExtensionService implements IExtensionService { }); ExtensionService._scanInstalledExtensions(this._environmentService, log).then((installedExtensions) => { + + // Migrate enablement service to use identifiers + this._extensionEnablementService.migrateToIdentifiers(installedExtensions); + const disabledExtensions = [ ...getGloballyDisabledExtensions(this._extensionEnablementService, this._storageService, installedExtensions), ...this._extensionEnablementService.getWorkspaceDisabledExtensions() @@ -314,7 +318,7 @@ export class ExtensionService implements IExtensionService { if (disabledExtensions.length === 0) { return installedExtensions; } - return installedExtensions.filter(e => disabledExtensions.every(id => !areSameExtensions({ id }, e))); + return installedExtensions.filter(e => disabledExtensions.every(disabled => !areSameExtensions(disabled, e))); }).then((extensionDescriptions) => { this._registry = new ExtensionDescriptionRegistry(extensionDescriptions);