@@ -20,7 +20,8 @@ import {
20
20
InstallExtensionResult ,
21
21
UninstallOptions ,
22
22
IGalleryMetadata ,
23
- StatisticType
23
+ StatisticType ,
24
+ IExtensionManagementParticipant
24
25
} from 'vs/platform/extensionManagement/common/extensionManagement' ;
25
26
import { areSameExtensions , getMaliciousExtensionsSet , getGalleryExtensionTelemetryData , ExtensionIdentifierWithVersion , getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil' ;
26
27
import { Event , Emitter } from 'vs/base/common/event' ;
@@ -76,6 +77,8 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
76
77
protected _onDidUninstallExtension = this . _register ( new Emitter < DidUninstallExtensionEvent > ( ) ) ;
77
78
onDidUninstallExtension : Event < DidUninstallExtensionEvent > = this . _onDidUninstallExtension . event ;
78
79
80
+ private readonly participants : IExtensionManagementParticipant [ ] = [ ] ;
81
+
79
82
constructor (
80
83
@IExtensionGalleryService protected readonly galleryService : IExtensionGalleryService ,
81
84
@ITelemetryService protected readonly telemetryService : ITelemetryService ,
@@ -152,6 +155,10 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
152
155
return this . reportedExtensions ;
153
156
}
154
157
158
+ registerParticipant ( participant : IExtensionManagementParticipant ) : void {
159
+ this . participants . push ( participant ) ;
160
+ }
161
+
155
162
protected async installExtension ( manifest : IExtensionManifest , extension : URI | IGalleryExtension , options : InstallOptions & InstallVSIXOptions ) : Promise < ILocalExtension > {
156
163
// only cache gallery extensions tasks
157
164
if ( ! URI . isUri ( extension ) ) {
@@ -217,10 +224,11 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
217
224
}
218
225
219
226
// Install extensions in parallel and wait until all extensions are installed / failed
220
- const result = await Promise . allSettled ( extensionsToInstall . map ( async ( { task } ) => {
227
+ await this . joinAllSettled ( extensionsToInstall . map ( async ( { task } ) => {
221
228
const startTime = new Date ( ) . getTime ( ) ;
222
229
try {
223
230
const local = await task . run ( ) ;
231
+ await this . joinAllSettled ( this . participants . map ( participant => participant . postInstall ( local , task . source , options , CancellationToken . None ) ) ) ;
224
232
if ( ! URI . isUri ( task . source ) ) {
225
233
reportTelemetry ( this . telemetryService , task . operation === InstallOperation . Update ? 'extensionGallery:update' : 'extensionGallery:install' , getGalleryExtensionTelemetryData ( task . source ) , new Date ( ) . getTime ( ) - startTime , undefined ) ;
226
234
}
@@ -234,11 +242,6 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
234
242
throw error ;
235
243
} finally { extensionsToInstallMap . delete ( task . identifier . id . toLowerCase ( ) ) ; }
236
244
} ) ) ;
237
-
238
- // Collect the errors
239
- const errors = result . reduce < any [ ] > ( ( errors , r ) => { if ( r . status === 'rejected' ) { errors . push ( r . reason ) ; } return errors ; } , [ ] ) ;
240
- // If there are errors, throw the error.
241
- if ( errors . length ) { throw joinErrors ( errors ) ; }
242
245
}
243
246
244
247
installResults . forEach ( ( { identifier } ) => this . logService . info ( `Extension installed successfully:` , identifier . id ) ) ;
@@ -289,6 +292,22 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
289
292
}
290
293
}
291
294
295
+ private async joinAllSettled < T > ( promises : Promise < T > [ ] ) : Promise < T [ ] > {
296
+ const results : T [ ] = [ ] ;
297
+ const errors : any [ ] = [ ] ;
298
+ const promiseResults = await Promise . allSettled ( promises ) ;
299
+ for ( const r of promiseResults ) {
300
+ if ( r . status === 'fulfilled' ) {
301
+ results . push ( r . value ) ;
302
+ } else {
303
+ errors . push ( r . reason ) ;
304
+ }
305
+ }
306
+ // If there are errors, throw the error.
307
+ if ( errors . length ) { throw joinErrors ( errors ) ; }
308
+ return results ;
309
+ }
310
+
292
311
private async getAllDepsAndPackExtensionsToInstall ( extensionIdentifier : IExtensionIdentifier , manifest : IExtensionManifest , getOnlyNewlyAddedFromExtensionPack : boolean ) : Promise < { gallery : IGalleryExtension , manifest : IExtensionManifest } [ ] > {
293
312
if ( ! this . galleryService . isEnabled ( ) ) {
294
313
return [ ] ;
@@ -413,9 +432,10 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
413
432
}
414
433
415
434
// Uninstall extensions in parallel and wait until all extensions are uninstalled / failed
416
- const result = await Promise . allSettled ( allTasks . map ( async task => {
435
+ await this . joinAllSettled ( allTasks . map ( async task => {
417
436
try {
418
437
await task . run ( ) ;
438
+ await this . joinAllSettled ( this . participants . map ( participant => participant . postUninstall ( task . extension , options , CancellationToken . None ) ) ) ;
419
439
// only report if extension has a mapped gallery extension. UUID identifies the gallery extension.
420
440
if ( task . extension . identifier . uuid ) {
421
441
try {
@@ -432,11 +452,6 @@ export abstract class AbstractExtensionManagementService extends Disposable impl
432
452
}
433
453
} ) ) ;
434
454
435
- // Collect the errors
436
- const errors = result . reduce < any [ ] > ( ( errors , r ) => { if ( r . status === 'rejected' ) { errors . push ( r . reason ) ; } return errors ; } , [ ] ) ;
437
- // If there are errors, throw the error.
438
- if ( errors . length ) { throw joinErrors ( errors ) ; }
439
-
440
455
} catch ( e ) {
441
456
const error = e instanceof ExtensionManagementError ? e : new ExtensionManagementError ( getErrorMessage ( e ) , ERROR_UNKNOWN ) ;
442
457
for ( const task of allTasks ) {
0 commit comments