@@ -3,7 +3,6 @@ import { nls } from '@theia/core/lib/common/nls';
33import { notEmpty } from '@theia/core/lib/common/objects' ;
44import { inject , injectable } from '@theia/core/shared/inversify' ;
55import {
6- Board ,
76 BoardDetails ,
87 BoardSearch ,
98 BoardUserField ,
@@ -32,11 +31,9 @@ import {
3231 BoardListAllResponse ,
3332 BoardSearchRequest ,
3433} from './cli-protocol/cc/arduino/cli/commands/v1/board_pb' ;
35- import { Platform } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb' ;
34+ import { PlatformSummary } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb' ;
3635import {
3736 PlatformInstallRequest ,
38- PlatformListRequest ,
39- PlatformListResponse ,
4037 PlatformSearchRequest ,
4138 PlatformSearchResponse ,
4239 PlatformUninstallRequest ,
@@ -247,24 +244,22 @@ export class BoardsServiceImpl
247244
248245 async getInstalledPlatforms ( ) : Promise < BoardsPackage [ ] > {
249246 const { instance, client } = await this . coreClient ;
250- return new Promise < BoardsPackage [ ] > ( ( resolve , reject ) => {
251- client . platformList (
252- new PlatformListRequest ( ) . setInstance ( instance ) ,
253- ( err , response ) => {
254- if ( err ) {
255- reject ( err ) ;
256- return ;
257- }
258- resolve (
259- response
260- . getInstalledPlatformsList ( )
261- . map ( ( platform , _ , installedPlatforms ) =>
262- toBoardsPackage ( platform , installedPlatforms )
263- )
264- ) ;
265- }
266- ) ;
267- } ) ;
247+ const resp = await new Promise < PlatformSearchResponse > (
248+ ( resolve , reject ) => {
249+ client . platformSearch (
250+ new PlatformSearchRequest ( )
251+ . setInstance ( instance )
252+ . setManuallyInstalled ( true ) , // include core manually installed to the sketchbook
253+ ( err , resp ) => ( err ? reject ( err ) : resolve ( resp ) )
254+ ) ;
255+ }
256+ ) ;
257+ const searchOutput = resp . getSearchOutputList ( ) ;
258+ return searchOutput
259+ . map ( ( message ) => message . toObject ( false ) )
260+ . filter ( ( summary ) => summary . installedVersion ) // only installed ones
261+ . map ( createBoardsPackage )
262+ . filter ( notEmpty ) ;
268263 }
269264
270265 private async handleListBoards (
@@ -287,12 +282,28 @@ export class BoardsServiceImpl
287282 for ( const board of resp . getBoardsList ( ) ) {
288283 const platform = board . getPlatform ( ) ;
289284 if ( platform ) {
290- const platformId = platform . getId ( ) ;
285+ const metadata = platform . getMetadata ( ) ;
286+ if ( ! metadata ) {
287+ console . warn (
288+ `Platform metadata is missing for platform: ${ JSON . stringify (
289+ platform . toObject ( false )
290+ ) } . Skipping`
291+ ) ;
292+ continue ;
293+ }
294+ const platformId = metadata . getId ( ) ;
295+ const release = platform . getRelease ( ) ;
296+ if ( ! release ) {
297+ console . warn (
298+ `Platform release is missing for platform: ${ platformId } . Skipping`
299+ ) ;
300+ continue ;
301+ }
291302 const fqbn = board . getFqbn ( ) || undefined ; // prefer undefined over empty string
292303 const parsedPlatformId = createPlatformIdentifier ( platformId ) ;
293304 if ( ! parsedPlatformId ) {
294305 console . warn (
295- `Could not create platform identifier from platform ID input: ${ platform . getId ( ) } . Skipping`
306+ `Could not create platform identifier from platform ID input: ${ platformId } . Skipping`
296307 ) ;
297308 continue ;
298309 }
@@ -319,8 +330,8 @@ export class BoardsServiceImpl
319330 name : board . getName ( ) ,
320331 fqbn : board . getFqbn ( ) ,
321332 packageId : parsedPlatformId ,
322- packageName : platform . getName ( ) ,
323- manuallyInstalled : platform . getManuallyInstalled ( ) ,
333+ packageName : release . getName ( ) ,
334+ manuallyInstalled : metadata . getManuallyInstalled ( ) ,
324335 } ) ;
325336 }
326337 }
@@ -375,89 +386,25 @@ export class BoardsServiceImpl
375386 const coreClient = await this . coreClient ;
376387 const { client, instance } = coreClient ;
377388
378- const installedPlatformsReq = new PlatformListRequest ( ) ;
379- installedPlatformsReq . setInstance ( instance ) ;
380- const installedPlatformsResp = await new Promise < PlatformListResponse > (
381- ( resolve , reject ) => {
382- client . platformList ( installedPlatformsReq , ( err , resp ) => {
383- ! ! err ? reject ( err ) : resolve ( resp ) ;
384- } ) ;
385- }
386- ) ;
387- const installedPlatforms =
388- installedPlatformsResp . getInstalledPlatformsList ( ) ;
389-
390- const req = new PlatformSearchRequest ( ) ;
391- req . setSearchArgs ( options . query || '' ) ;
392- req . setAllVersions ( true ) ;
393- req . setInstance ( instance ) ;
389+ // `core search` returns with all platform versions when the command is executed via gRPC or with `--format json`
390+ // The `--all` flag is applicable only when filtering for the human-readable (`--format text`) output of the CLI
394391 const resp = await new Promise < PlatformSearchResponse > (
395392 ( resolve , reject ) => {
396- client . platformSearch ( req , ( err , resp ) => {
397- ! ! err ? reject ( err ) : resolve ( resp ) ;
398- } ) ;
393+ client . platformSearch (
394+ new PlatformSearchRequest ( )
395+ . setInstance ( instance )
396+ . setSearchArgs ( options . query ?? '' ) ,
397+ ( err , resp ) => ( err ? reject ( err ) : resolve ( resp ) )
398+ ) ;
399399 }
400400 ) ;
401- const packages = new Map < string , BoardsPackage > ( ) ;
402- // We must group the cores by ID, and sort platforms by, first the installed version, then version alphabetical order.
403- // Otherwise we lose the FQBN information.
404- const groupedById : Map < string , Platform [ ] > = new Map ( ) ;
405- for ( const platform of resp . getSearchOutputList ( ) ) {
406- const id = platform . getId ( ) ;
407- const idGroup = groupedById . get ( id ) ;
408- if ( idGroup ) {
409- idGroup . push ( platform ) ;
410- } else {
411- groupedById . set ( id , [ platform ] ) ;
412- }
413- }
414- const installedAwareVersionComparator = (
415- left : Platform ,
416- right : Platform
417- ) => {
418- // XXX: we cannot rely on `platform.getInstalled()`, it is always an empty string.
419- const leftInstalled = ! ! installedPlatforms . find (
420- ( ip ) =>
421- ip . getId ( ) === left . getId ( ) && ip . getInstalled ( ) === left . getLatest ( )
422- ) ;
423- const rightInstalled = ! ! installedPlatforms . find (
424- ( ip ) =>
425- ip . getId ( ) === right . getId ( ) &&
426- ip . getInstalled ( ) === right . getLatest ( )
427- ) ;
428- if ( leftInstalled && ! rightInstalled ) {
429- return - 1 ;
430- }
431- if ( ! leftInstalled && rightInstalled ) {
432- return 1 ;
433- }
434-
435- const invertedVersionComparator =
436- Installable . Version . COMPARATOR ( left . getLatest ( ) , right . getLatest ( ) ) *
437- - 1 ;
438- // Higher version comes first.
439-
440- return invertedVersionComparator ;
441- } ;
442- for ( const value of groupedById . values ( ) ) {
443- value . sort ( installedAwareVersionComparator ) ;
444- }
445-
446- for ( const value of groupedById . values ( ) ) {
447- for ( const platform of value ) {
448- const id = platform . getId ( ) ;
449- const pkg = packages . get ( id ) ;
450- if ( pkg ) {
451- pkg . availableVersions . push ( platform . getLatest ( ) ) ;
452- pkg . availableVersions . sort ( Installable . Version . COMPARATOR ) . reverse ( ) ;
453- } else {
454- packages . set ( id , toBoardsPackage ( platform , installedPlatforms ) ) ;
455- }
456- }
457- }
458-
459- const filter = this . typePredicate ( options ) ;
460- const boardsPackages = [ ...packages . values ( ) ] . filter ( filter ) ;
401+ const typeFilter = this . typePredicate ( options ) ;
402+ const searchOutput = resp . getSearchOutputList ( ) ;
403+ const boardsPackages = searchOutput
404+ . map ( ( message ) => message . toObject ( false ) )
405+ . map ( createBoardsPackage )
406+ . filter ( notEmpty )
407+ . filter ( typeFilter ) ;
461408 return sortComponents ( boardsPackages , boardsPackageSortGroup ) ;
462409 }
463410
@@ -624,36 +571,45 @@ function boardsPackageSortGroup(boardsPackage: BoardsPackage): SortGroup {
624571 return types . join ( '-' ) as SortGroup ;
625572}
626573
627- function toBoardsPackage (
628- platform : Platform ,
629- installedPlatforms : Platform [ ]
630- ) : BoardsPackage {
631- let installedVersion : string | undefined ;
632- const matchingPlatform = installedPlatforms . find (
633- ( ip ) => ip . getId ( ) === platform . getId ( )
634- ) ;
635- if ( ! ! matchingPlatform ) {
636- installedVersion = matchingPlatform . getInstalled ( ) ;
574+ function createBoardsPackage (
575+ summary : PlatformSummary . AsObject
576+ ) : BoardsPackage | undefined {
577+ if ( ! isPlatformSummaryWithMetadata ( summary ) ) {
578+ return undefined ;
579+ }
580+ const versionReleaseMap = new Map ( summary . releasesMap ) ;
581+ const actualRelease =
582+ versionReleaseMap . get ( summary . installedVersion ) ??
583+ versionReleaseMap . get ( summary . latestVersion ) ;
584+ if ( ! actualRelease ) {
585+ return undefined ;
586+ }
587+ const { name, typeList, boardsList, deprecated, compatible } = actualRelease ;
588+ if ( ! compatible ) {
589+ return undefined ; // never show incompatible platforms
637590 }
591+ const { id, website, maintainer } = summary . metadata ;
638592 return {
639- id : platform . getId ( ) ,
640- name : platform . getName ( ) ,
641- author : platform . getMaintainer ( ) ,
642- availableVersions : [ platform . getLatest ( ) ] ,
643- description : platform
644- . getBoardsList ( )
645- . map ( ( b ) => b . getName ( ) )
646- . join ( ', ' ) ,
647- types : platform . getTypeList ( ) ,
648- deprecated : platform . getDeprecated ( ) ,
593+ id,
594+ name,
649595 summary : nls . localize (
650596 'arduino/component/boardsIncluded' ,
651597 'Boards included in this package:'
652598 ) ,
653- installedVersion,
654- boards : platform
655- . getBoardsList ( )
656- . map ( ( b ) => < Board > { name : b . getName ( ) , fqbn : b . getFqbn ( ) } ) ,
657- moreInfoLink : platform . getWebsite ( ) ,
599+ description : boardsList . map ( ( { name } ) => name ) . join ( ', ' ) ,
600+ boards : boardsList ,
601+ types : typeList ,
602+ moreInfoLink : website ,
603+ author : maintainer ,
604+ deprecated,
605+ availableVersions : Array . from ( versionReleaseMap . keys ( ) ) ,
658606 } ;
659607}
608+
609+ type PlatformSummaryWithMetadata = PlatformSummary . AsObject &
610+ Required < Pick < PlatformSummary . AsObject , 'metadata' > > ;
611+ function isPlatformSummaryWithMetadata (
612+ summary : PlatformSummary . AsObject
613+ ) : summary is PlatformSummaryWithMetadata {
614+ return Boolean ( summary . metadata ) ;
615+ }
0 commit comments