Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSandeep Somavarapu <sasomava@microsoft.com>2022-06-26 01:06:27 +0300
committerSandeep Somavarapu <sasomava@microsoft.com>2022-06-26 01:06:27 +0300
commit94459e758e229b13d882cc8298ad98c67586a52f (patch)
tree9e35a1ef15d68e2e77e3540a6d13a7487ac70538 /src
parentd1b4630a508ffd3bd6aab7a077dbfd0fdbadb1ba (diff)
Improve extensions management in profiles
- Make version property mandatory in extension profiles (like in web) - Extend extensions clean up to profiles - Add necessay changes in other services to support extension cleanup: - Introduce INativeServerExtensionManagementService - Extend profile change event to provide added and removed profiles
Diffstat (limited to 'src')
-rw-r--r--src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts144
-rw-r--r--src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts4
-rw-r--r--src/vs/code/node/cliProcessMain.ts6
-rw-r--r--src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts52
-rw-r--r--src/vs/platform/extensionManagement/common/extensionManagement.ts7
-rw-r--r--src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts61
-rw-r--r--src/vs/platform/extensionManagement/node/extensionManagementService.ts34
-rw-r--r--src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts5
-rw-r--r--src/vs/platform/userDataProfile/common/userDataProfile.ts6
-rw-r--r--src/vs/platform/userDataProfile/electron-main/userDataProfile.ts8
-rw-r--r--src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts10
-rw-r--r--src/vs/server/node/remoteExtensionHostAgentCli.ts6
-rw-r--r--src/vs/server/node/serverServices.ts10
-rw-r--r--src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts15
-rw-r--r--src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts19
-rw-r--r--src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts8
16 files changed, 301 insertions, 94 deletions
diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts
index a7ebe66abca..3ac907be458 100644
--- a/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts
+++ b/src/vs/code/electron-browser/sharedProcess/contrib/extensionsCleaner.ts
@@ -4,26 +4,162 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
-import { IExtensionGalleryService, IGlobalExtensionEnablementService, IServerExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { URI } from 'vs/base/common/uri';
+import { IExtensionGalleryService, IExtensionIdentifier, IGlobalExtensionEnablementService, ServerDidUninstallExtensionEvent, ServerInstallExtensionResult, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
import { ExtensionStorageService, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
import { migrateUnsupportedExtensions } from 'vs/platform/extensionManagement/common/unsupportedExtensionsMigration';
-import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
+import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IStorageService } from 'vs/platform/storage/common/storage';
+import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
+import { DidChangeProfilesEvent, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
+
+const uninstalOptions: UninstallOptions = { versionOnly: true, donotIncludePack: true, donotCheckDependents: true };
export class ExtensionsCleaner extends Disposable {
constructor(
- @IServerExtensionManagementService extensionManagementService: ExtensionManagementService,
+ @INativeServerExtensionManagementService extensionManagementService: INativeServerExtensionManagementService,
+ @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
@IExtensionStorageService extensionStorageService: IExtensionStorageService,
@IGlobalExtensionEnablementService extensionEnablementService: IGlobalExtensionEnablementService,
+ @IInstantiationService instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService,
@ILogService logService: ILogService,
) {
super();
- extensionManagementService.removeDeprecatedExtensions();
+
+ extensionManagementService.removeUninstalledExtensions(this.userDataProfilesService.profiles.length > 1);
migrateUnsupportedExtensions(extensionManagementService, extensionGalleryService, extensionStorageService, extensionEnablementService, logService);
ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService);
+ this._register(instantiationService.createInstance(ProfileExtensionsCleaner));
}
+
+}
+
+class ProfileExtensionsCleaner extends Disposable {
+
+ private profileExtensionsLocations = new Map<string, URI[]>;
+ private readonly initPromise: Promise<boolean>;
+
+ constructor(
+ @INativeServerExtensionManagementService private readonly extensionManagementService: INativeServerExtensionManagementService,
+ @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
+ @IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
+ @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
+ @ILogService private readonly logService: ILogService,
+ ) {
+ super();
+
+ this.initPromise = this.initialize();
+ this._register(this.userDataProfilesService.onDidChangeProfiles(e => this.onDidChangeProfiles(e)));
+ this._register(this.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e)));
+ this._register(this.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e)));
+ }
+
+ private async initialize(): Promise<boolean> {
+ if (this.userDataProfilesService.profiles.length === 1) {
+ return true;
+ }
+ try {
+ const installed = await this.extensionManagementService.getAllUserInstalled();
+ await Promise.all(this.userDataProfilesService.profiles.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve()));
+ const toUninstall = installed.filter(installedExtension => !this.profileExtensionsLocations.has(this.getKey(installedExtension.identifier, installedExtension.manifest.version)));
+ if (toUninstall.length) {
+ await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions)));
+ }
+ return true;
+ } catch (error) {
+ this.logService.error('ExtensionsCleaner: Failed to initialize');
+ this.logService.error(error);
+ return false;
+ }
+ }
+
+ private async onDidChangeProfiles({ added, removed }: DidChangeProfilesEvent): Promise<void> {
+ if (!(await this.initPromise)) {
+ return;
+ }
+ await Promise.all(added.map(profile => profile.extensionsResource ? this.populateExtensionsFromProfile(profile.extensionsResource) : Promise.resolve()));
+ await Promise.all(removed.map(profile => profile.extensionsResource ? this.removeExtensionsFromProfile(profile.extensionsResource) : Promise.resolve()));
+ }
+
+ private async onDidInstallExtensions(installedExtensions: readonly ServerInstallExtensionResult[]): Promise<void> {
+ if (!(await this.initPromise)) {
+ return;
+ }
+ for (const { local, profileLocation } of installedExtensions) {
+ if (!local || !profileLocation) {
+ continue;
+ }
+ this.addExtensionWithKey(this.getKey(local.identifier, local.manifest.version), profileLocation);
+ }
+ }
+
+ private async onDidUninstallExtension(e: ServerDidUninstallExtensionEvent): Promise<void> {
+ if (!e.profileLocation || !e.version) {
+ return;
+ }
+ if (!(await this.initPromise)) {
+ return;
+ }
+ if (this.removeExtensionWithKey(this.getKey(e.identifier, e.version), e.profileLocation)) {
+ await this.uninstallExtensions([{ identifier: e.identifier, version: e.version }]);
+ }
+ }
+
+ private async populateExtensionsFromProfile(extensionsProfileLocation: URI): Promise<void> {
+ const extensions = await this.extensionsProfileScannerService.scanProfileExtensions(extensionsProfileLocation);
+ for (const extension of extensions) {
+ this.addExtensionWithKey(this.getKey(extension.identifier, extension.version), extensionsProfileLocation);
+ }
+ }
+
+ private async removeExtensionsFromProfile(removedProfile: URI): Promise<void> {
+ const profileExtensions = await this.extensionsProfileScannerService.scanProfileExtensions(removedProfile);
+ const extensionsToRemove = profileExtensions.filter(profileExtension => this.removeExtensionWithKey(this.getKey(profileExtension.identifier, profileExtension.version), removedProfile));
+ if (extensionsToRemove.length) {
+ await this.uninstallExtensions(extensionsToRemove);
+ }
+ }
+
+ private addExtensionWithKey(key: string, extensionsProfileLocation: URI): void {
+ let locations = this.profileExtensionsLocations.get(key);
+ if (!locations) {
+ locations = [];
+ this.profileExtensionsLocations.set(key, locations);
+ }
+ locations.push(extensionsProfileLocation);
+ }
+
+ private removeExtensionWithKey(key: string, profileLocation: URI): boolean {
+ const profiles = this.profileExtensionsLocations.get(key);
+ if (profiles) {
+ const index = profiles.findIndex(profile => this.uriIdentityService.extUri.isEqual(profile, profileLocation));
+ if (index > -1) {
+ profiles.splice(index, 1);
+ }
+ }
+ if (!profiles?.length) {
+ this.profileExtensionsLocations.delete(key);
+ }
+ return !profiles?.length;
+ }
+
+ private async uninstallExtensions(extensionsToRemove: { identifier: IExtensionIdentifier; version: string }[]): Promise<void> {
+ const installed = await this.extensionManagementService.getAllUserInstalled();
+ const toUninstall = installed.filter(installedExtension => extensionsToRemove.some(e => this.getKey(installedExtension.identifier, installedExtension.manifest.version) === this.getKey(e.identifier, e.version)));
+ if (toUninstall.length) {
+ await Promise.all(toUninstall.map(extension => this.extensionManagementService.uninstall(extension, uninstalOptions)));
+ }
+ }
+
+ private getKey(identifier: IExtensionIdentifier, version: string): string {
+ return `${ExtensionIdentifier.toKey(identifier.id)}@${version}`;
+ }
+
}
diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
index 862a359dfd9..11116cc4cce 100644
--- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
+++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts
@@ -34,7 +34,7 @@ import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/
import { IExtensionGalleryService, IExtensionManagementService, IExtensionTipsService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementChannel, ExtensionTipsChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
import { ExtensionTipsService } from 'vs/platform/extensionManagement/electron-sandbox/extensionTipsService';
-import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { IExtensionRecommendationNotificationService } from 'vs/platform/extensionRecommendations/common/extensionRecommendations';
import { ExtensionRecommendationNotificationServiceChannelClient } from 'vs/platform/extensionRecommendations/electron-sandbox/extensionRecommendationsIpc';
import { IFileService } from 'vs/platform/files/common/files';
@@ -315,7 +315,7 @@ class SharedProcessMain extends Disposable {
// Extension Management
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService));
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService));
- services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
+ services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
// Extension Gallery
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts
index 6ffc074614c..56ee36e7f1b 100644
--- a/src/vs/code/node/cliProcessMain.ts
+++ b/src/vs/code/node/cliProcessMain.ts
@@ -23,11 +23,11 @@ import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { NativeEnvironmentService } from 'vs/platform/environment/node/environmentService';
import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
-import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IExtensionGalleryService, IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
import { IExtensionsScannerService } from 'vs/platform/extensionManagement/common/extensionsScannerService';
-import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService';
import { IFileService } from 'vs/platform/files/common/files';
import { FileService } from 'vs/platform/files/common/fileService';
@@ -178,7 +178,7 @@ class CliMain extends Disposable {
// Extensions
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService));
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService));
- services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
+ services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService));
services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService));
diff --git a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts
index 99d049079ed..c31a9e3c427 100644
--- a/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts
+++ b/src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts
@@ -14,7 +14,8 @@ import { URI } from 'vs/base/common/uri';
import * as nls from 'vs/nls';
import {
ExtensionManagementError, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementParticipant, IGalleryExtension, IGalleryMetadata, ILocalExtension, InstallOperation,
- IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode, IServerExtensionManagementService, ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions, Metadata, ServerInstallExtensionEvent, ServerInstallExtensionResult, ServerUninstallExtensionEvent, ServerDidUninstallExtensionEvent
+ IExtensionsControlManifest, StatisticType, isTargetPlatformCompatible, TargetPlatformToString, ExtensionManagementErrorCode, IServerExtensionManagementService,
+ ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions, Metadata, ServerInstallExtensionEvent, ServerInstallExtensionResult, ServerUninstallExtensionEvent, ServerDidUninstallExtensionEvent
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, ExtensionKey, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
@@ -34,8 +35,6 @@ export interface IInstallExtensionTask {
cancel(): void;
}
-export type UninstallExtensionTaskOptions = { readonly remove?: boolean; readonly versionOnly?: boolean };
-
export interface IUninstallExtensionTask {
readonly extension: ILocalExtension;
run(): Promise<void>;
@@ -426,47 +425,58 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
}
private async unininstallExtension(extension: ILocalExtension, options: ServerUninstallOptions): Promise<void> {
- if (!options.profileLocation) {
- const uninstallExtensionTask = this.uninstallingExtensions.get(extension.identifier.id.toLowerCase());
- if (uninstallExtensionTask) {
- this.logService.info('Extensions is already requested to uninstall', extension.identifier.id);
- return uninstallExtensionTask.waitUntilTaskIsFinished();
- }
+ const getUninstallExtensionTaskKey = (identifier: IExtensionIdentifier) => `${identifier.id.toLowerCase()}${options.profileLocation ? `@${options.profileLocation.toString()}` : ''}`;
+ const uninstallExtensionTask = this.uninstallingExtensions.get(getUninstallExtensionTaskKey(extension.identifier));
+ if (uninstallExtensionTask) {
+ this.logService.info('Extensions is already requested to uninstall', extension.identifier.id);
+ return uninstallExtensionTask.waitUntilTaskIsFinished();
}
- const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: UninstallExtensionTaskOptions): IUninstallExtensionTask => {
+ const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: ServerUninstallOptions): IUninstallExtensionTask => {
const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions, options.profileLocation);
- this.uninstallingExtensions.set(uninstallExtensionTask.extension.identifier.id.toLowerCase(), uninstallExtensionTask);
- this.logService.info('Uninstalling extension:', extension.identifier.id);
+ this.uninstallingExtensions.set(getUninstallExtensionTaskKey(uninstallExtensionTask.extension.identifier), uninstallExtensionTask);
+ if (options.profileLocation) {
+ this.logService.info('Uninstalling extension from the profile:', extension.identifier.id, options.profileLocation.toString());
+ } else {
+ this.logService.info('Uninstalling extension:', extension.identifier.id);
+ }
this._onUninstallExtension.fire({ identifier: extension.identifier, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped });
return uninstallExtensionTask;
};
const postUninstallExtension = (extension: ILocalExtension, error?: ExtensionManagementError): void => {
if (error) {
- this.logService.error('Failed to uninstall extension:', extension.identifier.id, error.message);
+ if (options.profileLocation) {
+ this.logService.error('Failed to uninstall extension from the profile:', extension.identifier.id, options.profileLocation.toString(), error.message);
+ } else {
+ this.logService.error('Failed to uninstall extension:', extension.identifier.id, error.message);
+ }
} else {
- this.logService.info('Successfully uninstalled extension:', extension.identifier.id);
+ if (options.profileLocation) {
+ this.logService.info('Successfully uninstalled extension from the profile', extension.identifier.id, options.profileLocation.toString());
+ } else {
+ this.logService.info('Successfully uninstalled extension:', extension.identifier.id);
+ }
}
reportTelemetry(this.telemetryService, 'extensionGallery:uninstall', { extensionData: getLocalExtensionTelemetryData(extension), error });
- this._onDidUninstallExtension.fire({ identifier: extension.identifier, error: error?.code, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped });
+ this._onDidUninstallExtension.fire({ identifier: extension.identifier, version: extension.manifest.version, error: error?.code, profileLocation: options.profileLocation, applicationScoped: extension.isApplicationScoped });
};
const allTasks: IUninstallExtensionTask[] = [];
const processedTasks: IUninstallExtensionTask[] = [];
try {
- allTasks.push(createUninstallExtensionTask(extension, {}));
+ allTasks.push(createUninstallExtensionTask(extension, options));
const installed = await this.getInstalled(ExtensionType.User, options.profileLocation);
if (options.donotIncludePack) {
this.logService.info('Uninstalling the extension without including packed extension', extension.identifier.id);
} else {
const packedExtensions = this.getAllPackExtensionsToUninstall(extension, installed);
for (const packedExtension of packedExtensions) {
- if (this.uninstallingExtensions.has(packedExtension.identifier.id.toLowerCase())) {
+ if (this.uninstallingExtensions.has(getUninstallExtensionTaskKey(packedExtension.identifier))) {
this.logService.info('Extensions is already requested to uninstall', packedExtension.identifier.id);
} else {
- allTasks.push(createUninstallExtensionTask(packedExtension, {}));
+ allTasks.push(createUninstallExtensionTask(packedExtension, options));
}
}
}
@@ -511,7 +521,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
} finally {
// Remove tasks from cache
for (const task of allTasks) {
- if (!this.uninstallingExtensions.delete(task.extension.identifier.id.toLowerCase())) {
+ if (!this.uninstallingExtensions.delete(getUninstallExtensionTaskKey(task.extension.identifier))) {
this.logService.warn('Uninstallation task is not found in the cache', task.extension.identifier.id);
}
}
@@ -607,7 +617,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
return new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService);
}
- private createUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions, profile?: URI): IUninstallExtensionTask {
+ private createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions, profile?: URI): IUninstallExtensionTask {
return profile && this.userDataProfilesService.defaultProfile.extensionsResource ? new UninstallExtensionFromProfileTask(extension, profile, this.userDataProfilesService, this.extensionsProfileScannerService) : this.createDefaultUninstallExtensionTask(extension, options);
}
@@ -623,7 +633,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
abstract updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension>;
protected abstract createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask;
- protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask;
+ protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask;
}
export function joinErrors(errorOrErrors: (Error | string) | (Array<Error | string>)): Error {
diff --git a/src/vs/platform/extensionManagement/common/extensionManagement.ts b/src/vs/platform/extensionManagement/common/extensionManagement.ts
index 4e376a1a4c8..3c5ec520512 100644
--- a/src/vs/platform/extensionManagement/common/extensionManagement.ts
+++ b/src/vs/platform/extensionManagement/common/extensionManagement.ts
@@ -361,8 +361,9 @@ export interface UninstallExtensionEvent {
}
export interface DidUninstallExtensionEvent {
- identifier: IExtensionIdentifier;
- error?: string;
+ readonly identifier: IExtensionIdentifier;
+ readonly version?: string;
+ readonly error?: string;
}
export enum ExtensionManagementErrorCode {
@@ -403,7 +404,7 @@ export type InstallOptions = {
context?: IStringDictionary<any>;
};
export type InstallVSIXOptions = Omit<InstallOptions, 'installGivenVersion'> & { installOnlyNewlyAddedFromExtensionPack?: boolean };
-export type UninstallOptions = { donotIncludePack?: boolean; donotCheckDependents?: boolean };
+export type UninstallOptions = { readonly donotIncludePack?: boolean; readonly donotCheckDependents?: boolean; readonly versionOnly?: boolean; readonly remove?: boolean };
export interface IExtensionManagementParticipant {
postInstall(local: ILocalExtension, source: URI | IGalleryExtension, options: InstallOptions | InstallVSIXOptions, token: CancellationToken): Promise<void>;
diff --git a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts
index 0dfadaa8c49..8acce96e6e1 100644
--- a/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts
+++ b/src/vs/platform/extensionManagement/common/extensionsProfileScannerService.ts
@@ -10,19 +10,23 @@ import { ResourceMap } from 'vs/base/common/map';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ILocalExtension, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
-import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
+import { IExtensionIdentifier, IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
+import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
+import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
interface IStoredProfileExtension {
- readonly identifier: IExtensionIdentifier;
- readonly location: UriComponents;
- readonly metadata?: Metadata;
+ identifier: IExtensionIdentifier;
+ location: UriComponents;
+ version: string;
+ metadata?: Metadata;
}
export interface IScannedProfileExtension {
readonly identifier: IExtensionIdentifier;
+ readonly version: string;
readonly location: URI;
readonly metadata?: Metadata;
}
@@ -39,13 +43,45 @@ export interface IExtensionsProfileScannerService {
export class ExtensionsProfileScannerService extends Disposable implements IExtensionsProfileScannerService {
readonly _serviceBrand: undefined;
+ private readonly migratePromise: Promise<void>;
private readonly resourcesAccessQueueMap = new ResourceMap<Queue<IScannedProfileExtension[]>>();
constructor(
@IFileService private readonly fileService: IFileService,
+ @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
+ @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
@ILogService private readonly logService: ILogService,
) {
super();
+ this.migratePromise = this.migrate();
+ }
+
+ // TODO: @sandy081 remove it in a month
+ private async migrate(): Promise<void> {
+ await Promise.all(this.userDataProfilesService.profiles.map(async e => {
+ if (!e.extensionsResource) {
+ return;
+ }
+ try {
+ let needsMigrating: boolean = false;
+ const storedWebExtensions: IStoredProfileExtension[] = JSON.parse((await this.fileService.readFile(e.extensionsResource)).value.toString());
+ for (const e of storedWebExtensions) {
+ if (!e.location) {
+ continue;
+ }
+ if (!e.version) {
+ try {
+ const content = (await this.fileService.readFile(this.uriIdentityService.extUri.joinPath(URI.revive(e.location), 'package.json'))).value.toString();
+ e.version = (<IExtensionManifest>JSON.parse(content)).version;
+ needsMigrating = true;
+ } catch (error) { /* ignore */ }
+ }
+ }
+ if (needsMigrating) {
+ await this.fileService.writeFile(e.extensionsResource, VSBuffer.fromString(JSON.stringify(storedWebExtensions)));
+ }
+ } catch (error) { /* Ignore */ }
+ }));
}
scanProfileExtensions(profileLocation: URI): Promise<IScannedProfileExtension[]> {
@@ -56,7 +92,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte
return this.withProfileExtensions(profileLocation, profileExtensions => {
// Remove the existing extension to avoid duplicates
profileExtensions = profileExtensions.filter(e => extensions.some(([extension]) => !areSameExtensions(e.identifier, extension.identifier)));
- profileExtensions.push(...extensions.map(([extension, metadata]) => ({ identifier: extension.identifier, location: extension.location, metadata })));
+ profileExtensions.push(...extensions.map(([extension, metadata]) => ({ identifier: extension.identifier, version: extension.manifest.version, location: extension.location, metadata })));
return profileExtensions;
});
}
@@ -66,6 +102,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte
}
private async withProfileExtensions(file: URI, updateFn?: (extensions: IScannedProfileExtension[]) => IScannedProfileExtension[]): Promise<IScannedProfileExtension[]> {
+ await this.migratePromise;
return this.getResourceAccessQueue(file).queue(async () => {
let extensions: IScannedProfileExtension[] = [];
@@ -74,13 +111,22 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte
const content = await this.fileService.readFile(file);
const storedWebExtensions: IStoredProfileExtension[] = JSON.parse(content.value.toString());
for (const e of storedWebExtensions) {
- if (!e.location || !e.identifier) {
- this.logService.info('Ignoring invalid extension while scanning', storedWebExtensions);
+ if (!e.identifier) {
+ this.logService.info('Ignoring invalid extension while scanning. Identifier does not exist.', e);
+ continue;
+ }
+ if (!e.location) {
+ this.logService.info('Ignoring invalid extension while scanning. Location does not exist.', e);
+ continue;
+ }
+ if (!e.version) {
+ this.logService.info('Ignoring invalid extension while scanning. Version does not exist.', e);
continue;
}
extensions.push({
identifier: e.identifier,
location: URI.revive(e.location),
+ version: e.version,
metadata: e.metadata,
});
}
@@ -96,6 +142,7 @@ export class ExtensionsProfileScannerService extends Disposable implements IExte
extensions = updateFn(extensions);
const storedProfileExtensions: IStoredProfileExtension[] = extensions.map(e => ({
identifier: e.identifier,
+ version: e.version,
location: e.location.toJSON(),
metadata: e.metadata
}));
diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts
index 4c2d6a47d6b..3eadb31770b 100644
--- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts
+++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts
@@ -22,10 +22,11 @@ import { extract, ExtractError, IFile, zip } from 'vs/base/node/zip';
import * as nls from 'vs/nls';
import { IDownloadService } from 'vs/platform/download/common/download';
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
-import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, joinErrors, UninstallExtensionTaskOptions } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService';
+import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, joinErrors } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService';
import {
ExtensionManagementError, ExtensionManagementErrorCode, IExtensionGalleryService, IExtensionIdentifier, IGalleryExtension, IGalleryMetadata, ILocalExtension, InstallOperation,
- Metadata, ServerInstallOptions, ServerInstallVSIXOptions
+ IServerExtensionManagementService,
+ Metadata, ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions
} from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions, computeTargetPlatform, ExtensionKey, getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
@@ -38,7 +39,7 @@ import { ExtensionsWatcher } from 'vs/platform/extensionManagement/node/extensio
import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
import { IFileService } from 'vs/platform/files/common/files';
-import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
+import { IInstantiationService, refineServiceDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -51,7 +52,14 @@ interface InstallableExtension {
metadata?: Metadata;
}
-export class ExtensionManagementService extends AbstractExtensionManagementService {
+export const INativeServerExtensionManagementService = refineServiceDecorator<IServerExtensionManagementService, INativeServerExtensionManagementService>(IServerExtensionManagementService);
+export interface INativeServerExtensionManagementService extends IServerExtensionManagementService {
+ readonly _serviceBrand: undefined;
+ removeUninstalledExtensions(removeOutdated: boolean): Promise<void>;
+ getAllUserInstalled(): Promise<ILocalExtension[]>;
+}
+
+export class ExtensionManagementService extends AbstractExtensionManagementService implements INativeServerExtensionManagementService {
private readonly extensionsScanner: ExtensionsScanner;
private readonly manifestCache: ExtensionsManifestCache;
@@ -117,6 +125,10 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
return this.extensionsScanner.scanExtensions(type ?? null, profileLocation);
}
+ getAllUserInstalled(): Promise<ILocalExtension[]> {
+ return this.extensionsScanner.scanUserExtensions(false);
+ }
+
async install(vsix: URI, options: ServerInstallVSIXOptions = {}): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#install', vsix.toString());
@@ -151,8 +163,8 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
return local;
}
- removeDeprecatedExtensions(): Promise<void> {
- return this.extensionsScanner.cleanUp();
+ removeUninstalledExtensions(removeOutdated: boolean): Promise<void> {
+ return this.extensionsScanner.cleanUp(removeOutdated);
}
private async downloadVsix(vsix: URI): Promise<URI> {
@@ -168,7 +180,7 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
return URI.isUri(extension) ? new InstallVSIXTask(manifest, extension, options, this.galleryService, this.extensionsScanner, this.logService) : new InstallGalleryExtensionTask(manifest, extension, options, this.extensionsDownloader, this.extensionsScanner, this.logService);
}
- protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask {
+ protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask {
return new UninstallExtensionTask(extension, options, this.extensionsScanner);
}
@@ -215,9 +227,11 @@ class ExtensionsScanner extends Disposable {
this.uninstalledFileLimiter = new Queue();
}
- async cleanUp(): Promise<void> {
+ async cleanUp(removeOutdated: boolean): Promise<void> {
await this.removeUninstalledExtensions();
- await this.removeOutdatedExtensions();
+ if (removeOutdated) {
+ await this.removeOutdatedExtensions();
+ }
}
async scanExtensions(type: ExtensionType | null, profileLocation: URI | undefined): Promise<ILocalExtension[]> {
@@ -696,7 +710,7 @@ class UninstallExtensionTask extends AbstractExtensionTask<void> implements IUni
constructor(
readonly extension: ILocalExtension,
- private readonly options: UninstallExtensionTaskOptions,
+ private readonly options: ServerUninstallOptions,
private readonly extensionsScanner: ExtensionsScanner,
) {
super();
diff --git a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts
index cdfaa38b842..54a7232c285 100644
--- a/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts
+++ b/src/vs/platform/extensionManagement/test/node/extensionsScannerService.test.ts
@@ -17,6 +17,7 @@ import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFil
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
+import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
let translations: Translations = Object.create(null);
@@ -69,7 +70,9 @@ suite('NativeExtensionsScanerService Test', () => {
extensionsPath: userExtensionsLocation.fsPath,
});
instantiationService.stub(IProductService, { version: '1.66.0' });
- instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, logService));
+ const uriIdentityService = new UriIdentityService(fileService);
+ const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, logService);
+ instantiationService.stub(IExtensionsProfileScannerService, new ExtensionsProfileScannerService(fileService, uriIdentityService, userDataProfilesService, logService));
instantiationService.stub(IUserDataProfilesService, new UserDataProfilesService(environmentService, fileService, logService));
await fileService.createFolder(systemExtensionsLocation);
await fileService.createFolder(userExtensionsLocation);
diff --git a/src/vs/platform/userDataProfile/common/userDataProfile.ts b/src/vs/platform/userDataProfile/common/userDataProfile.ts
index 39d0df3d6ba..9e9897e8cdc 100644
--- a/src/vs/platform/userDataProfile/common/userDataProfile.ts
+++ b/src/vs/platform/userDataProfile/common/userDataProfile.ts
@@ -81,6 +81,8 @@ if (!isWeb) {
});
}
+export type DidChangeProfilesEvent = { readonly added: IUserDataProfile[]; readonly removed: IUserDataProfile[]; readonly all: IUserDataProfile[] };
+
export const IUserDataProfilesService = createDecorator<IUserDataProfilesService>('IUserDataProfilesService');
export interface IUserDataProfilesService {
readonly _serviceBrand: undefined;
@@ -88,7 +90,7 @@ export interface IUserDataProfilesService {
readonly profilesHome: URI;
readonly defaultProfile: IUserDataProfile;
- readonly onDidChangeProfiles: Event<IUserDataProfile[]>;
+ readonly onDidChangeProfiles: Event<DidChangeProfilesEvent>;
readonly profiles: IUserDataProfile[];
newProfile(name: string, useDefaultFlags?: UseDefaultProfileFlags): CustomUserDataProfile;
@@ -140,7 +142,7 @@ export class UserDataProfilesService extends Disposable implements IUserDataProf
get defaultProfile(): IUserDataProfile { return this.profiles[0] ?? this._defaultProfile; }
get profiles(): IUserDataProfile[] { return []; }
- protected readonly _onDidChangeProfiles = this._register(new Emitter<IUserDataProfile[]>());
+ protected readonly _onDidChangeProfiles = this._register(new Emitter<DidChangeProfilesEvent>());
readonly onDidChangeProfiles = this._onDidChangeProfiles.event;
constructor(
diff --git a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts
index 3a7b9503f80..08974874814 100644
--- a/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts
+++ b/src/vs/platform/userDataProfile/electron-main/userDataProfile.ts
@@ -85,7 +85,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
const storedProfile: StoredUserDataProfile = { name: profile.name, location: profile.location, useDefaultFlags: profile.useDefaultFlags };
const storedProfiles = [...this.getStoredProfiles(), storedProfile];
- this.setStoredProfiles(storedProfiles);
+ this.setStoredProfiles(storedProfiles, [profile], []);
if (workspaceIdentifier) {
await this.setProfileForWorkspace(profile, workspaceIdentifier);
}
@@ -128,7 +128,7 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
await Promises.settled(joiners);
this.setStoredWorskpaceInfos(this.getStoredWorskpaceInfos().filter(p => !this.uriIdentityService.extUri.isEqual(p.profile, profile.location)));
- this.setStoredProfiles(this.getStoredProfiles().filter(p => !this.uriIdentityService.extUri.isEqual(p.location, profile.location)));
+ this.setStoredProfiles(this.getStoredProfiles().filter(p => !this.uriIdentityService.extUri.isEqual(p.location, profile.location)), [], [profile]);
try {
if (this.profiles.length === 2) {
@@ -141,10 +141,10 @@ export class UserDataProfilesMainService extends UserDataProfilesService impleme
}
}
- private setStoredProfiles(storedProfiles: StoredUserDataProfile[]) {
+ private setStoredProfiles(storedProfiles: StoredUserDataProfile[], added: IUserDataProfile[], removed: IUserDataProfile[]): void {
this.stateMainService.setItem(UserDataProfilesMainService.PROFILES_KEY, storedProfiles);
this._profilesObject = undefined;
- this._onDidChangeProfiles.fire(this.profiles);
+ this._onDidChangeProfiles.fire({ added, removed, all: this.profiles });
}
private setStoredWorskpaceInfos(storedWorkspaceInfos: StoredWorkspaceInfo[]) {
diff --git a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts
index 97ae03b8663..210bd2288b9 100644
--- a/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts
+++ b/src/vs/platform/userDataProfile/electron-sandbox/userDataProfile.ts
@@ -9,7 +9,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IFileService } from 'vs/platform/files/common/files';
import { IMainProcessService } from 'vs/platform/ipc/electron-sandbox/services';
import { ILogService } from 'vs/platform/log/common/log';
-import { IUserDataProfile, IUserDataProfilesService, reviveProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
+import { DidChangeProfilesEvent, IUserDataProfile, IUserDataProfilesService, reviveProfile, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
export class UserDataProfilesNativeService extends UserDataProfilesService implements IUserDataProfilesService {
@@ -29,9 +29,11 @@ export class UserDataProfilesNativeService extends UserDataProfilesService imple
super(environmentService, fileService, logService);
this.channel = mainProcessService.getChannel('userDataProfiles');
this._profiles = profiles.map(profile => reviveProfile(profile, this.profilesHome.scheme));
- this._register(this.channel.listen<IUserDataProfile[]>('onDidChangeProfiles')((profiles) => {
- this._profiles = profiles.map(profile => reviveProfile(profile, this.profilesHome.scheme));
- this._onDidChangeProfiles.fire(this._profiles);
+ this._register(this.channel.listen<DidChangeProfilesEvent>('onDidChangeProfiles')(e => {
+ const added = e.added.map(profile => reviveProfile(profile, this.profilesHome.scheme));
+ const removed = e.removed.map(profile => reviveProfile(profile, this.profilesHome.scheme));
+ this._profiles = e.all.map(profile => reviveProfile(profile, this.profilesHome.scheme));
+ this._onDidChangeProfiles.fire({ added, removed, all: this.profiles });
}));
}
diff --git a/src/vs/server/node/remoteExtensionHostAgentCli.ts b/src/vs/server/node/remoteExtensionHostAgentCli.ts
index 631a6d18b12..653748724e0 100644
--- a/src/vs/server/node/remoteExtensionHostAgentCli.ts
+++ b/src/vs/server/node/remoteExtensionHostAgentCli.ts
@@ -12,9 +12,9 @@ import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/platform/request/node/requestService';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IExtensionGalleryService, IExtensionManagementCLIService, InstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
-import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import product from 'vs/platform/product/common/product';
@@ -109,7 +109,7 @@ class CliMain extends Disposable {
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService));
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService));
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService));
- services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
+ services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionManagementCLIService, new SyncDescriptor(ExtensionManagementCLIService));
services.set(ILanguagePackService, new SyncDescriptor(NativeLanguagePackService));
diff --git a/src/vs/server/node/serverServices.ts b/src/vs/server/node/serverServices.ts
index fa2c8004a77..797f29fd9e5 100644
--- a/src/vs/server/node/serverServices.ts
+++ b/src/vs/server/node/serverServices.ts
@@ -24,10 +24,10 @@ import { IEncryptionMainService } from 'vs/platform/encryption/common/encryption
import { EncryptionMainService } from 'vs/platform/encryption/node/encryptionMainService';
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { ExtensionGalleryServiceWithNoStorageService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
-import { IExtensionGalleryService, IExtensionManagementCLIService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IExtensionGalleryService, IExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementCLIService } from 'vs/platform/extensionManagement/common/extensionManagementCLIService';
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc';
-import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
+import { ExtensionManagementService, INativeServerExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { IFileService } from 'vs/platform/files/common/files';
import { FileService } from 'vs/platform/files/common/fileService';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
@@ -165,7 +165,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
services.set(IExtensionsProfileScannerService, new SyncDescriptor(ExtensionsProfileScannerService));
services.set(IExtensionsScannerService, new SyncDescriptor(ExtensionsScannerService));
- services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
+ services.set(INativeServerExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
const instantiationService: IInstantiationService = new InstantiationService(services);
services.set(ILanguagePackService, instantiationService.createInstance(NativeLanguagePackService));
@@ -188,7 +188,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
services.set(ICredentialsMainService, new SyncDescriptor(CredentialsWebMainService));
instantiationService.invokeFunction(accessor => {
- const extensionManagementService = accessor.get(IExtensionManagementService);
+ const extensionManagementService = accessor.get(INativeServerExtensionManagementService);
const extensionsScannerService = accessor.get(IExtensionsScannerService);
const remoteExtensionEnvironmentChannel = new RemoteAgentEnvironmentChannel(connectionToken, environmentService, userDataProfilesService, extensionManagementCLIService, logService, extensionHostStatusService, extensionsScannerService);
socketServer.registerChannel('remoteextensionsenvironment', remoteExtensionEnvironmentChannel);
@@ -213,7 +213,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
socketServer.registerChannel('credentials', credentialsChannel);
// clean up deprecated extensions
- (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
+ extensionManagementService.removeUninstalledExtensions(true);
disposables.add(new ErrorTelemetry(accessor.get(ITelemetryService)));
diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts
index 6fbc52d18ba..57969a4ba9b 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts
@@ -75,7 +75,8 @@ import { Event } from 'vs/base/common/event';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
import { UnsupportedExtensionsMigrationContrib } from 'vs/workbench/contrib/extensions/browser/unsupportedExtensionsMigrationContribution';
import { isWeb } from 'vs/base/common/platform';
-import { ExtensionsCleaner } from 'vs/workbench/contrib/extensions/browser/extensionsCleaner';
+import { ExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
+import { IStorageService } from 'vs/platform/storage/common/storage';
// Singletons
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
@@ -1559,6 +1560,16 @@ class ExtensionsContributions extends Disposable implements IWorkbenchContributi
}
+class ExtensionStorageCleaner implements IWorkbenchContribution {
+
+ constructor(
+ @IExtensionManagementService extensionManagementService: IExtensionManagementService,
+ @IStorageService storageService: IStorageService,
+ ) {
+ ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService);
+ }
+}
+
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ExtensionsContributions, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
@@ -1571,7 +1582,7 @@ workbenchRegistry.registerWorkbenchContribution(ExtensionEnablementWorkspaceTrus
workbenchRegistry.registerWorkbenchContribution(ExtensionsCompletionItemsProvider, LifecyclePhase.Restored);
workbenchRegistry.registerWorkbenchContribution(UnsupportedExtensionsMigrationContrib, LifecyclePhase.Eventually);
if (isWeb) {
- workbenchRegistry.registerWorkbenchContribution(ExtensionsCleaner, LifecyclePhase.Eventually);
+ workbenchRegistry.registerWorkbenchContribution(ExtensionStorageCleaner, LifecyclePhase.Eventually);
}
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts b/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts
deleted file mode 100644
index 2d9b7872491..00000000000
--- a/src/vs/workbench/contrib/extensions/browser/extensionsCleaner.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
-import { ExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
-import { IStorageService } from 'vs/platform/storage/common/storage';
-import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
-
-export class ExtensionsCleaner implements IWorkbenchContribution {
-
- constructor(
- @IExtensionManagementService extensionManagementService: IExtensionManagementService,
- @IStorageService storageService: IStorageService,
- ) {
- ExtensionStorageService.removeOutdatedExtensionVersions(extensionManagementService, storageService);
- }
-}
diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts
index 6c1cba6e975..147936d4468 100644
--- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts
+++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts
@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { ExtensionType, IExtension, IExtensionIdentifier, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
-import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata } from 'vs/platform/extensionManagement/common/extensionManagement';
+import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IGalleryMetadata, InstallOperation, IExtensionGalleryService, InstallOptions, Metadata, UninstallOptions } from 'vs/platform/extensionManagement/common/extensionManagement';
import { URI } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { areSameExtensions, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IProfileAwareExtensionManagementService, IScannedExtension, IWebExtensionsScannerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
-import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask, UninstallExtensionTaskOptions } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService';
+import { AbstractExtensionManagementService, AbstractExtensionTask, IInstallExtensionTask, IUninstallExtensionTask } from 'vs/platform/extensionManagement/common/abstractExtensionManagementService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IProductService } from 'vs/platform/product/common/productService';
@@ -106,7 +106,7 @@ export class WebExtensionManagementService extends AbstractExtensionManagementSe
return new InstallExtensionTask(manifest, extension, options, this.webExtensionsScannerService);
}
- protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallExtensionTaskOptions): IUninstallExtensionTask {
+ protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: UninstallOptions): IUninstallExtensionTask {
return new UninstallExtensionTask(extension, options, this.webExtensionsScannerService);
}
@@ -191,7 +191,7 @@ class UninstallExtensionTask extends AbstractExtensionTask<void> implements IUni
constructor(
readonly extension: ILocalExtension,
- options: UninstallExtensionTaskOptions,
+ options: UninstallOptions,
private readonly webExtensionsScannerService: IWebExtensionsScannerService,
) {
super();