Skip to content

Commit 5ccf7c4

Browse files
authored
Merge pull request microsoft#154540 from microsoft/sandy081/profiles-adopt-web-scanner
prepare web extensions management for profiles
2 parents e69176a + 3784c14 commit 5ccf7c4

File tree

19 files changed

+305
-198
lines changed

19 files changed

+305
-198
lines changed

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

Lines changed: 24 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +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';
22-
import { ExtensionType, IExtensionManifest, TargetPlatform } from 'vs/platform/extensions/common/extensions';
21+
import { ExtensionType, IExtensionManifest, isApplicationScopedExtension, 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';
2725
import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
2826

2927
export interface IInstallExtensionTask {
@@ -66,13 +64,11 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
6664
private readonly participants: IExtensionManagementParticipant[] = [];
6765

6866
constructor(
69-
@IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService,
70-
@IUriIdentityService private readonly uriIdenityService: IUriIdentityService,
7167
@IExtensionGalleryService protected readonly galleryService: IExtensionGalleryService,
72-
@IExtensionsProfileScannerService protected readonly extensionsProfileScannerService: IExtensionsProfileScannerService,
7368
@ITelemetryService protected readonly telemetryService: ITelemetryService,
7469
@ILogService protected readonly logService: ILogService,
75-
@IProductService protected readonly productService: IProductService
70+
@IProductService protected readonly productService: IProductService,
71+
@IUserDataProfilesService protected readonly userDataProfilesService: IUserDataProfilesService,
7672
) {
7773
super();
7874
this._register(toDisposable(() => {
@@ -120,7 +116,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
120116
throw new Error(nls.localize('Not a Marketplace extension', "Only Marketplace Extensions can be reinstalled"));
121117
}
122118

123-
await this.createDefaultUninstallExtensionTask(extension, { remove: true, versionOnly: true }).run();
119+
await this.createUninstallExtensionTask(extension, { remove: true, versionOnly: true }).run();
124120
await this.installFromGallery(galleryExtension);
125121
}
126122

@@ -140,13 +136,15 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
140136
}
141137

142138
protected async installExtension(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): Promise<ILocalExtension> {
139+
140+
const getInstallExtensionTaskKey = (extension: IGalleryExtension) => `${ExtensionKey.create(extension).toString()}${options.profileLocation ? `-${options.profileLocation.toString()}` : ''}`;
141+
143142
// only cache gallery extensions tasks
144143
if (!URI.isUri(extension)) {
145-
const installExtensionTask = this.installingExtensions.get(ExtensionKey.create(extension).toString());
144+
const installExtensionTask = this.installingExtensions.get(getInstallExtensionTaskKey(extension));
146145
if (installExtensionTask) {
147146
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();
147+
const { local } = await installExtensionTask.waitUntilTaskIsFinished();
150148
return local;
151149
}
152150
options = { ...options, installOnlyNewlyAddedFromExtensionPack: true /* always true for gallery extensions */ };
@@ -156,7 +154,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
156154
const installResults: (ServerInstallExtensionResult & { local: ILocalExtension })[] = [];
157155
const installExtensionTask = this.createInstallExtensionTask(manifest, extension, options);
158156
if (!URI.isUri(extension)) {
159-
this.installingExtensions.set(ExtensionKey.create(extension).toString(), installExtensionTask);
157+
this.installingExtensions.set(getInstallExtensionTaskKey(extension), installExtensionTask);
160158
}
161159
this._onInstallExtension.fire({ identifier: installExtensionTask.identifier, source: extension, profileLocation: options.profileLocation });
162160
this.logService.info('Installing extension:', installExtensionTask.identifier.id);
@@ -171,7 +169,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
171169
const allDepsAndPackExtensionsToInstall = await this.getAllDepsAndPackExtensionsToInstall(installExtensionTask.identifier, manifest, !!options.installOnlyNewlyAddedFromExtensionPack, !!options.installPreReleaseVersion, options.profileLocation);
172170
for (const { gallery, manifest } of allDepsAndPackExtensionsToInstall) {
173171
installExtensionHasDependents = installExtensionHasDependents || !!manifest.extensionDependencies?.some(id => areSameExtensions({ id }, installExtensionTask.identifier));
174-
const key = ExtensionKey.create(gallery).toString();
172+
const key = getInstallExtensionTaskKey(gallery);
175173
if (this.installingExtensions.has(key)) {
176174
this.logService.info('Extension is already requested to install', gallery.identifier.id);
177175
} else {
@@ -260,7 +258,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
260258
// rollback installed extensions
261259
if (installResults.length) {
262260
try {
263-
const result = await Promise.allSettled(installResults.map(({ local }) => this.createUninstallExtensionTask(local, { versionOnly: true }, options.profileLocation).run()));
261+
const result = await Promise.allSettled(installResults.map(({ local }) => this.createUninstallExtensionTask(local, { versionOnly: true, profileLocation: options.profileLocation }).run()));
264262
for (let index = 0; index < result.length; index++) {
265263
const r = result[index];
266264
const { identifier } = installResults[index];
@@ -282,7 +280,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
282280
/* Remove the gallery tasks from the cache */
283281
for (const { task } of allInstallExtensionTasks) {
284282
if (!URI.isUri(task.source)) {
285-
const key = ExtensionKey.create(task.source).toString();
283+
const key = getInstallExtensionTaskKey(task.source);
286284
if (!this.installingExtensions.delete(key)) {
287285
this.logService.warn('Installation task is not found in the cache', key);
288286
}
@@ -434,7 +432,7 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
434432
}
435433

436434
const createUninstallExtensionTask = (extension: ILocalExtension, uninstallOptions: ServerUninstallOptions): IUninstallExtensionTask => {
437-
const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions, options.profileLocation);
435+
const uninstallExtensionTask = this.createUninstallExtensionTask(extension, uninstallOptions);
438436
this.uninstallingExtensions.set(getUninstallExtensionTaskKey(uninstallExtensionTask.extension.identifier), uninstallExtensionTask);
439437
if (options.profileLocation) {
440438
this.logService.info('Uninstalling extension from the profile:', `${extension.identifier.id}@${extension.manifest.version}`, options.profileLocation.toString());
@@ -604,22 +602,17 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
604602
}
605603

606604
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;
605+
if (options.profileLocation && isApplicationScopedExtension(manifest)) {
606+
options = { ...options, profileLocation: this.userDataProfilesService.defaultProfile.extensionsResource };
617607
}
618-
return new InstallExtensionInProfileTask(installTask, options.profileLocation, this.userDataProfilesService.defaultProfile.extensionsResource, this.extensionsProfileScannerService);
608+
return this.doCreateInstallExtensionTask(manifest, extension, options);
619609
}
620610

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);
611+
private createUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask {
612+
if (options.profileLocation && extension.isApplicationScoped) {
613+
options = { ...options, profileLocation: this.userDataProfilesService.defaultProfile.extensionsResource };
614+
}
615+
return this.doCreateUninstallExtensionTask(extension, options);
623616
}
624617

625618
abstract getTargetPlatform(): Promise<TargetPlatform>;
@@ -633,8 +626,8 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
633626
abstract updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension>;
634627
abstract updateExtensionScope(local: ILocalExtension, isMachineScoped: boolean): Promise<ILocalExtension>;
635628

636-
protected abstract createDefaultInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask;
637-
protected abstract createDefaultUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask;
629+
protected abstract doCreateInstallExtensionTask(manifest: IExtensionManifest, extension: URI | IGalleryExtension, options: ServerInstallOptions & ServerInstallVSIXOptions): IInstallExtensionTask;
630+
protected abstract doCreateUninstallExtensionTask(extension: ILocalExtension, options: ServerUninstallOptions): IUninstallExtensionTask;
638631
}
639632

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

732725
protected abstract doRun(token: CancellationToken): Promise<T>;
733726
}
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-
}

0 commit comments

Comments
 (0)