3
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
- import { distinct , flatten } from 'vs/base/common/arrays' ;
6
+ import { distinct } from 'vs/base/common/arrays' ;
7
7
import { CancellationToken } from 'vs/base/common/cancellation' ;
8
8
import { canceled , getErrorMessage , isPromiseCanceledError } from 'vs/base/common/errors' ;
9
9
import { getOrDefault } from 'vs/base/common/objects' ;
10
10
import { IPager } from 'vs/base/common/paging' ;
11
11
import { isWeb } from 'vs/base/common/platform' ;
12
- import { equalsIgnoreCase } from 'vs/base/common/strings' ;
13
12
import { URI } from 'vs/base/common/uri' ;
14
13
import { IHeaders , IRequestContext , IRequestOptions } from 'vs/base/parts/request/common/request' ;
15
14
import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
16
- import { arePlatformsValid , CURRENT_TARGET_PLATFORM , DefaultIconPath , IExtensionGalleryService , IExtensionIdentifier , IExtensionIdentifierWithVersion , IGalleryExtension , IGalleryExtensionAsset , IGalleryExtensionAssets , IGalleryExtensionVersion , InstallOperation , IQueryOptions , IReportedExtension , isIExtensionIdentifier , ITranslation , SortBy , SortOrder , StatisticType , TargetPlatform , toTargetPlatform , WEB_EXTENSION_TAG } from 'vs/platform/extensionManagement/common/extensionManagement' ;
15
+ import { CURRENT_TARGET_PLATFORM , DefaultIconPath , IExtensionGalleryService , IExtensionIdentifier , IExtensionIdentifierWithVersion , IGalleryExtension , IGalleryExtensionAsset , IGalleryExtensionAssets , IGalleryExtensionVersion , InstallOperation , IQueryOptions , IReportedExtension , isIExtensionIdentifier , ITranslation , SortBy , SortOrder , StatisticType , TargetPlatform , toTargetPlatform , WEB_EXTENSION_TAG } from 'vs/platform/extensionManagement/common/extensionManagement' ;
17
16
import { adoptToGalleryExtensionId , areSameExtensions , getGalleryExtensionId , getGalleryExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil' ;
18
17
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions' ;
19
18
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator' ;
@@ -184,17 +183,6 @@ type GalleryServiceQueryEvent = QueryTelemetryData & {
184
183
readonly count ?: string ;
185
184
} ;
186
185
187
- const ANY_TARGET_PLATFORMS = Object . freeze ( [
188
- TargetPlatform . WIN32_X64 ,
189
- TargetPlatform . WIN32_IA32 ,
190
- TargetPlatform . WIN32_ARM64 ,
191
- TargetPlatform . LINUX_X64 ,
192
- TargetPlatform . LINUX_ARM64 ,
193
- TargetPlatform . LINUX_ARMHF ,
194
- TargetPlatform . DARWIN_X64 ,
195
- TargetPlatform . DARWIN_ARM64 ,
196
- ] ) ;
197
-
198
186
class Query {
199
187
200
188
constructor ( private state = DefaultQueryState ) { }
@@ -324,11 +312,75 @@ function getIsPreview(flags: string): boolean {
324
312
return flags . indexOf ( 'preview' ) !== - 1 ;
325
313
}
326
314
327
- function getTargetPlatforms ( version : IRawGalleryExtensionVersion ) : TargetPlatform [ ] {
328
- return version . targetPlatform && ! equalsIgnoreCase ( version . targetPlatform , 'universal' ) ? [ toTargetPlatform ( version . targetPlatform ) ] : [ ...ANY_TARGET_PLATFORMS ] ;
315
+ function getTargetPlatform ( version : IRawGalleryExtensionVersion ) : TargetPlatform {
316
+ return version . targetPlatform ? toTargetPlatform ( version . targetPlatform ) : TargetPlatform . UNIVERSAL ;
317
+ }
318
+
319
+ function getAllTargetPlatforms ( rawGalleryExtension : IRawGalleryExtension ) : TargetPlatform [ ] {
320
+ const allTargetPlatforms = distinct ( rawGalleryExtension . versions . map ( getTargetPlatform ) ) ;
321
+
322
+ // Is a web extension only if it has WEB_EXTENSION_TAG
323
+ const isWebExtension = ! ! rawGalleryExtension . tags ?. includes ( WEB_EXTENSION_TAG ) ;
324
+
325
+ // Include Web Target Platform only if it is a web extension
326
+ const webTargetPlatformIndex = allTargetPlatforms . indexOf ( TargetPlatform . WEB ) ;
327
+ if ( isWebExtension ) {
328
+ if ( webTargetPlatformIndex === - 1 ) {
329
+ // Web extension but does not has web target platform -> add it
330
+ allTargetPlatforms . push ( TargetPlatform . WEB ) ;
331
+ }
332
+ } else {
333
+ if ( webTargetPlatformIndex !== - 1 ) {
334
+ // Not a web extension but has web target platform -> remove it
335
+ allTargetPlatforms . splice ( webTargetPlatformIndex , 1 ) ;
336
+ }
337
+ }
338
+
339
+ return allTargetPlatforms ;
340
+ }
341
+
342
+ function isNotWebExtensionInWebTargetPlatform ( allTargetPlatforms : TargetPlatform [ ] , productTargetPlatform : TargetPlatform ) : boolean {
343
+ // Not a web extension in web target platform
344
+ return productTargetPlatform === TargetPlatform . WEB && ! allTargetPlatforms . includes ( TargetPlatform . WEB ) ;
345
+ }
346
+
347
+ function isTargetPlatformCompatible ( extensionTargetPlatform : TargetPlatform , allTargetPlatforms : TargetPlatform [ ] , productTargetPlatform : TargetPlatform ) : boolean {
348
+ // Not compatible when extension is not a web extension in web target platform
349
+ if ( isNotWebExtensionInWebTargetPlatform ( allTargetPlatforms , productTargetPlatform ) ) {
350
+ return false ;
351
+ }
352
+
353
+ // Compatible when extension target platform is universal
354
+ if ( extensionTargetPlatform === TargetPlatform . UNIVERSAL ) {
355
+ return true ;
356
+ }
357
+
358
+ // Not compatible when extension target platform is unknown
359
+ if ( extensionTargetPlatform === TargetPlatform . UNKNOWN ) {
360
+ return false ;
361
+ }
362
+
363
+ // Compatible when extension and product target platforms matches
364
+ if ( extensionTargetPlatform === productTargetPlatform ) {
365
+ return true ;
366
+ }
367
+
368
+ // Fallback
369
+ switch ( productTargetPlatform ) {
370
+ case TargetPlatform . WIN32_X64 : return extensionTargetPlatform === TargetPlatform . WIN32_IA32 ;
371
+ case TargetPlatform . WIN32_ARM64 : return extensionTargetPlatform === TargetPlatform . WIN32_IA32 ;
372
+ default : return false ;
373
+ }
374
+ }
375
+
376
+ function toExtensionWithLatestVersion ( galleryExtension : IRawGalleryExtension , index : number , query : Query , querySource ?: string ) : IGalleryExtension {
377
+ const allTargetPlatforms = getAllTargetPlatforms ( galleryExtension ) ;
378
+ let latestVersion = galleryExtension . versions [ 0 ] ;
379
+ latestVersion = galleryExtension . versions . find ( version => version . version === latestVersion . version && isTargetPlatformCompatible ( getTargetPlatform ( version ) , allTargetPlatforms , CURRENT_TARGET_PLATFORM ) ) || latestVersion ;
380
+ return toExtension ( galleryExtension , latestVersion , allTargetPlatforms , index , query , querySource ) ;
329
381
}
330
382
331
- function toExtension ( galleryExtension : IRawGalleryExtension , version : IRawGalleryExtensionVersion , index : number , query : Query , querySource ?: string ) : IGalleryExtension {
383
+ function toExtension ( galleryExtension : IRawGalleryExtension , version : IRawGalleryExtensionVersion , allTargetPlatforms : TargetPlatform [ ] , index : number , query : Query , querySource ?: string ) : IGalleryExtension {
332
384
const assets = < IGalleryExtensionAssets > {
333
385
manifest : getVersionAsset ( version , AssetType . Manifest ) ,
334
386
readme : getVersionAsset ( version , AssetType . Details ) ,
@@ -340,16 +392,6 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
340
392
coreTranslations : getCoreTranslationAssets ( version )
341
393
} ;
342
394
343
- const allTargetPlatforms = distinct ( flatten ( galleryExtension . versions . map ( getTargetPlatforms ) ) ) ;
344
- if ( galleryExtension . tags ?. includes ( WEB_EXTENSION_TAG ) && ! allTargetPlatforms . includes ( TargetPlatform . WEB ) ) {
345
- allTargetPlatforms . push ( TargetPlatform . WEB ) ;
346
- }
347
-
348
- const targetPlatforms = getTargetPlatforms ( version ) ;
349
- if ( allTargetPlatforms . includes ( TargetPlatform . WEB ) && ! targetPlatforms . includes ( TargetPlatform . WEB ) ) {
350
- targetPlatforms . push ( TargetPlatform . WEB ) ;
351
- }
352
-
353
395
return {
354
396
identifier : {
355
397
id : getGalleryExtensionId ( galleryExtension . publisher . publisherName , galleryExtension . extensionName ) ,
@@ -376,7 +418,7 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
376
418
extensionPack : getExtensions ( version , PropertyType . ExtensionPack ) ,
377
419
engine : getEngine ( version ) ,
378
420
localizedLanguages : getLocalizedLanguages ( version ) ,
379
- targetPlatforms ,
421
+ targetPlatform : getTargetPlatform ( version ) ,
380
422
} ,
381
423
preview : getIsPreview ( galleryExtension . flags ) ,
382
424
/* __GDPR__FRAGMENT__
@@ -392,11 +434,6 @@ function toExtension(galleryExtension: IRawGalleryExtension, version: IRawGaller
392
434
} ;
393
435
}
394
436
395
- function getLatestVersion ( versions : IRawGalleryExtensionVersion [ ] ) : IRawGalleryExtensionVersion {
396
- const latestVersion = versions [ 0 ] ;
397
- return versions . find ( v => v . version === latestVersion . version && arePlatformsValid ( getTargetPlatforms ( v ) , CURRENT_TARGET_PLATFORM ) ) || latestVersion ;
398
- }
399
-
400
437
interface IRawExtensionsReport {
401
438
malicious : string [ ] ;
402
439
slow : string [ ] ;
@@ -457,10 +494,10 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
457
494
if ( version ) {
458
495
const versionAsset = galleryExtension . versions . find ( v => v . version === version ) ;
459
496
if ( versionAsset ) {
460
- result . push ( toExtension ( galleryExtension , versionAsset , index , query ) ) ;
497
+ result . push ( toExtension ( galleryExtension , versionAsset , getAllTargetPlatforms ( galleryExtension ) , index , query ) ) ;
461
498
}
462
499
} else {
463
- result . push ( toExtension ( galleryExtension , getLatestVersion ( galleryExtension . versions ) , index , query ) ) ;
500
+ result . push ( toExtensionWithLatestVersion ( galleryExtension , index , query ) ) ;
464
501
}
465
502
}
466
503
@@ -469,8 +506,13 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
469
506
470
507
async getCompatibleExtension ( arg1 : IExtensionIdentifier | IGalleryExtension , targetPlatform : TargetPlatform ) : Promise < IGalleryExtension | null > {
471
508
const extension : IGalleryExtension | null = isIExtensionIdentifier ( arg1 ) ? null : arg1 ;
472
- if ( extension && extension . properties . engine && this . isCompatible ( extension . properties . engine , extension . properties . targetPlatforms , targetPlatform ) ) {
473
- return extension ;
509
+ if ( extension ) {
510
+ if ( isNotWebExtensionInWebTargetPlatform ( extension . allTargetPlatforms , targetPlatform ) ) {
511
+ return null ;
512
+ }
513
+ if ( await this . isExtensionCompatible ( extension , targetPlatform ) ) {
514
+ return extension ;
515
+ }
474
516
}
475
517
const { id, uuid } = extension ? extension . identifier : < IExtensionIdentifier > arg1 ;
476
518
let query = new Query ( )
@@ -490,14 +532,33 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
490
532
return null ;
491
533
}
492
534
493
- const rawVersion = await this . getLastValidExtensionVersion ( rawExtension , rawExtension . versions , targetPlatform ) ;
494
- if ( rawVersion ) {
495
- return toExtension ( rawExtension , rawVersion , 0 , query ) ;
535
+ const allTargetPlatforms = getAllTargetPlatforms ( rawExtension ) ;
536
+ if ( isNotWebExtensionInWebTargetPlatform ( allTargetPlatforms , targetPlatform ) ) {
537
+ return null ;
496
538
}
539
+
540
+ for ( let rawVersion of rawExtension . versions ) {
541
+ // set engine property if does not exist
542
+ if ( ! getEngine ( rawVersion ) ) {
543
+ const engine = await this . getEngine ( rawVersion ) ;
544
+ rawVersion = {
545
+ ...rawVersion ,
546
+ properties : [ ...( rawVersion . properties || [ ] ) , { key : PropertyType . Engine , value : engine } ]
547
+ } ;
548
+ }
549
+ if ( await this . isRawExtensionVersionCompatible ( rawVersion , allTargetPlatforms , targetPlatform ) ) {
550
+ return toExtension ( rawExtension , rawVersion , allTargetPlatforms , 0 , query ) ;
551
+ }
552
+ }
553
+
497
554
return null ;
498
555
}
499
556
500
557
async isExtensionCompatible ( extension : IGalleryExtension , targetPlatform : TargetPlatform ) : Promise < boolean > {
558
+ if ( ! isTargetPlatformCompatible ( extension . properties . targetPlatform , extension . allTargetPlatforms , targetPlatform ) ) {
559
+ return false ;
560
+ }
561
+
501
562
let engine = extension . properties . engine ;
502
563
if ( ! engine ) {
503
564
const manifest = await this . getManifest ( extension , CancellationToken . None ) ;
@@ -506,7 +567,16 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
506
567
}
507
568
engine = manifest . engines . vscode ;
508
569
}
509
- return this . isCompatible ( engine , extension . properties . targetPlatforms , targetPlatform ) ;
570
+ return isEngineValid ( engine , this . productService . version , this . productService . date ) ;
571
+ }
572
+
573
+ private async isRawExtensionVersionCompatible ( rawExtensionVersion : IRawGalleryExtensionVersion , allTargetPlatforms : TargetPlatform [ ] , targetPlatform : TargetPlatform ) : Promise < boolean > {
574
+ if ( ! isTargetPlatformCompatible ( getTargetPlatform ( rawExtensionVersion ) , allTargetPlatforms , targetPlatform ) ) {
575
+ return false ;
576
+ }
577
+
578
+ const engine = await this . getEngine ( rawExtensionVersion ) ;
579
+ return isEngineValid ( engine , this . productService . version , this . productService . date ) ;
510
580
}
511
581
512
582
query ( token : CancellationToken ) : Promise < IPager < IGalleryExtension > > ;
@@ -571,14 +641,14 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
571
641
}
572
642
573
643
const { galleryExtensions, total } = await this . queryGallery ( query , token ) ;
574
- const extensions = galleryExtensions . map ( ( e , index ) => toExtension ( e , getLatestVersion ( e . versions ) , index , query , options . source ) ) ;
644
+ const extensions = galleryExtensions . map ( ( e , index ) => toExtensionWithLatestVersion ( e , index , query , options . source ) ) ;
575
645
const getPage = async ( pageIndex : number , ct : CancellationToken ) => {
576
646
if ( ct . isCancellationRequested ) {
577
647
throw canceled ( ) ;
578
648
}
579
649
const nextPageQuery = query . withPage ( pageIndex + 1 ) ;
580
650
const { galleryExtensions } = await this . queryGallery ( nextPageQuery , ct ) ;
581
- return galleryExtensions . map ( ( e , index ) => toExtension ( e , getLatestVersion ( e . versions ) , index , nextPageQuery , options . source ) ) ;
651
+ return galleryExtensions . map ( ( e , index ) => toExtensionWithLatestVersion ( e , index , nextPageQuery , options . source ) ) ;
582
652
} ;
583
653
584
654
return { firstPage : extensions , total, pageSize : query . pageSize , getPage } as IPager < IGalleryExtension > ;
@@ -711,6 +781,16 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
711
781
return null ;
712
782
}
713
783
784
+ private async getManifestFromRawExtensionVersion ( rawExtensionVersion : IRawGalleryExtensionVersion , token : CancellationToken ) : Promise < IExtensionManifest | null > {
785
+ const manifestAsset = getVersionAsset ( rawExtensionVersion , AssetType . Manifest ) ;
786
+ if ( ! manifestAsset ) {
787
+ throw new Error ( 'Manifest was not found' ) ;
788
+ }
789
+ const headers = { 'Accept-Encoding' : 'gzip' } ;
790
+ const context = await this . getAsset ( manifestAsset , { headers } ) ;
791
+ return await asJson < IExtensionManifest > ( context ) ;
792
+ }
793
+
714
794
async getCoreTranslation ( extension : IGalleryExtension , languageId : string ) : Promise < ITranslation | null > {
715
795
const asset = extension . assets . coreTranslations . filter ( t => t [ 0 ] === languageId . toUpperCase ( ) ) [ 0 ] ;
716
796
if ( asset ) {
@@ -742,17 +822,23 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
742
822
query = query . withFilter ( FilterType . ExtensionName , extension . identifier . id ) ;
743
823
}
744
824
745
- const result : IGalleryExtensionVersion [ ] = [ ] ;
746
825
const { galleryExtensions } = await this . queryGallery ( query , CancellationToken . None ) ;
747
- if ( galleryExtensions . length ) {
748
- await Promise . all ( galleryExtensions [ 0 ] . versions . map ( async v => {
749
- try {
750
- const engine = await this . getEngine ( v ) ;
751
- if ( this . isCompatible ( engine , getTargetPlatforms ( v ) , targetPlatform ) ) {
752
- result . push ( { version : v ! . version , date : v ! . lastUpdated } ) ;
753
- }
754
- } catch ( error ) { /* Ignore error and skip version */ }
755
- } ) ) ;
826
+ if ( ! galleryExtensions . length ) {
827
+ return [ ] ;
828
+ }
829
+
830
+ const allTargetPlatforms = getAllTargetPlatforms ( galleryExtensions [ 0 ] ) ;
831
+ if ( isNotWebExtensionInWebTargetPlatform ( allTargetPlatforms , targetPlatform ) ) {
832
+ return [ ] ;
833
+ }
834
+
835
+ const result : IGalleryExtensionVersion [ ] = [ ] ;
836
+ for ( const version of galleryExtensions [ 0 ] . versions ) {
837
+ try {
838
+ if ( await this . isRawExtensionVersionCompatible ( version , allTargetPlatforms , targetPlatform ) ) {
839
+ result . push ( { version : version ! . version , date : version ! . lastUpdated } ) ;
840
+ }
841
+ } catch ( error ) { /* Ignore error and skip version */ }
756
842
}
757
843
return result ;
758
844
}
@@ -795,67 +881,16 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
795
881
}
796
882
}
797
883
798
- private async getLastValidExtensionVersion ( extension : IRawGalleryExtension , versions : IRawGalleryExtensionVersion [ ] , targetPlatform : TargetPlatform ) : Promise < IRawGalleryExtensionVersion | null > {
799
- const version = this . getLastValidExtensionVersionFromProperties ( extension , versions , targetPlatform ) ;
800
- if ( version ) {
801
- return version ;
802
- }
803
- return this . getLastValidExtensionVersionRecursively ( extension , versions , targetPlatform ) ;
804
- }
805
-
806
- private getLastValidExtensionVersionFromProperties ( extension : IRawGalleryExtension , versions : IRawGalleryExtensionVersion [ ] , targetPlatform : TargetPlatform ) : IRawGalleryExtensionVersion | null {
807
- for ( const version of versions ) {
808
- const engine = getEngine ( version ) ;
809
- if ( ! engine ) {
810
- return null ;
811
- }
812
- if ( this . isCompatible ( engine , getTargetPlatforms ( version ) , targetPlatform ) ) {
813
- return version ;
884
+ private async getEngine ( rawExtensionVersion : IRawGalleryExtensionVersion ) : Promise < string > {
885
+ let engine = getEngine ( rawExtensionVersion ) ;
886
+ if ( ! engine ) {
887
+ const manifest = await this . getManifestFromRawExtensionVersion ( rawExtensionVersion , CancellationToken . None ) ;
888
+ if ( ! manifest ) {
889
+ throw new Error ( 'Manifest was not found' ) ;
814
890
}
891
+ engine = manifest . engines . vscode ;
815
892
}
816
- return null ;
817
- }
818
-
819
- private async getEngine ( version : IRawGalleryExtensionVersion ) : Promise < string > {
820
- const engine = getEngine ( version ) ;
821
- if ( engine ) {
822
- return engine ;
823
- }
824
-
825
- const manifestAsset = getVersionAsset ( version , AssetType . Manifest ) ;
826
- if ( ! manifestAsset ) {
827
- throw new Error ( 'Manifest was not found' ) ;
828
- }
829
-
830
- const headers = { 'Accept-Encoding' : 'gzip' } ;
831
- const context = await this . getAsset ( manifestAsset , { headers } ) ;
832
- const manifest = await asJson < IExtensionManifest > ( context ) ;
833
- if ( manifest ) {
834
- return manifest . engines . vscode ;
835
- }
836
-
837
- throw new Error ( 'Error while reading manifest' ) ;
838
- }
839
-
840
- private async getLastValidExtensionVersionRecursively ( extension : IRawGalleryExtension , versions : IRawGalleryExtensionVersion [ ] , targetPlatform : TargetPlatform ) : Promise < IRawGalleryExtensionVersion | null > {
841
- if ( ! versions . length ) {
842
- return null ;
843
- }
844
-
845
- const version = versions [ 0 ] ;
846
- const engine = await this . getEngine ( version ) ;
847
- if ( ! this . isCompatible ( engine , getTargetPlatforms ( version ) , targetPlatform ) ) {
848
- return this . getLastValidExtensionVersionRecursively ( extension , versions . slice ( 1 ) , targetPlatform ) ;
849
- }
850
-
851
- return {
852
- ...version ,
853
- properties : [ ...( version . properties || [ ] ) , { key : PropertyType . Engine , value : engine } ]
854
- } ;
855
- }
856
-
857
- private isCompatible ( engine : string , targetPlatforms : TargetPlatform [ ] , targetPlatform : TargetPlatform ) : boolean {
858
- return isEngineValid ( engine , this . productService . version , this . productService . date ) && arePlatformsValid ( targetPlatforms , targetPlatform ) ;
893
+ return engine ;
859
894
}
860
895
861
896
async getExtensionsReport ( ) : Promise < IReportedExtension [ ] > {
0 commit comments