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 , ExtensionIdentifier } from 'vs/platform/extensions/common/extensions' ;
6
+ import { IBuiltinExtensionsScannerService , ExtensionType , IExtensionIdentifier , IExtension , IExtensionManifest , TargetPlatform } 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,17 +33,16 @@ 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 { delta , isNonEmptyArray } from 'vs/base/common/arrays' ;
36
+ import { 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 { DidChangeUserDataProfileEvent , IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' ;
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' ;
43
+ import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/common/userDataProfile' ;
44
+ import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile' ;
45
+ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity' ;
47
46
48
47
type GalleryExtensionInfo = { readonly id : string ; preRelease ?: boolean ; migrateStorageFrom ?: string } ;
49
48
type ExtensionInfo = { readonly id : string ; preRelease : boolean } ;
@@ -89,9 +88,6 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
89
88
private readonly customBuiltinExtensionsCacheResource : URI | undefined = undefined ;
90
89
private readonly resourcesAccessQueueMap = new ResourceMap < Queue < IWebExtension [ ] > > ( ) ;
91
90
92
- private readonly _onDidChangeProfileExtensions = this . _register ( new Emitter < { readonly added : IScannedExtension [ ] ; readonly removed : IScannedExtension [ ] } > ( ) ) ;
93
- readonly onDidChangeProfileExtensions = this . _onDidChangeProfileExtensions . event ;
94
-
95
91
constructor (
96
92
@IBrowserWorkbenchEnvironmentService private readonly environmentService : IBrowserWorkbenchEnvironmentService ,
97
93
@IBuiltinExtensionsScannerService private readonly builtinExtensionsScannerService : IBuiltinExtensionsScannerService ,
@@ -103,8 +99,8 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
103
99
@IExtensionStorageService private readonly extensionStorageService : IExtensionStorageService ,
104
100
@IStorageService private readonly storageService : IStorageService ,
105
101
@IProductService private readonly productService : IProductService ,
106
- @IUserDataProfileService private readonly userDataProfileService : IUserDataProfileService ,
107
102
@IUserDataProfilesService private readonly userDataProfilesService : IUserDataProfilesService ,
103
+ @IUriIdentityService private readonly uriIdentityService : IUriIdentityService ,
108
104
@ILifecycleService lifecycleService : ILifecycleService ,
109
105
) {
110
106
super ( ) ;
@@ -115,7 +111,6 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
115
111
116
112
// Eventually update caches
117
113
lifecycleService . when ( LifecyclePhase . Eventually ) . then ( ( ) => this . updateCaches ( ) ) ;
118
- this . _register ( userDataProfileService . onDidChangeCurrentProfile ( e => e . join ( this . whenProfileChanged ( e ) ) ) ) ;
119
114
}
120
115
}
121
116
@@ -377,7 +372,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
377
372
return this . readSystemExtensions ( ) ;
378
373
}
379
374
380
- async scanUserExtensions ( scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
375
+ async scanUserExtensions ( profileLocation ?: URI , scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
381
376
const extensions = new Map < string , IScannedExtension > ( ) ;
382
377
383
378
// Custom builtin extensions defined through `additionalBuiltinExtensions` API
@@ -387,7 +382,7 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
387
382
}
388
383
389
384
// User Installed extensions
390
- const installedExtensions = await this . scanInstalledExtensions ( this . userDataProfileService . currentProfile , scanOptions ) ;
385
+ const installedExtensions = await this . scanInstalledExtensions ( profileLocation , scanOptions ) ;
391
386
for ( const extension of installedExtensions ) {
392
387
extensions . set ( extension . identifier . id . toLowerCase ( ) , extension ) ;
393
388
}
@@ -416,17 +411,17 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
416
411
return result ;
417
412
}
418
413
419
- async scanExistingExtension ( extensionLocation : URI , extensionType : ExtensionType ) : Promise < IScannedExtension | null > {
414
+ async scanExistingExtension ( extensionLocation : URI , extensionType : ExtensionType , profileLocation ?: URI ) : Promise < IScannedExtension | null > {
420
415
if ( extensionType === ExtensionType . System ) {
421
416
const systemExtensions = await this . scanSystemExtensions ( ) ;
422
417
return systemExtensions . find ( e => e . location . toString ( ) === extensionLocation . toString ( ) ) || null ;
423
418
}
424
- const userExtensions = await this . scanUserExtensions ( ) ;
419
+ const userExtensions = await this . scanUserExtensions ( profileLocation ) ;
425
420
return userExtensions . find ( e => e . location . toString ( ) === extensionLocation . toString ( ) ) || null ;
426
421
}
427
422
428
- async scanMetadata ( extensionLocation : URI ) : Promise < Metadata | undefined > {
429
- const extension = await this . scanExistingExtension ( extensionLocation , ExtensionType . User ) ;
423
+ async scanMetadata ( extensionLocation : URI , profileLocation ?: URI ) : Promise < Metadata | undefined > {
424
+ const extension = await this . scanExistingExtension ( extensionLocation , ExtensionType . User , profileLocation ) ;
430
425
return extension ?. metadata ;
431
426
}
432
427
@@ -443,26 +438,38 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
443
438
return null ;
444
439
}
445
440
446
- async addExtensionFromGallery ( galleryExtension : IGalleryExtension , metadata ? : Metadata ) : Promise < IScannedExtension > {
441
+ async addExtensionFromGallery ( galleryExtension : IGalleryExtension , metadata : Metadata , profileLocation ?: URI ) : Promise < IScannedExtension > {
447
442
const webExtension = await this . toWebExtensionFromGallery ( galleryExtension , metadata ) ;
448
- return this . addWebExtension ( webExtension ) ;
443
+ return this . addWebExtension ( webExtension , profileLocation ) ;
449
444
}
450
445
451
- async addExtension ( location : URI , metadata ? : Metadata ) : Promise < IScannedExtension > {
446
+ async addExtension ( location : URI , metadata : Metadata , profileLocation ?: URI ) : Promise < IScannedExtension > {
452
447
const webExtension = await this . toWebExtension ( location , undefined , undefined , undefined , undefined , undefined , metadata ) ;
453
- return this . addWebExtension ( webExtension ) ;
448
+ return this . addWebExtension ( webExtension , profileLocation ) ;
454
449
}
455
450
456
- async removeExtension ( extension : IScannedExtension ) : Promise < void > {
457
- const profile = extension . metadata ?. isApplicationScoped ? this . userDataProfilesService . defaultProfile : this . userDataProfileService . currentProfile ;
458
- await this . writeInstalledExtensions ( profile , installedExtensions => installedExtensions . filter ( installedExtension => ! areSameExtensions ( installedExtension . identifier , extension . identifier ) ) ) ;
451
+ async removeExtension ( extension : IScannedExtension , profileLocation ?: URI ) : Promise < void > {
452
+ await this . writeInstalledExtensions ( profileLocation , installedExtensions => installedExtensions . filter ( installedExtension => ! areSameExtensions ( installedExtension . identifier , extension . identifier ) ) ) ;
459
453
}
460
454
461
- private async addWebExtension ( webExtension : IWebExtension ) : Promise < IScannedExtension > {
455
+ async copyExtensions ( fromProfileLocation : URI , toProfileLocation : URI , filter : ( extension : IScannedExtension ) => boolean ) : Promise < void > {
456
+ const extensionsToCopy : IWebExtension [ ] = [ ] ;
457
+ const fromWebExtensions = await this . readInstalledExtensions ( fromProfileLocation ) ;
458
+ await Promise . all ( fromWebExtensions . map ( async webExtension => {
459
+ const scannedExtension = await this . toScannedExtension ( webExtension , false ) ;
460
+ if ( filter ( scannedExtension ) ) {
461
+ extensionsToCopy . push ( webExtension ) ;
462
+ }
463
+ } ) ) ;
464
+ if ( extensionsToCopy . length ) {
465
+ await this . addToInstalledExtensions ( extensionsToCopy , toProfileLocation ) ;
466
+ }
467
+ }
468
+
469
+ private async addWebExtension ( webExtension : IWebExtension , profileLocation ?: URI ) : Promise < IScannedExtension > {
462
470
const isSystem = ! ! ( await this . scanSystemExtensions ( ) ) . find ( e => areSameExtensions ( e . identifier , webExtension . identifier ) ) ;
463
471
const isBuiltin = ! ! webExtension . metadata ?. isBuiltin ;
464
472
const extension = await this . toScannedExtension ( webExtension , isBuiltin ) ;
465
- const profile = webExtension . metadata ?. isApplicationScoped ? this . userDataProfilesService . defaultProfile : this . userDataProfileService . currentProfile ;
466
473
467
474
if ( isSystem ) {
468
475
await this . writeSystemExtensionsCache ( systemExtensions => {
@@ -483,37 +490,37 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
483
490
return customBuiltinExtensions ;
484
491
} ) ;
485
492
486
- const installedExtensions = await this . readInstalledExtensions ( profile ) ;
493
+ const installedExtensions = await this . readInstalledExtensions ( profileLocation ) ;
487
494
// Also add to installed extensions if it is installed to update its version
488
495
if ( installedExtensions . some ( e => areSameExtensions ( e . identifier , webExtension . identifier ) ) ) {
489
- await this . addToInstalledExtensions ( [ webExtension ] , profile ) ;
496
+ await this . addToInstalledExtensions ( [ webExtension ] , profileLocation ) ;
490
497
}
491
498
return extension ;
492
499
}
493
500
494
501
// Add to installed extensions
495
- await this . addToInstalledExtensions ( [ webExtension ] , profile ) ;
502
+ await this . addToInstalledExtensions ( [ webExtension ] , profileLocation ) ;
496
503
return extension ;
497
504
}
498
505
499
- private async addToInstalledExtensions ( webExtensions : IWebExtension [ ] , profile : IUserDataProfile ) : Promise < void > {
500
- await this . writeInstalledExtensions ( profile , installedExtensions => {
506
+ private async addToInstalledExtensions ( webExtensions : IWebExtension [ ] , profileLocation ?: URI ) : Promise < void > {
507
+ await this . writeInstalledExtensions ( profileLocation , installedExtensions => {
501
508
// Remove the existing extension to avoid duplicates
502
509
installedExtensions = installedExtensions . filter ( installedExtension => webExtensions . some ( extension => ! areSameExtensions ( installedExtension . identifier , extension . identifier ) ) ) ;
503
510
installedExtensions . push ( ...webExtensions ) ;
504
511
return installedExtensions ;
505
512
} ) ;
506
513
}
507
514
508
- private async scanInstalledExtensions ( profile : IUserDataProfile , scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
509
- let installedExtensions = await this . readInstalledExtensions ( profile ) ;
515
+ private async scanInstalledExtensions ( profileLocation ?: URI , scanOptions ?: ScanOptions ) : Promise < IScannedExtension [ ] > {
516
+ let installedExtensions = await this . readInstalledExtensions ( profileLocation ) ;
510
517
511
518
// If current profile is not a default profile, then add the application extensions to the list
512
- if ( ! profile . isDefault ) {
519
+ if ( this . userDataProfilesService . defaultProfile . extensionsResource && ! this . uriIdentityService . extUri . isEqual ( profileLocation , this . userDataProfilesService . defaultProfile . extensionsResource ) ) {
513
520
// Remove application extensions from the non default profile
514
521
installedExtensions = installedExtensions . filter ( i => ! i . metadata ?. isApplicationScoped ) ;
515
522
// Add application extensions from the default profile to the list
516
- const defaultProfileExtensions = await this . readInstalledExtensions ( this . userDataProfilesService . defaultProfile ) ;
523
+ const defaultProfileExtensions = await this . readInstalledExtensions ( this . userDataProfilesService . defaultProfile . extensionsResource ) ;
517
524
installedExtensions . push ( ...defaultProfileExtensions . filter ( i => i . metadata ?. isApplicationScoped ) ) ;
518
525
}
519
526
@@ -713,15 +720,15 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
713
720
return this . _migratePackageNLSUrisPromise ;
714
721
}
715
722
716
- private async readInstalledExtensions ( profile : IUserDataProfile ) : Promise < IWebExtension [ ] > {
717
- if ( profile . isDefault ) {
723
+ private async readInstalledExtensions ( profileLocation ?: URI ) : Promise < IWebExtension [ ] > {
724
+ if ( this . uriIdentityService . extUri . isEqual ( profileLocation , this . userDataProfilesService . defaultProfile . extensionsResource ) ) {
718
725
await this . migratePackageNLSUris ( ) ;
719
726
}
720
- return this . withWebExtensions ( profile . extensionsResource ) ;
727
+ return this . withWebExtensions ( profileLocation ) ;
721
728
}
722
729
723
- private writeInstalledExtensions ( profile : IUserDataProfile , updateFn : ( extensions : IWebExtension [ ] ) => IWebExtension [ ] ) : Promise < IWebExtension [ ] > {
724
- return this . withWebExtensions ( profile . extensionsResource , updateFn ) ;
730
+ private writeInstalledExtensions ( profileLocation : URI | undefined , updateFn : ( extensions : IWebExtension [ ] ) => IWebExtension [ ] ) : Promise < IWebExtension [ ] > {
731
+ return this . withWebExtensions ( profileLocation , updateFn ) ;
725
732
}
726
733
727
734
private readCustomBuiltinExtensionsCache ( ) : Promise < IWebExtension [ ] > {
@@ -819,7 +826,6 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
819
826
}
820
827
821
828
private registerActions ( ) : void {
822
- const that = this ;
823
829
this . _register ( registerAction2 ( class extends Action2 {
824
830
constructor ( ) {
825
831
super ( {
@@ -831,24 +837,13 @@ export class WebExtensionsScannerService extends Disposable implements IWebExten
831
837
} ) ;
832
838
}
833
839
run ( serviceAccessor : ServicesAccessor ) : void {
834
- serviceAccessor . get ( IEditorService ) . openEditor ( { resource : that . userDataProfileService . currentProfile . extensionsResource } ) ;
840
+ const editorService = serviceAccessor . get ( IEditorService ) ;
841
+ const userDataProfileService = serviceAccessor . get ( IUserDataProfileService ) ;
842
+ editorService . openEditor ( { resource : userDataProfileService . currentProfile . extensionsResource } ) ;
835
843
}
836
844
} ) ) ;
837
845
}
838
846
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
- }
852
847
}
853
848
854
849
registerSingleton ( IWebExtensionsScannerService , WebExtensionsScannerService ) ;
0 commit comments