From e767f79f1f87ee4c2e75c267f886909396955812 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 17 Mar 2022 12:20:13 +0530 Subject: [PATCH] consider outdated targetplatform while loading extensions --- .../server/node/remoteAgentEnvironmentImpl.ts | 41 +++++++++++-------- src/vs/server/node/serverServices.ts | 4 +- .../extensions/common/extensionPoints.ts | 25 +++++++++-- .../cachedExtensionScanner.ts | 18 ++++---- 4 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/vs/server/node/remoteAgentEnvironmentImpl.ts b/src/vs/server/node/remoteAgentEnvironmentImpl.ts index 36a11016d2fe2..92bd8d309a36d 100644 --- a/src/vs/server/node/remoteAgentEnvironmentImpl.ts +++ b/src/vs/server/node/remoteAgentEnvironmentImpl.ts @@ -25,7 +25,7 @@ import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics import { basename, isAbsolute, join, normalize } from 'vs/base/common/path'; import { ProcessItem } from 'vs/base/common/processes'; import { IBuiltInExtension } from 'vs/base/common/product'; -import { IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementCLIService, IExtensionManagementService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { cwd } from 'vs/base/common/process'; import * as pfs from 'vs/base/node/pfs'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -58,8 +58,9 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { private readonly _connectionToken: ServerConnectionToken, private readonly environmentService: IServerEnvironmentService, extensionManagementCLIService: IExtensionManagementCLIService, + private readonly _extensionManagementService: IExtensionManagementService, private readonly logService: ILogService, - private readonly productService: IProductService + private readonly productService: IProductService, ) { this._logger = new class implements ILog { public error(source: string, message: string): void { @@ -389,10 +390,9 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { return r; } - private _scanDevelopedExtensions(language: string, translations: Translations, extensionDevelopmentPaths?: string[]): Promise { - + private async _scanDevelopedExtensions(language: string, translations: Translations, extensionDevelopmentPaths?: string[]): Promise { if (extensionDevelopmentPaths) { - + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); const extDescsP = extensionDevelopmentPaths.map(extDevPath => { return ExtensionScanner.scanOneOrMultipleExtensions( new ExtensionScannerInput( @@ -404,30 +404,31 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { extDevPath, false, // isBuiltin true, // isUnderDevelopment + targetPlatform, translations // translations ), this._extensionScannerHost ); }); - return Promise.all(extDescsP).then((extDescArrays: IExtensionDescription[][]) => { - let extDesc: IExtensionDescription[] = []; - for (let eds of extDescArrays) { - extDesc = extDesc.concat(eds); - } - return extDesc; - }); + const extDescArrays = await Promise.all(extDescsP); + let extDesc: IExtensionDescription[] = []; + for (let eds of extDescArrays) { + extDesc = extDesc.concat(eds); + } + return extDesc; } - return Promise.resolve([]); + return []; } - private _scanBuiltinExtensions(language: string, translations: Translations): Promise { + private async _scanBuiltinExtensions(language: string, translations: Translations): Promise { const version = this.productService.version; const commit = this.productService.commit; const date = this.productService.date; const devMode = !!process.env['VSCODE_DEV']; + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); - const input = new ExtensionScannerInput(version, date, commit, language, devMode, getSystemExtensionsRoot(), true, false, translations); + const input = new ExtensionScannerInput(version, date, commit, language, devMode, getSystemExtensionsRoot(), true, false, targetPlatform, translations); const builtinExtensions = ExtensionScanner.scanExtensions(input, this._extensionScannerHost); let finalBuiltinExtensions: Promise = builtinExtensions; @@ -444,7 +445,7 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { const builtInExtensions = Promise.resolve(this.productService.builtInExtensions || []); - const input = new ExtensionScannerInput(version, date, commit, language, devMode, getExtraDevSystemExtensionsRoot(), true, false, {}); + const input = new ExtensionScannerInput(version, date, commit, language, devMode, getExtraDevSystemExtensionsRoot(), true, false, targetPlatform, {}); const extraBuiltinExtensions = builtInExtensions .then((builtInExtensions) => new ExtraBuiltInExtensionResolver(builtInExtensions)) .then(resolver => ExtensionScanner.scanExtensions(input, this._extensionScannerHost, resolver)); @@ -455,7 +456,8 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { return finalBuiltinExtensions; } - private _scanInstalledExtensions(language: string, translations: Translations): Promise { + private async _scanInstalledExtensions(language: string, translations: Translations): Promise { + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); const devMode = !!process.env['VSCODE_DEV']; const input = new ExtensionScannerInput( this.productService.version, @@ -466,13 +468,15 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { this.environmentService.extensionsPath!, false, // isBuiltin false, // isUnderDevelopment + targetPlatform, translations ); return ExtensionScanner.scanExtensions(input, this._extensionScannerHost); } - private _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string, translations: Translations): Promise { + private async _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string, translations: Translations): Promise { + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); const devMode = !!process.env['VSCODE_DEV']; const input = new ExtensionScannerInput( this.productService.version, @@ -483,6 +487,7 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel { extensionPath, isBuiltin, false, // isUnderDevelopment + targetPlatform, translations ); return ExtensionScanner.scanSingleExtension(input, this._extensionScannerHost); diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts index 6c6e74409a089..0cef732294ec3 100644 --- a/src/vs/server/node/serverServices.ts +++ b/src/vs/server/node/serverServices.ts @@ -171,7 +171,8 @@ export async function setupServerServices(connectionToken: ServerConnectionToken services.set(ICredentialsMainService, new SyncDescriptor(CredentialsMainService, [true])); instantiationService.invokeFunction(accessor => { - const remoteExtensionEnvironmentChannel = new RemoteAgentEnvironmentChannel(connectionToken, environmentService, extensionManagementCLIService, logService, productService); + const extensionManagementService = accessor.get(IExtensionManagementService); + const remoteExtensionEnvironmentChannel = new RemoteAgentEnvironmentChannel(connectionToken, environmentService, extensionManagementCLIService, extensionManagementService, logService, productService); socketServer.registerChannel('remoteextensionsenvironment', remoteExtensionEnvironmentChannel); const telemetryChannel = new ServerTelemetryChannel(accessor.get(IServerTelemetryService), appInsightsAppender); @@ -184,7 +185,6 @@ export async function setupServerServices(connectionToken: ServerConnectionToken socketServer.registerChannel('request', new RequestChannel(accessor.get(IRequestService))); - const extensionManagementService = accessor.get(IExtensionManagementService); const channel = new ExtensionManagementChannel(extensionManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority)); socketServer.registerChannel('extensions', channel); diff --git a/src/vs/workbench/services/extensions/common/extensionPoints.ts b/src/vs/workbench/services/extensions/common/extensionPoints.ts index 9f68b72e82350..aa12d75a7571a 100644 --- a/src/vs/workbench/services/extensions/common/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/common/extensionPoints.ts @@ -12,7 +12,7 @@ import * as arrays from 'vs/base/common/arrays'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; -import { getGalleryExtensionId, groupByExtension, getExtensionId, ExtensionKey } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionId, getExtensionId, ExtensionKey } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isValidExtensionVersion } from 'vs/platform/extensions/common/extensionValidator'; import { ExtensionIdentifier, IExtensionDescription, IRelaxedExtensionDescription, TargetPlatform, UNDEFINED_PUBLISHER } from 'vs/platform/extensions/common/extensions'; import { Metadata } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -517,6 +517,7 @@ export class ExtensionScannerInput { public readonly absoluteFolderPath: string, public readonly isBuiltin: boolean, public readonly isUnderDevelopment: boolean, + public readonly targetPlatform: TargetPlatform, public readonly translations: Translations ) { // Keep empty!! (JSON.parse) @@ -643,9 +644,7 @@ export class ExtensionScanner { extensionDescriptions = extensionDescriptions.filter(item => item !== null && !obsolete[new ExtensionKey({ id: getGalleryExtensionId(item.publisher, item.name) }, item.version, item.targetPlatform).toString()]); if (!isBuiltin) { - // Filter out outdated extensions - const byExtension: IExtensionDescription[][] = groupByExtension(extensionDescriptions, e => ({ id: e.identifier.value, uuid: e.uuid })); - extensionDescriptions = byExtension.map(p => p.sort((a, b) => semver.rcompare(a.version, b.version))[0]); + extensionDescriptions = this.filterOutdatedExtensions(extensionDescriptions, input.targetPlatform); } extensionDescriptions.sort((a, b) => { @@ -721,4 +720,22 @@ export class ExtensionScanner { return resultArr; }); } + + private static filterOutdatedExtensions(extensions: IExtensionDescription[], targetPlatform: TargetPlatform): IExtensionDescription[] { + const result = new Map(); + for (const extension of extensions) { + const extensionKey = extension.identifier.value; + const existing = result.get(extensionKey); + if (existing) { + if (semver.gt(existing.version, extension.version)) { + continue; + } + if (semver.eq(existing.version, extension.version) && existing.targetPlatform === targetPlatform) { + continue; + } + } + result.set(extensionKey, extension); + } + return [...result.values()]; + } } diff --git a/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts index 6d55c713a8b30..9bd64f4b1a77d 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner.ts @@ -20,6 +20,7 @@ import { Translations, ILog, ExtensionScanner, ExtensionScannerInput, IExtension import { dedupExtensions } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { FileOperationResult, IFileService, toFileOperationResult } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; interface IExtensionCacheData { input: ExtensionScannerInput; @@ -54,7 +55,8 @@ export class CachedExtensionScanner { @INativeWorkbenchEnvironmentService private readonly _environmentService: INativeWorkbenchEnvironmentService, @IHostService private readonly _hostService: IHostService, @IProductService private readonly _productService: IProductService, - @IFileService private readonly _fileService: IFileService + @IFileService private readonly _fileService: IFileService, + @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService ) { this.scannedExtensions = new Promise((resolve, reject) => { this._scannedExtensionsResolve = resolve; @@ -108,7 +110,8 @@ export class CachedExtensionScanner { const date = this._productService.date; const devMode = !this._environmentService.isBuilt; const locale = platform.language; - const input = new ExtensionScannerInput(version, date, commit, locale, devMode, path, isBuiltin, false, translations); + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); + const input = new ExtensionScannerInput(version, date, commit, locale, devMode, path, isBuiltin, false, targetPlatform, translations); return ExtensionScanner.scanSingleExtension(input, this._createExtensionScannerHost(log)); } @@ -247,7 +250,7 @@ export class CachedExtensionScanner { return Object.create(null); } - private _scanInstalledExtensions( + private async _scanInstalledExtensions( log: ILog, translations: Translations ): Promise<{ system: IExtensionDescription[]; user: IExtensionDescription[]; development: IExtensionDescription[] }> { @@ -257,10 +260,11 @@ export class CachedExtensionScanner { const date = this._productService.date; const devMode = !this._environmentService.isBuilt; const locale = platform.language; + const targetPlatform = await this._extensionManagementService.getTargetPlatform(); const builtinExtensions = this._scanExtensionsWithCache( BUILTIN_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, date, commit, locale, devMode, getSystemExtensionsRoot(), true, false, translations), + new ExtensionScannerInput(version, date, commit, locale, devMode, getSystemExtensionsRoot(), true, false, targetPlatform, translations), log ); @@ -273,7 +277,7 @@ export class CachedExtensionScanner { const controlFile = this._fileService.readFile(URI.file(controlFilePath)) .then(raw => JSON.parse(raw.value.toString()), () => ({} as any)); - const input = new ExtensionScannerInput(version, date, commit, locale, devMode, getExtraDevSystemExtensionsRoot(), true, false, translations); + const input = new ExtensionScannerInput(version, date, commit, locale, devMode, getExtraDevSystemExtensionsRoot(), true, false, targetPlatform, translations); const extraBuiltinExtensions = Promise.all([builtInExtensions, controlFile]) .then(([builtInExtensions, control]) => new ExtraBuiltInExtensionResolver(builtInExtensions, control)) .then(resolver => ExtensionScanner.scanExtensions(input, this._createExtensionScannerHost(log), resolver)); @@ -283,7 +287,7 @@ export class CachedExtensionScanner { const userExtensions = (this._scanExtensionsWithCache( USER_MANIFEST_CACHE_FILE, - new ExtensionScannerInput(version, date, commit, locale, devMode, this._environmentService.extensionsPath, false, false, translations), + new ExtensionScannerInput(version, date, commit, locale, devMode, this._environmentService.extensionsPath, false, false, targetPlatform, translations), log )); @@ -292,7 +296,7 @@ export class CachedExtensionScanner { if (this._environmentService.isExtensionDevelopment && this._environmentService.extensionDevelopmentLocationURI) { const extDescsP = this._environmentService.extensionDevelopmentLocationURI.filter(extLoc => extLoc.scheme === Schemas.file).map(extLoc => { return ExtensionScanner.scanOneOrMultipleExtensions( - new ExtensionScannerInput(version, date, commit, locale, devMode, originalFSPath(extLoc), false, true, translations), + new ExtensionScannerInput(version, date, commit, locale, devMode, originalFSPath(extLoc), false, true, targetPlatform, translations), this._createExtensionScannerHost(log) ); });