3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
- import { IBuiltinExtensionsScannerService , ExtensionType , IExtensionIdentifier , IExtension , IExtensionManifest , TargetPlatform } from 'vs/platform/extensions/common/extensions' ;
6
+ import { IBuiltinExtensionsScannerService , ExtensionType , IExtensionIdentifier , IExtension , IExtensionManifest , TargetPlatform , ExtensionIdentifier } from 'vs/platform/extensions/common/extensions' ;
7
7
import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService' ;
8
8
import { IScannedExtension , IWebExtensionsScannerService , ScanOptions } from 'vs/workbench/services/extensionManagement/common/extensionManagement' ;
9
9
import { isWeb , Language } from 'vs/base/common/platform' ;
@@ -33,15 +33,17 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
33
33
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation' ;
34
34
import { basename } from 'vs/base/common/path' ;
35
35
import { IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage' ;
36
- import { isNonEmptyArray } from 'vs/base/common/arrays' ;
36
+ import { delta , isNonEmptyArray } from 'vs/base/common/arrays' ;
37
37
import { ILifecycleService , LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
38
38
import { IStorageService , StorageScope , StorageTarget } from 'vs/platform/storage/common/storage' ;
39
39
import { IProductService } from 'vs/platform/product/common/productService' ;
40
40
import { validateExtensionManifest } from 'vs/platform/extensions/common/extensionValidator' ;
41
41
import Severity from 'vs/base/common/severity' ;
42
42
import { IStringDictionary } from 'vs/base/common/collections' ;
43
- import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' ;
43
+ import { DidChangeUserDataProfileEvent , IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' ;
44
44
import { IUserDataProfile , IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile' ;
45
+ import { Emitter } from 'vs/base/common/event' ;
46
+ import { compare } from 'vs/base/common/strings' ;
45
47
46
48
type GalleryExtensionInfo = { readonly id : string ; preRelease ?: boolean ; migrateStorageFrom ?: string } ;
47
49
type ExtensionInfo = { readonly id : string ; preRelease : boolean } ;
@@ -87,6 +89,9 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
87
89
private readonly customBuiltinExtensionsCacheResource : URI | undefined = undefined ;
88
90
private readonly resourcesAccessQueueMap = new ResourceMap < Queue < IWebExtension [ ] > > ( ) ;
89
91
92
+ private readonly _onDidChangeProfileExtensions = this . _register ( new Emitter < { readonly added : IScannedExtension [ ] ; readonly removed : IScannedExtension [ ] } > ( ) ) ;
93
+ readonly onDidChangeProfileExtensions = this . _onDidChangeProfileExtensions . event ;
94
+
90
95
constructor (
91
96
@IBrowserWorkbenchEnvironmentService private readonly environmentService : IBrowserWorkbenchEnvironmentService ,
92
97
@IBuiltinExtensionsScannerService private readonly builtinExtensionsScannerService : IBuiltinExtensionsScannerService ,
@@ -110,6 +115,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
110
115
111
116
// Eventually update caches
112
117
lifecycleService . when ( LifecyclePhase . Eventually ) . then ( ( ) => this . updateCaches ( ) ) ;
118
+ this . _register ( userDataProfileService . onDidChangeCurrentProfile ( e => e . join ( this . whenProfileChanged ( e ) ) ) ) ;
113
119
}
114
120
}
115
121
@@ -381,7 +387,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
381
387
}
382
388
383
389
// User Installed extensions
384
- const installedExtensions = await this . scanInstalledExtensions ( scanOptions ) ;
390
+ const installedExtensions = await this . scanInstalledExtensions ( this . userDataProfileService . currentProfile , scanOptions ) ;
385
391
for ( const extension of installedExtensions ) {
386
392
extensions . set ( extension . identifier . id . toLowerCase ( ) , extension ) ;
387
393
}
@@ -480,30 +486,30 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
480
486
const installedExtensions = await this . readInstalledExtensions ( profile ) ;
481
487
// Also add to installed extensions if it is installed to update its version
482
488
if ( installedExtensions . some ( e => areSameExtensions ( e . identifier , webExtension . identifier ) ) ) {
483
- await this . addToInstalledExtensions ( webExtension , profile ) ;
489
+ await this . addToInstalledExtensions ( [ webExtension ] , profile ) ;
484
490
}
485
491
return extension ;
486
492
}
487
493
488
494
// Add to installed extensions
489
- await this . addToInstalledExtensions ( webExtension , profile ) ;
495
+ await this . addToInstalledExtensions ( [ webExtension ] , profile ) ;
490
496
return extension ;
491
497
}
492
498
493
- private async addToInstalledExtensions ( webExtension : IWebExtension , profile : IUserDataProfile ) : Promise < void > {
499
+ private async addToInstalledExtensions ( webExtensions : IWebExtension [ ] , profile : IUserDataProfile ) : Promise < void > {
494
500
await this . writeInstalledExtensions ( profile , installedExtensions => {
495
501
// Remove the existing extension to avoid duplicates
496
- installedExtensions = installedExtensions . filter ( e => ! areSameExtensions ( e . identifier , webExtension . identifier ) ) ;
497
- installedExtensions . push ( webExtension ) ;
502
+ installedExtensions = installedExtensions . filter ( installedExtension => webExtensions . some ( extension => ! areSameExtensions ( installedExtension . identifier , extension . identifier ) ) ) ;
503
+ installedExtensions . push ( ... webExtensions ) ;
498
504
return installedExtensions ;
499
505
} ) ;
500
506
}
501
507
502
- private async scanInstalledExtensions ( scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
503
- let installedExtensions = await this . readInstalledExtensions ( this . userDataProfileService . currentProfile ) ;
508
+ private async scanInstalledExtensions ( profile : IUserDataProfile , scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
509
+ let installedExtensions = await this . readInstalledExtensions ( profile ) ;
504
510
505
511
// If current profile is not a default profile, then add the application extensions to the list
506
- if ( ! this . userDataProfileService . currentProfile . isDefault ) {
512
+ if ( ! profile . isDefault ) {
507
513
// Remove application extensions from the non default profile
508
514
installedExtensions = installedExtensions . filter ( i => ! i . metadata ?. isApplicationScoped ) ;
509
515
// Add application extensions from the default profile to the list
@@ -830,6 +836,19 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
830
836
} ) ) ;
831
837
}
832
838
839
+ private async whenProfileChanged ( e : DidChangeUserDataProfileEvent ) : Promise < void > {
840
+ if ( e . preserveData ) {
841
+ const extensions = ( await this . readInstalledExtensions ( e . previous ) ) . filter ( e => ! e . metadata ?. isApplicationScoped ) ; /* remove application scoped extensions */
842
+ await this . addToInstalledExtensions ( extensions , e . profile ) ;
843
+ } else {
844
+ const oldExtensions = await this . scanInstalledExtensions ( e . previous ) ;
845
+ const newExtensions = await this . scanInstalledExtensions ( e . profile ) ;
846
+ const { added, removed } = delta ( oldExtensions , newExtensions , ( a , b ) => compare ( `${ ExtensionIdentifier . toKey ( a . identifier . id ) } @${ a . manifest . version } ` , `${ ExtensionIdentifier . toKey ( b . identifier . id ) } @${ b . manifest . version } ` ) ) ;
847
+ if ( added . length || removed . length ) {
848
+ this . _onDidChangeProfileExtensions . fire ( { added, removed } ) ;
849
+ }
850
+ }
851
+ }
833
852
}
834
853
835
854
registerSingleton ( IWebExtensionsScannerService , WebExtensionsScannerService ) ;
0 commit comments