diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index f547bdb49cf03..b215a23c6544e 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -16,7 +16,7 @@ import { URI } from 'vs/base/common/uri'; import { IHeaders, IRequestContext, IRequestOptions } from 'vs/base/parts/request/common/request'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { DefaultIconPath, getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionIdentifierWithVersion, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isIExtensionIdentifier, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, TargetPlatform, toTargetPlatform, WEB_EXTENSION_TAG } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { DefaultIconPath, getFallbackTargetPlarforms, getTargetPlatform, IExtensionGalleryService, IExtensionIdentifier, IExtensionIdentifierWithVersion, IGalleryExtension, IGalleryExtensionAsset, IGalleryExtensionAssets, IGalleryExtensionVersion, InstallOperation, IQueryOptions, IExtensionsControlManifest, isIExtensionIdentifier, isNotWebExtensionInWebTargetPlatform, isTargetPlatformCompatible, ITranslation, SortBy, SortOrder, StatisticType, TargetPlatform, toTargetPlatform, WEB_EXTENSION_TAG, IExtensionIdentifierWithPreRelease } from 'vs/platform/extensionManagement/common/extensionManagement'; import { adoptToGalleryExtensionId, areSameExtensions, getGalleryExtensionId, getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator'; @@ -506,9 +506,39 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const { galleryExtensions } = await this.queryGallery(query, CURRENT_TARGET_PLATFORM, CancellationToken.None); const galleryExtensionsByVersion = galleryExtensions.map(rawGalleryExtension => { const id = getGalleryExtensionId(rawGalleryExtension.publisher.publisherName, rawGalleryExtension.extensionName); - return { rawGalleryExtension, version: (identifiers.find(identifier => areSameExtensions(identifier, { id })))?.version }; + return { rawGalleryExtension, version: (identifiers.find(identifier => areSameExtensions(identifier, { id })))?.version, preRelease: includePreRelease }; }); - return this.converToGalleryExtensions(galleryExtensionsByVersion, includePreRelease, CURRENT_TARGET_PLATFORM, () => undefined, token); + return this.converToGalleryExtensions(galleryExtensionsByVersion, CURRENT_TARGET_PLATFORM, () => undefined, token); + } + + async getExtensions2(identifiers: ReadonlyArray): Promise { + const names: string[] = []; const ids: string[] = []; + for (const identifier of identifiers) { + if (identifier.uuid) { + ids.push(identifier.uuid); + } else { + names.push(identifier.id.toLowerCase()); + } + } + let query = new Query() + .withFlags(Flags.IncludeAssetUri, Flags.IncludeStatistics, Flags.IncludeCategoryAndTags, Flags.IncludeFiles, Flags.IncludeVersionProperties, Flags.IncludeLatestVersionOnly) + .withPage(1, identifiers.length) + .withFilter(FilterType.Target, 'Microsoft.VisualStudio.Code'); + if (ids.length) { + query = query.withFilter(FilterType.ExtensionId, ...ids); + } + if (names.length) { + query = query.withFilter(FilterType.ExtensionId, ...names); + } + + const { galleryExtensions: rawGalleryExtensions } = await this.queryGallery(query, CURRENT_TARGET_PLATFORM, CancellationToken.None); + const rawGalleryExtensionsInput = rawGalleryExtensions.map(rawGalleryExtension => { + const id = getGalleryExtensionId(rawGalleryExtension.publisher.publisherName, rawGalleryExtension.extensionName); + const identifier = identifiers.find(identifier => areSameExtensions(identifier, { id, uuid: rawGalleryExtension.extensionId })); + return { rawGalleryExtension, preRelease: !!identifier?.preRelease }; + }); + + return this.converToGalleryExtensions(rawGalleryExtensionsInput, CURRENT_TARGET_PLATFORM, () => undefined, CancellationToken.None); } async getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, includePreRelease: boolean, targetPlatform: TargetPlatform): Promise { @@ -653,33 +683,33 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi const { galleryExtensions, total } = await this.queryGallery(query, CURRENT_TARGET_PLATFORM, token); const telemetryData = (index: number) => ({ index: ((query.pageNumber - 1) * query.pageSize) + index, querySource: options.source }); - const extensions = await this.converToGalleryExtensions(galleryExtensions.map(rawGalleryExtension => ({ rawGalleryExtension })), !!options.includePreRelease, CURRENT_TARGET_PLATFORM, telemetryData, token); + const extensions = await this.converToGalleryExtensions(galleryExtensions.map(rawGalleryExtension => ({ rawGalleryExtension, preRelease: !!options.includePreRelease })), CURRENT_TARGET_PLATFORM, telemetryData, token); const getPage = async (pageIndex: number, ct: CancellationToken) => { if (ct.isCancellationRequested) { throw canceled(); } const nextPageQuery = query.withPage(pageIndex + 1); const { galleryExtensions } = await this.queryGallery(nextPageQuery, CURRENT_TARGET_PLATFORM, ct); - return await this.converToGalleryExtensions(galleryExtensions.map(rawGalleryExtension => ({ rawGalleryExtension })), !!options.includePreRelease, CURRENT_TARGET_PLATFORM, telemetryData, token); + return await this.converToGalleryExtensions(galleryExtensions.map(rawGalleryExtension => ({ rawGalleryExtension, preRelease: !!options.includePreRelease })), CURRENT_TARGET_PLATFORM, telemetryData, token); }; return { firstPage: extensions, total, pageSize: query.pageSize, getPage } as IPager; } - private async converToGalleryExtensions(rawGalleryExtensions: { rawGalleryExtension: IRawGalleryExtension, version?: string }[], includePreRelease: boolean, targetPlatform: TargetPlatform, telemetryData: (index: number) => IStringDictionary | undefined, token: CancellationToken): Promise { - const toExtensionWithLatestVersion = (galleryExtension: IRawGalleryExtension, index: number, hasReleaseVersion: boolean): IGalleryExtension => { + private async converToGalleryExtensions(rawGalleryExtensions: { rawGalleryExtension: IRawGalleryExtension, preRelease: boolean, version?: string }[], targetPlatform: TargetPlatform, telemetryData: (index: number) => IStringDictionary | undefined, token: CancellationToken): Promise { + const toExtensionWithLatestVersion = (galleryExtension: IRawGalleryExtension, index: number, hasReleaseVersion: boolean, preRelease: boolean): IGalleryExtension => { const allTargetPlatforms = getAllTargetPlatforms(galleryExtension); let latestVersion = galleryExtension.versions[0]; latestVersion = galleryExtension.versions.find(version => version.version === latestVersion.version && isTargetPlatformCompatible(getTargetPlatformForExtensionVersion(version), allTargetPlatforms, targetPlatform)) || latestVersion; - if (isPreReleaseVersion(latestVersion) && !includePreRelease) { + if (isPreReleaseVersion(latestVersion) && !preRelease) { latestVersion = galleryExtension.versions.find(version => version.version !== latestVersion.version && !isPreReleaseVersion(version)) || latestVersion; } return toExtension(galleryExtension, latestVersion, allTargetPlatforms, hasReleaseVersion, telemetryData(index)); }; const result: [number, IGalleryExtension][] = []; - const preReleaseVersions = new Map(); + const preReleaseVersions = new Map(); for (let index = 0; index < rawGalleryExtensions.length; index++) { - const { rawGalleryExtension, version } = rawGalleryExtensions[index]; + const { rawGalleryExtension, version, preRelease } = rawGalleryExtensions[index]; const hasReleaseVersion = rawGalleryExtension.versions.some(version => !isPreReleaseVersion(version)); if (version) { const versionAsset = rawGalleryExtension.versions.find(v => v.version === version); @@ -687,9 +717,9 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi result.push([index, toExtension(rawGalleryExtension, versionAsset, getAllTargetPlatforms(rawGalleryExtension), hasReleaseVersion)]); } } else { - const extension = toExtensionWithLatestVersion(rawGalleryExtension, index, hasReleaseVersion); + const extension = toExtensionWithLatestVersion(rawGalleryExtension, index, hasReleaseVersion, preRelease); if (extension.properties.isPreReleaseVersion) { - preReleaseVersions.set(extension.identifier.uuid, index); + preReleaseVersions.set(extension.identifier.uuid, { index, preRelease }); } else { result.push([index, extension]); } @@ -713,8 +743,8 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi } for (const rawGalleryExtension of galleryExtensions) { const hasReleaseVersion = rawGalleryExtension.versions.some(version => !isPreReleaseVersion(version)); - const index = preReleaseVersions.get(rawGalleryExtension.extensionId)!; - const extension = toExtensionWithLatestVersion(rawGalleryExtension, index, hasReleaseVersion); + const { index, preRelease } = preReleaseVersions.get(rawGalleryExtension.extensionId)!; + const extension = toExtensionWithLatestVersion(rawGalleryExtension, index, hasReleaseVersion, preRelease); result.push([index, extension]); } } diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts index 309613f6554e0..9b090274536c3 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagement.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts @@ -228,6 +228,10 @@ export interface IExtensionIdentifierWithVersion extends IExtensionIdentifier { version: string; } +export interface IExtensionIdentifierWithPreRelease extends IExtensionIdentifier { + preRelease: boolean; +} + export interface IGalleryExtensionIdentifier extends IExtensionIdentifier { uuid: string; } @@ -268,7 +272,7 @@ export interface IGalleryMetadata { id: string; publisherId: string; publisherDisplayName: string; - isPreReleaseVersion: boolean, + isPreReleaseVersion: boolean, } export type Metadata = Partial; @@ -338,6 +342,7 @@ export interface IExtensionGalleryService { query(options: IQueryOptions, token: CancellationToken): Promise>; getExtensions(identifiers: ReadonlyArray, token: CancellationToken): Promise; getExtensions(identifiers: ReadonlyArray, includePreRelease: boolean, token: CancellationToken): Promise; + getExtensions2(identifiers: ReadonlyArray): Promise; download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise; reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise; getReadme(extension: IGalleryExtension, token: CancellationToken): Promise; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index db58fb870c72b..a1e6bafbd7e67 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -379,7 +379,7 @@ class Extensions extends Disposable { private installed: Extension[] = []; constructor( - private readonly server: IExtensionManagementServer, + readonly server: IExtensionManagementServer, private readonly stateProvider: IExtensionStateProvider, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, @IWorkbenchExtensionEnablementService private readonly extensionEnablementService: IWorkbenchExtensionEnablementService, @@ -1018,21 +1018,22 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension .then(undefined, err => null); } - private syncWithGallery(): Promise { - const ids: string[] = [], names: string[] = []; + private async syncWithGallery(): Promise { + const identifiers: (IExtensionIdentifier & { preRelease: boolean })[] = [], names: string[] = []; for (const installed of this.local) { if (installed.type === ExtensionType.User) { if (installed.identifier.uuid) { - ids.push(installed.identifier.uuid); + identifiers.push({ ...installed.identifier, preRelease: !!installed.local?.isPreReleaseVersion || !!installed.local?.preRelease }); } else { names.push(installed.identifier.id); } } } - const promises: Promise>[] = []; - if (ids.length) { - promises.push(this.queryGallery({ ids, pageSize: ids.length }, CancellationToken.None)); + const promises: Promise[] = []; + if (identifiers.length) { + const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest(); + promises.push(this.galleryService.getExtensions2(identifiers).then(galleryExtensions => galleryExtensions.forEach(gallery => this.fromGallery(gallery, extensionsControlManifest)))); } if (names.length) { promises.push(this.queryGallery({ names, pageSize: names.length }, CancellationToken.None));