Skip to content

Commit 7f8fdb3

Browse files
committed
adopt extension installation in profiles in web
1 parent 6037448 commit 7f8fdb3

File tree

3 files changed

+102
-111
lines changed

3 files changed

+102
-111
lines changed

src/vs/platform/extensionManagement/common/abstractExtensionManagementService.ts

Lines changed: 13 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ import {
1818
ServerInstallOptions, ServerInstallVSIXOptions, ServerUninstallOptions, Metadata, ServerInstallExtensionEvent, ServerInstallExtensionResult, ServerUninstallExtensionEvent, ServerDidUninstallExtensionEvent
1919
} from 'vs/platform/extensionManagement/common/extensionManagement';
2020
import { areSameExtensions, ExtensionKey, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, getMaliciousExtensionsSet } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
21-
import { IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
2221
import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
2322
import { ILogService } from 'vs/platform/log/common/log';
2423
import { IProductService } from 'vs/platform/product/common/productService';
2524
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
26-
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
27-
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
2825

2926
export interface IInstallExtensionTask {
3027
readonly identifier: IExtensionIdentifier;
@@ -66,10 +63,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
6663
private readonly participants: IExtensionManagementParticipant[] = [];
6764

6865
constructor(
69-
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
70-
@IUriIdentityService private readonly uriIdenityService: IUriIdentityService,
7166
@IExtensionGalleryService protected readonly galleryService: IExtensionGalleryService,
72-
@IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
7367
@ITelemetryService protected readonly telemetryService: ITelemetryService,
7468
@ILogService protected readonly logService: ILogService,
7569
@IProductService protected readonly productService: IProductService
@@ -120,7 +114,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
120114
throw new Error(nls.localize('Not a Marketplace extension', "Only Marketplace Extensions can be reinstalled"));
121115
}
122116

123-
await this.createDefaultUninstallExtensionTask(extension, { remove: true, versionOnly: true }).run();
117+
await this.createUninstallExtensionTask(extension, { remove: true, versionOnly: true }).run();
124118
await this.installFromGallery(galleryExtension);
125119
}
126120

@@ -140,13 +134,15 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
140134
}
141135

