#15756 prompt users to migrate from old extension to main prerelease extension
This commit is contained in:
parent
4aad18d229
commit
503a9bcd16
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
import { canceled, getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
|
import { canceled, getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||||
import { getOrDefault } from 'vs/base/common/objects';
|
import { getOrDefault } from 'vs/base/common/objects';
|
||||||
import { IPager } from 'vs/base/common/paging';
|
import { IPager } from 'vs/base/common/paging';
|
||||||
|
@ -440,7 +441,7 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
|
||||||
|
|
||||||
interface IRawExtensionsControlManifest {
|
interface IRawExtensionsControlManifest {
|
||||||
malicious: string[];
|
malicious: string[];
|
||||||
slow: string[];
|
unsupported: IStringDictionary<boolean | { preReleaseExtension: { id: string, displayName: string } }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractExtensionGalleryService implements IExtensionGalleryService {
|
abstract class AbstractExtensionGalleryService implements IExtensionGalleryService {
|
||||||
|
@ -958,14 +959,23 @@ abstract class AbstractExtensionGalleryService implements IExtensionGalleryServi
|
||||||
|
|
||||||
const result = await asJson<IRawExtensionsControlManifest>(context);
|
const result = await asJson<IRawExtensionsControlManifest>(context);
|
||||||
const malicious: IExtensionIdentifier[] = [];
|
const malicious: IExtensionIdentifier[] = [];
|
||||||
|
const unsupportedPreReleaseExtensions: IStringDictionary<{ id: string, displayName: string }> = {};
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
for (const id of result.malicious) {
|
for (const id of result.malicious) {
|
||||||
malicious.push({ id });
|
malicious.push({ id });
|
||||||
}
|
}
|
||||||
|
if (result.unsupported) {
|
||||||
|
for (const extensionId of Object.keys(result.unsupported)) {
|
||||||
|
const value = result.unsupported[extensionId];
|
||||||
|
if (!isBoolean(value)) {
|
||||||
|
unsupportedPreReleaseExtensions[extensionId.toLowerCase()] = value.preReleaseExtension;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { malicious };
|
return { malicious, unsupportedPreReleaseExtensions };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { IStringDictionary } from 'vs/base/common/collections';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { FileAccess } from 'vs/base/common/network';
|
import { FileAccess } from 'vs/base/common/network';
|
||||||
import { IPager } from 'vs/base/common/paging';
|
import { IPager } from 'vs/base/common/paging';
|
||||||
|
@ -312,6 +313,7 @@ export const enum StatisticType {
|
||||||
|
|
||||||
export interface IExtensionsControlManifest {
|
export interface IExtensionsControlManifest {
|
||||||
malicious: IExtensionIdentifier[];
|
malicious: IExtensionIdentifier[];
|
||||||
|
unsupportedPreReleaseExtensions?: IStringDictionary<{ id: string, displayName: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum InstallOperation {
|
export const enum InstallOperation {
|
||||||
|
|
|
@ -74,6 +74,7 @@ import { ExtensionsCompletionItemsProvider } from 'vs/workbench/contrib/extensio
|
||||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||||
|
import { UnsupportedPreReleaseExtensionsChecker } from 'vs/workbench/contrib/extensions/browser/unsupportedPreReleaseExtensionsChecker';
|
||||||
|
|
||||||
// Singletons
|
// Singletons
|
||||||
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
|
||||||
|
@ -1461,6 +1462,7 @@ const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(Workbench
|
||||||
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
|
||||||
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
|
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
|
||||||
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
|
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
|
||||||
|
workbenchRegistry.registerWorkbenchContribution(UnsupportedPreReleaseExtensionsChecker, LifecyclePhase.Eventually);
|
||||||
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
|
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
|
||||||
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting);
|
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting);
|
||||||
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);
|
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||||
import { dispose } from 'vs/base/common/lifecycle';
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, IExtensionContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewPaneContainer, IExtensionContainer, TOGGLE_IGNORE_EXTENSION_ACTION_ID, SELECT_INSTALL_VSIX_EXTENSION_COMMAND_ID } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
|
||||||
import { IGalleryExtension, IExtensionGalleryService, ILocalExtension, InstallOptions, InstallOperation, TargetPlatformToString, ExtensionManagementErrorCode } from 'vs/platform/extensionManagement/common/extensionManagement';
|
import { IGalleryExtension, IExtensionGalleryService, ILocalExtension, InstallOptions, InstallOperation, TargetPlatformToString, ExtensionManagementErrorCode, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||||
import { ExtensionRecommendationReason, IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
import { ExtensionRecommendationReason, IExtensionIgnoredRecommendationsService, IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
|
||||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
|
@ -1125,6 +1125,40 @@ export class SwitchToReleasedVersionAction extends ExtensionAction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SwitchUnsupportedExtensionToPreReleaseExtensionAction extends Action {
|
||||||
|
|
||||||
|
private static readonly Class = `${ExtensionAction.LABEL_ACTION_CLASS} hide-when-disabled`;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly local: ILocalExtension,
|
||||||
|
private readonly gallery: IGalleryExtension,
|
||||||
|
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||||
|
@IProductService private readonly productService: IProductService,
|
||||||
|
@IHostService private readonly hostService: IHostService,
|
||||||
|
@IWorkbenchExtensionEnablementService private readonly workbenchExtensionEnablementService: IWorkbenchExtensionEnablementService,
|
||||||
|
@INotificationService private readonly notificationService: INotificationService,
|
||||||
|
) {
|
||||||
|
super('workbench.extensions.action.switchUnsupportedExtensionToPreReleaseExtension', localize('switchUnsupportedExtensionToPreReleaseExtension', "Switch to '{0}' Pre-Release version", gallery.displayName), SwitchUnsupportedExtensionToPreReleaseExtensionAction.Class);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async run(): Promise<any> {
|
||||||
|
await Promise.all([
|
||||||
|
this.extensionManagementService.uninstall(this.local),
|
||||||
|
this.extensionManagementService.installFromGallery(this.gallery, { installPreReleaseVersion: true, isMachineScoped: this.local.isMachineScoped })
|
||||||
|
.then(local => this.workbenchExtensionEnablementService.setEnablement([this.local], EnablementState.EnabledGlobally)),
|
||||||
|
]);
|
||||||
|
this.notificationService.prompt(
|
||||||
|
Severity.Info,
|
||||||
|
localize('SwitchToAnotherReleaseExtension.successReload', "Please reload {0} to complete switching to the '{1}' extension.", this.productService.nameLong, this.gallery.displayName),
|
||||||
|
[{
|
||||||
|
label: localize('reloadNow', "Reload Now"),
|
||||||
|
run: () => this.hostService.reload()
|
||||||
|
}],
|
||||||
|
{ sticky: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class InstallAnotherVersionAction extends ExtensionAction {
|
export class InstallAnotherVersionAction extends ExtensionAction {
|
||||||
|
|
||||||
static readonly ID = 'workbench.extensions.action.install.anotherVersion';
|
static readonly ID = 'workbench.extensions.action.install.anotherVersion';
|
||||||
|
|
|
@ -14,10 +14,10 @@ import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import {
|
import {
|
||||||
IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions,
|
IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions,
|
||||||
InstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier, InstallOperation, DefaultIconPath, InstallOptions, WEB_EXTENSION_TAG, InstallExtensionResult, isIExtensionIdentifier
|
InstallExtensionEvent, DidUninstallExtensionEvent, IExtensionIdentifier, InstallOperation, DefaultIconPath, InstallOptions, WEB_EXTENSION_TAG, InstallExtensionResult, isIExtensionIdentifier, IExtensionsControlManifest
|
||||||
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
} from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||||
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, groupByExtension, ExtensionIdentifierWithVersion, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||||
|
@ -418,28 +418,32 @@ class Extensions extends Disposable {
|
||||||
return this.local;
|
return this.local;
|
||||||
}
|
}
|
||||||
|
|
||||||
async syncLocalWithGalleryExtension(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): Promise<boolean> {
|
async syncLocalWithGalleryExtension(gallery: IGalleryExtension, extensionsControlManifest: IExtensionsControlManifest): Promise<boolean> {
|
||||||
const extension = this.getInstalledExtensionMatchingGallery(gallery);
|
const extension = this.getInstalledExtensionMatchingGallery(gallery);
|
||||||
if (!extension) {
|
if (!extension?.local) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (maliciousExtensionSet.has(extension.identifier.id)) {
|
|
||||||
extension.isMalicious = true;
|
let hasChanged: boolean = false;
|
||||||
|
|
||||||
|
const isMalicious = extensionsControlManifest.malicious.some(identifier => areSameExtensions(extension.identifier, identifier));
|
||||||
|
if (extension.isMalicious !== isMalicious) {
|
||||||
|
extension.isMalicious = isMalicious;
|
||||||
|
hasChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compatible = await this.getCompatibleExtension(gallery, !!extension.local?.isPreReleaseVersion);
|
const compatible = await this.getCompatibleExtension(gallery, !!extension.local?.isPreReleaseVersion);
|
||||||
if (!compatible) {
|
if (compatible) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Sync the local extension with gallery extension if local extension doesnot has metadata
|
|
||||||
if (extension.local) {
|
|
||||||
const local = extension.local.identifier.uuid ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId });
|
const local = extension.local.identifier.uuid ? extension.local : await this.server.extensionManagementService.updateMetadata(extension.local, { id: compatible.identifier.uuid, publisherDisplayName: compatible.publisherDisplayName, publisherId: compatible.publisherId });
|
||||||
extension.local = local;
|
extension.local = local;
|
||||||
extension.gallery = compatible;
|
extension.gallery = compatible;
|
||||||
this._onChange.fire({ extension });
|
hasChanged = true;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
if (hasChanged) {
|
||||||
|
this._onChange.fire({ extension });
|
||||||
|
}
|
||||||
|
return hasChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getCompatibleExtension(extensionOrIdentifier: IGalleryExtension | IExtensionIdentifier, includePreRelease: boolean): Promise<IGalleryExtension | null> {
|
private async getCompatibleExtension(extensionOrIdentifier: IGalleryExtension | IExtensionIdentifier, includePreRelease: boolean): Promise<IGalleryExtension | null> {
|
||||||
|
@ -749,11 +753,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
options.text = options.text ? this.resolveQueryText(options.text) : options.text;
|
options.text = options.text ? this.resolveQueryText(options.text) : options.text;
|
||||||
options.includePreRelease = isUndefined(options.includePreRelease) ? this.preferPreReleases : options.includePreRelease;
|
options.includePreRelease = isUndefined(options.includePreRelease) ? this.preferPreReleases : options.includePreRelease;
|
||||||
|
|
||||||
const report = await this.extensionManagementService.getExtensionsControlManifest();
|
const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest();
|
||||||
const maliciousSet = getMaliciousExtensionsSet(report);
|
|
||||||
try {
|
try {
|
||||||
const result = await this.galleryService.query(options, token);
|
const result = await this.galleryService.query(options, token);
|
||||||
return mapPager(result, gallery => this.fromGallery(gallery, maliciousSet));
|
return mapPager(result, gallery => this.fromGallery(gallery, extensionsControlManifest));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (/No extension gallery service configured/.test(error.message)) {
|
if (/No extension gallery service configured/.test(error.message)) {
|
||||||
return Promise.resolve(singlePagePager([]));
|
return Promise.resolve(singlePagePager([]));
|
||||||
|
@ -890,11 +893,11 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
return extension || extensions[0];
|
return extension || extensions[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private fromGallery(gallery: IGalleryExtension, maliciousExtensionSet: Set<string>): IExtension {
|
private fromGallery(gallery: IGalleryExtension, extensionsControlManifest: IExtensionsControlManifest): IExtension {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
this.localExtensions ? this.localExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false),
|
this.localExtensions ? this.localExtensions.syncLocalWithGalleryExtension(gallery, extensionsControlManifest) : Promise.resolve(false),
|
||||||
this.remoteExtensions ? this.remoteExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false),
|
this.remoteExtensions ? this.remoteExtensions.syncLocalWithGalleryExtension(gallery, extensionsControlManifest) : Promise.resolve(false),
|
||||||
this.webExtensions ? this.webExtensions.syncLocalWithGalleryExtension(gallery, maliciousExtensionSet) : Promise.resolve(false)
|
this.webExtensions ? this.webExtensions.syncLocalWithGalleryExtension(gallery, extensionsControlManifest) : Promise.resolve(false)
|
||||||
])
|
])
|
||||||
.then(result => {
|
.then(result => {
|
||||||
if (result[0] || result[1] || result[2]) {
|
if (result[0] || result[1] || result[2]) {
|
||||||
|
@ -907,7 +910,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
||||||
return installed;
|
return installed;
|
||||||
}
|
}
|
||||||
const extension = this.instantiationService.createInstance(Extension, ext => this.getExtensionState(ext), undefined, undefined, gallery);
|
const extension = this.instantiationService.createInstance(Extension, ext => this.getExtensionState(ext), undefined, undefined, gallery);
|
||||||
if (maliciousExtensionSet.has(extension.identifier.id)) {
|
if (extensionsControlManifest.malicious.some(identifier => areSameExtensions(extension.identifier, identifier))) {
|
||||||
extension.isMalicious = true;
|
extension.isMalicious = true;
|
||||||
}
|
}
|
||||||
return extension;
|
return extension;
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { IExtensionGalleryService, IExtensionManagementService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
|
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||||
|
import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||||
|
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||||
|
import { SwitchUnsupportedExtensionToPreReleaseExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
|
|
||||||
|
export class UnsupportedPreReleaseExtensionsChecker implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@INotificationService private readonly notificationService: INotificationService,
|
||||||
|
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||||
|
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||||
|
) {
|
||||||
|
this.notifyUnsupportedPreReleaseExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async notifyUnsupportedPreReleaseExtensions(): Promise<void> {
|
||||||
|
const extensionsControlManifest = await this.extensionManagementService.getExtensionsControlManifest();
|
||||||
|
if (!extensionsControlManifest.unsupportedPreReleaseExtensions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const installed = await this.extensionManagementService.getInstalled(ExtensionType.User);
|
||||||
|
const unsupportedLocalExtensionsWithIdentifiers: [ILocalExtension, IExtensionIdentifier][] = [];
|
||||||
|
for (const extension of installed) {
|
||||||
|
const preReleaseExtension = extensionsControlManifest.unsupportedPreReleaseExtensions[extension.identifier.id.toLowerCase()];
|
||||||
|
if (preReleaseExtension) {
|
||||||
|
unsupportedLocalExtensionsWithIdentifiers.push([extension, { id: preReleaseExtension.id }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!unsupportedLocalExtensionsWithIdentifiers.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsupportedPreReleaseExtensions: [ILocalExtension, IGalleryExtension][] = [];
|
||||||
|
const galleryExensions = await this.extensionGalleryService.getExtensions(unsupportedLocalExtensionsWithIdentifiers.map(([, identifier]) => identifier), true, CancellationToken.None);
|
||||||
|
for (const gallery of galleryExensions) {
|
||||||
|
const unsupportedLocalExtension = unsupportedLocalExtensionsWithIdentifiers.find(([, identifier]) => areSameExtensions(identifier, gallery.identifier));
|
||||||
|
if (unsupportedLocalExtension) {
|
||||||
|
unsupportedPreReleaseExtensions.push([unsupportedLocalExtension[0], gallery]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!unsupportedPreReleaseExtensions.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unsupportedPreReleaseExtensions.length === 1) {
|
||||||
|
const [local, gallery] = unsupportedPreReleaseExtensions[0];
|
||||||
|
const action = this.instantiationService.createInstance(SwitchUnsupportedExtensionToPreReleaseExtensionAction, unsupportedPreReleaseExtensions[0][0], unsupportedPreReleaseExtensions[0][1]);
|
||||||
|
this.notificationService.notify({
|
||||||
|
severity: Severity.Info,
|
||||||
|
message: localize('unsupported prerelease message', "'{0}' extension is now part of the '{1}' extension as a pre-release version and it is no longer supported. Would you like to switch to '{2}' extension?", local.manifest.displayName || local.identifier.id, gallery.displayName, gallery.displayName),
|
||||||
|
actions: {
|
||||||
|
primary: [action]
|
||||||
|
},
|
||||||
|
sticky: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue