Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider outdated targetplatform while loading extensions #145293

Merged
merged 1 commit into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions src/vs/server/node/remoteAgentEnvironmentImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -389,10 +390,9 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel {
return r;
}

private _scanDevelopedExtensions(language: string, translations: Translations, extensionDevelopmentPaths?: string[]): Promise<IExtensionDescription[]> {

private async _scanDevelopedExtensions(language: string, translations: Translations, extensionDevelopmentPaths?: string[]): Promise<IExtensionDescription[]> {
if (extensionDevelopmentPaths) {

const targetPlatform = await this._extensionManagementService.getTargetPlatform();
const extDescsP = extensionDevelopmentPaths.map(extDevPath => {
return ExtensionScanner.scanOneOrMultipleExtensions(
new ExtensionScannerInput(
Expand All @@ -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<IExtensionDescription[]> {
private async _scanBuiltinExtensions(language: string, translations: Translations): Promise<IExtensionDescription[]> {
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<IExtensionDescription[]> = builtinExtensions;

Expand All @@ -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));
Expand All @@ -455,7 +456,8 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel {
return finalBuiltinExtensions;
}

private _scanInstalledExtensions(language: string, translations: Translations): Promise<IExtensionDescription[]> {
private async _scanInstalledExtensions(language: string, translations: Translations): Promise<IExtensionDescription[]> {
const targetPlatform = await this._extensionManagementService.getTargetPlatform();
const devMode = !!process.env['VSCODE_DEV'];
const input = new ExtensionScannerInput(
this.productService.version,
Expand All @@ -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<IExtensionDescription | null> {
private async _scanSingleExtension(extensionPath: string, isBuiltin: boolean, language: string, translations: Translations): Promise<IExtensionDescription | null> {
const targetPlatform = await this._extensionManagementService.getTargetPlatform();
const devMode = !!process.env['VSCODE_DEV'];
const input = new ExtensionScannerInput(
this.productService.version,
Expand All @@ -483,6 +487,7 @@ export class RemoteAgentEnvironmentChannel implements IServerChannel {
extensionPath,
isBuiltin,
false, // isUnderDevelopment
targetPlatform,
translations
);
return ExtensionScanner.scanSingleExtension(input, this._extensionScannerHost);
Expand Down
4 changes: 2 additions & 2 deletions src/vs/server/node/serverServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);

Expand Down
25 changes: 21 additions & 4 deletions src/vs/workbench/services/extensions/common/extensionPoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -517,6 +517,7 @@ export class ExtensionScannerInput {
public readonly absoluteFolderPath: string,
public readonly isBuiltin: boolean,
public readonly isUnderDevelopment: boolean,
public readonly targetPlatform: TargetPlatform,
sandy081 marked this conversation as resolved.
Show resolved Hide resolved
public readonly translations: Translations
) {
// Keep empty!! (JSON.parse)
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -721,4 +720,22 @@ export class ExtensionScanner {
return resultArr;
});
}

private static filterOutdatedExtensions(extensions: IExtensionDescription[], targetPlatform: TargetPlatform): IExtensionDescription[] {
const result = new Map<string, IExtensionDescription>();
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()];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<IExtensionDescription[]>((resolve, reject) => {
this._scannedExtensionsResolve = resolve;
Expand Down Expand Up @@ -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));
}

Expand Down Expand Up @@ -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[] }> {
Expand All @@ -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
);

Expand All @@ -273,7 +277,7 @@ export class CachedExtensionScanner {
const controlFile = this._fileService.readFile(URI.file(controlFilePath))
.then<IBuiltInExtensionControl>(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));
Expand All @@ -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
));

Expand All @@ -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)
);
});
Expand Down