142136
protected async installExtension(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): Promise<ILocalExtension> {
137+
138+
const getInstallExtensionTaskKey = (extension: IGalleryExtension) => `${ExtensionKey.create(extension).toString()}${options.profileLocation ? `-${options.profileLocation.toString()}` : ''}`;
139+
143140
// only cache gallery extensions tasks
144141
if (!URI.isUri(extension)) {
145-
const installExtensionTask = this.installingExtensions.get(ExtensionKey.create(extension).toString());
142+
const installExtensionTask = this.installingExtensions.get(getInstallExtensionTaskKey(extension));
146143
if (installExtensionTask) {
147144
this.logService.info('Extensions is already requested to install', extension.identifier.id);
148-
const waitUntilTaskIsFinishedTask = this.createWaitUntilInstallExtensionTaskIsFinishedTask(installExtensionTask, options);
149-
const { local } = await waitUntilTaskIsFinishedTask.waitUntilTaskIsFinished();
145+
const { local } = await installExtensionTask.waitUntilTaskIsFinished();
150146
return local;
151147
}
152148
options = { ...options, installOnlyNewlyAddedFromExtensionPack: true /* always true for gallery extensions */ };
@@ -156,7 +152,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
156152
const installResults: (ServerInstallExtensionResult & { local: ILocalExtension })[] = [];
157153
const installExtensionTask = this.createInstallExtensionTask(manifest, extension, options);
158154
if (!URI.isUri(extension)) {
159-
this.installingExtensions.set(ExtensionKey.create(extension).toString(), installExtensionTask);
155+
this.installingExtensions.set(getInstallExtensionTaskKey(extension), installExtensionTask);
160156
}
161157
this._onInstallExtension.fire({ identifier: installExtensionTask.identifier, source: extension, profileLocation: options.profileLocation });
162158
this.logService.info('Installing extension:', installExtensionTask.identifier.id);
@@ -171,7 +167,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
171167
const allDepsAndPackExtensionsToInstall = await this.getAllDepsAndPackExtensionsToInstall(installExtensionTask.identifier, manifest, !!options.installOnlyNewlyAddedFromExtensionPack, !!options.installPreReleaseVersion, options.profileLocation);
172168
for (const { gallery, manifest } of allDepsAndPackExtensionsToInstall) {
173169
installExtensionHasDependents = installExtensionHasDependents || !!manifest.extensionDependencies?.some(id => areSameExtensions({ id }, installExtensionTask.identifier));
174-
const key = ExtensionKey.create(gallery).toString();
170+
const key = getInstallExtensionTaskKey(gallery);
175171
if (this.installingExtensions.has(key)) {
176172
this.logService.info('Extension is already requested to install', gallery.identifier.id);
177173
} else {
@@ -260,7 +256,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
260256
// rollback installed extensions
261257
if (installResults.length) {
262258
try {
263-
const result = await Promise.allSettled(installResults.map(({ local }) => this.createUninstallExtensionTask(local, { versionOnly: true }, options.profileLocation).run()));
259+
const result = await Promise.allSettled(installResults.map(({ local }) => this.createUninstallExtensionTask(local, { versionOnly: true, profileLocation: options.profileLocation }).run()));
264260
for (let index = 0; index < result.length; index++) {
265261
const r = result[index];
266262
const { identifier } = installResults[index];
@@ -282,7 +278,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
282278
/* Remove the gallery tasks from the cache */
283279
for (const { task } of allInstallExtensionTasks) {
284280
if (!URI.isUri(task.source)) {
285-
const key = ExtensionKey.create(task.source).toString();
281+
const key = getInstallExtensionTaskKey(task.source);
286282
if (!this.installingExtensions.delete(key)) {
287283
this.logService.warn('Installation task is not found in the cache', key);
288284
}
@@ -434,7 +430,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
434430
}
435431

436432
const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: ServerUninstallOptions): IUninstallExtensionTask => {
437-
const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions, options.profileLocation);
433+
const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions);
438434
this.uninstallingExtensions.set(getUninstallExtensionTaskKey(uninstallExtensionTask.extension.identifier), uninstallExtensionTask);
439435
if (options.profileLocation) {
440436
this.logService.info('Uninstalling extension from the profile:', `${extension.identifier.id}@${extension.manifest.version}`, options.profileLocation.toString());
@@ -603,25 +599,6 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
603599
}
604600
}
605601

606-
private createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
607-
const installTask = this.createDefaultInstallExtensionTask(manifest, extension, options);
608-
return options.profileLocation && this.userDataProfilesService.defaultProfile.extensionsResource ? new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService) : installTask;
609-
}
610-
611-
private createWaitUntilInstallExtensionTaskIsFinishedTask(installTask: IInstallExtensionTask, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
612-
if (!options.profileLocation || !this.userDataProfilesService.defaultProfile.extensionsResource) {
613-
return installTask;
614-
}
615-
if (installTask instanceof InstallExtensionInProfileTask && this.uriIdenityService.extUri.isEqual(installTask.profileLocation, options.profileLocation)) {
616-
return installTask;
617-
}
618-
return new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService);
619-
}
620-
621-
private createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions, profile?: URI): IUninstallExtensionTask {
622-
return profile && this.userDataProfilesService.defaultProfile.extensionsResource ? new UninstallExtensionFromProfileTask(extension, profile, this.userDataProfilesService, this.extensionsProfileScannerService) : this.createDefaultUninstallExtensionTask(extension, options);
623-
}
624-
625602
abstract getTargetPlatform(): Promise<TargetPlatform>;
626603
abstract zip(extension: ILocalExtension): Promise<URI>;
627604
abstract unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
@@ -633,8 +610,8 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
633610
abstract updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension>;
634611
abstract updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension>;
635612

636-
protected abstract createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask;
637-
protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask;
613+
protected abstract createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask;
614+
protected abstract createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask;
638615
}
639616

640617
export function joinErrors(errorOrErrors: (Error | string) | (Array<Error | string>)): Error {
@@ -731,63 +708,3 @@ export abstract class AbstractExtensionTask<T> {
731708

732709
protected abstract doRun(token: CancellationToken): Promise<T>;
733710
}
734-
735-
class InstallExtensionInProfileTask implements IInstallExtensionTask {
736-
737-
readonly identifier = this.task.identifier;
738-
readonly source = this.task.source;
739-
readonly operation = this.task.operation;
740-
741-
private readonly promise: Promise<{ local: ILocalExtension; metadata: Metadata }>;
742-
743-
constructor(
744-
private readonly task: IInstallExtensionTask,
745-
readonly profileLocation: URI,
746-
private readonly defaultProfileLocation: URI,
747-
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
748-
) {
749-
this.promise = this.waitAndAddExtensionToProfile();
750-
}
751-
752-
private async waitAndAddExtensionToProfile(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
753-
const result = await this.task.waitUntilTaskIsFinished();
754-
const profileLocation = result.local.isApplicationScoped ? this.defaultProfileLocation : this.profileLocation;
755-
await this.extensionsProfileScannerService.addExtensionsToProfile([[result.local, result.metadata]], profileLocation);
756-
return result;
757-
}
758-
759-
async run(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
760-
await this.task.run();
761-
return this.promise;
762-
}
763-
764-
waitUntilTaskIsFinished(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
765-
return this.promise;
766-
}
767-
768-
cancel(): void {
769-
return this.task.cancel();
770-
}
771-
}
772-
773-
class UninstallExtensionFromProfileTask extends AbstractExtensionTask<void> implements IUninstallExtensionTask {
774-
775-
constructor(
776-
readonly extension: ILocalExtension,
777-
private readonly profileLocation: URI,
778-
private readonly userDataProfilesService: IUserDataProfilesService,
779-
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
780-
) {
781-
super();
782-
}
783-
784-
protected async doRun(token: CancellationToken): Promise<void> {
785-
const promises: Promise<any>[] = [];
786-
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.profileLocation));
787-
if (this.extension.isApplicationScoped && this.userDataProfilesService.defaultProfile.extensionsResource) {
788-
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.userDataProfilesService.defaultProfile.extensionsResource));
789-
}
790-
await Promise.all(promises);
791-
}
792-
793-
}

src/vs/platform/extensionManagement/node/extensionManagementService.ts

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,23 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
6565
private readonly manifestCache: ExtensionsManifestCache;
6666
private readonly extensionsDownloader: ExtensionsDownloader;
6767

68+
private readonly installGalleryExtensionsTasks = new Map<string, InstallGalleryExtensionTask>();
69+
6870
constructor(
6971
@IExtensionGalleryService galleryService: IExtensionGalleryService,
7072
@ITelemetryService telemetryService: ITelemetryService,
7173
@ILogService logService: ILogService,
7274
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
7375
@IExtensionsScannerService private readonly extensionsScannerService: IExtensionsScannerService,
74-
@IExtensionsProfileScannerService extensionsProfileScannerService: IExtensionsProfileScannerService,
76+
@IExtensionsProfileScannerService private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
7577
@IDownloadService private downloadService: IDownloadService,
7678
@IInstantiationService instantiationService: IInstantiationService,
7779
@IFileService private readonly fileService: IFileService,
7880
@IProductService productService: IProductService,
7981
@IUriIdentityService uriIdentityService: IUriIdentityService,
80-
@IUserDataProfilesService userDataProfilesService: IUserDataProfilesService,
82+
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
8183
) {
82-
super(userDataProfilesService, uriIdentityService, galleryService, extensionsProfileScannerService, telemetryService, logService, productService);
84+
super(galleryService, telemetryService, logService, productService);
8385
const extensionLifecycle = this._register(instantiationService.createInstance(ExtensionsLifecycle));
8486
this.extensionsScanner = this._register(instantiationService.createInstance(ExtensionsScanner, extension => extensionLifecycle.postUninstall(extension)));
8587
this.manifestCache = this._register(new ExtensionsManifestCache(environmentService, this));
@@ -176,11 +178,28 @@ export class ExtensionManagementService extends AbstractExtensionManagementServi
176178
return downloadedLocation;
177179
}
178180

179-
protected createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
180-
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);
181+
protected createInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask {
182+
let installExtensionTask: IInstallExtensionTask | undefined;
183+
if (URI.isUri(extension)) {
184+
installExtensionTask = new InstallVSIXTask(manifest, extension, options, this.galleryService, this.extensionsScanner, this.logService);
185+
} else {
186+
const key = ExtensionKey.create(extension).toString();
187+
installExtensionTask = this.installGalleryExtensionsTasks.get(key);
188+
if (!installExtensionTask) {
189+
this.installGalleryExtensionsTasks.set(key, installExtensionTask = new InstallGalleryExtensionTask(manifest, extension, options, this.extensionsDownloader, this.extensionsScanner, this.logService));
190+
installExtensionTask.waitUntilTaskIsFinished().then(() => this.installGalleryExtensionsTasks.delete(key));
191+
}
192+
}
193+
if (options.profileLocation && this.userDataProfilesService.defaultProfile.extensionsResource) {
194+
return new InstallExtensionInProfileTask(installExtensionTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService);
195+
}
196+
return installExtensionTask;
181197
}
182198

183-
protected createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask {
199+
protected createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask {
200+
if (options.profileLocation && this.userDataProfilesService.defaultProfile.extensionsResource) {
201+
return new UninstallExtensionFromProfileTask(extension, options.profileLocation, this.userDataProfilesService, this.extensionsProfileScannerService);
202+
}
184203
return new UninstallExtensionTask(extension, options, this.extensionsScanner);
185204
}
186205

@@ -706,6 +725,44 @@ class InstallVSIXTask extends InstallExtensionTask {
706725
}
707726
}
708727

728+
class InstallExtensionInProfileTask implements IInstallExtensionTask {
729+
730+
readonly identifier = this.task.identifier;
731+
readonly source = this.task.source;
732+
readonly operation = this.task.operation;
733+
734+
private readonly promise: Promise<{ local: ILocalExtension; metadata: Metadata }>;
735+
736+
constructor(
737+
private readonly task: IInstallExtensionTask,
738+
readonly profileLocation: URI,
739+
private readonly defaultProfileLocation: URI,
740+
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
741+
) {
742+
this.promise = this.waitAndAddExtensionToProfile();
743+
}
744+
745+
private async waitAndAddExtensionToProfile(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
746+
const result = await this.task.waitUntilTaskIsFinished();
747+
const profileLocation = result.local.isApplicationScoped ? this.defaultProfileLocation : this.profileLocation;
748+
await this.extensionsProfileScannerService.addExtensionsToProfile([[result.local, result.metadata]], profileLocation);
749+
return result;
750+
}
751+
752+
async run(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
753+
await this.task.run();
754+
return this.promise;
755+
}
756+
757+
waitUntilTaskIsFinished(): Promise<{ local: ILocalExtension; metadata: Metadata }> {
758+
return this.promise;
759+
}
760+
761+
cancel(): void {
762+
return this.task.cancel();
763+
}
764+
}
765+
709766
class UninstallExtensionTask extends AbstractExtensionTask<void> implements IUninstallExtensionTask {
710767

711768
constructor(
@@ -745,3 +802,26 @@ class UninstallExtensionTask extends AbstractExtensionTask<void> implements IUni
745802
}
746803

747804
}
805+
806+
class UninstallExtensionFromProfileTask extends AbstractExtensionTask<void> implements IUninstallExtensionTask {
807+
808+
constructor(
809+
readonly extension: ILocalExtension,
810+
private readonly profileLocation: URI,
811+
private readonly userDataProfilesService: IUserDataProfilesService,
812+
private readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
813+
) {
814+
super();
815+
}
816+
817+
protected async doRun(token: CancellationToken): Promise<void> {
818+
const promises: Promise<any>[] = [];
819+
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.profileLocation));
820+
if (this.extension.isApplicationScoped && this.userDataProfilesService.defaultProfile.extensionsResource) {
821+
promises.push(this.extensionsProfileScannerService.removeExtensionFromProfile(this.extension.identifier, this.userDataProfilesService.defaultProfile.extensionsResource));
822+
}
823+
await Promise.all(promises);
824+
}
825+
826+
}
827+

0 commit comments

Comments
 (0)