Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e70f0fe

Browse files
committedOct 10, 2023
DRAFTONE
1 parent 240ceeb commit e70f0fe

File tree

26 files changed

+510
-506
lines changed

26 files changed

+510
-506
lines changed
 

‎arduino/cores/cores.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,13 @@ import (
3737

3838
// Platform represents a platform package.
3939
type Platform struct {
40-
Architecture string // The name of the architecture of this package.
41-
Name string
42-
Category string
40+
Architecture string // The name of the architecture of this package.
4341
Releases map[semver.NormalizedString]*PlatformRelease // The Releases of this platform, labeled by version.
4442
Package *Package `json:"-"`
4543
ManuallyInstalled bool // true if the Platform has been installed without the CLI
46-
Deprecated bool // true if the Platform has been deprecated
44+
Deprecated bool // true if the latest PlatformRelease of this Platform has been deprecated
4745
Indexed bool // true if the Platform has been indexed from additional-urls
46+
Latest *semver.Version `json:"-"`
4847
}
4948

5049
// PlatformReleaseHelp represents the help URL for this Platform release
@@ -54,12 +53,15 @@ type PlatformReleaseHelp struct {
5453

5554
// PlatformRelease represents a release of a plaform package.
5655
type PlatformRelease struct {
56+
Name string
57+
Category string
5758
Resource *resources.DownloadResource
5859
Version *semver.Version
5960
BoardsManifest []*BoardManifest
6061
ToolDependencies ToolDependencies
6162
DiscoveryDependencies DiscoveryDependencies
6263
MonitorDependencies MonitorDependencies
64+
Deprecated bool
6365
Help PlatformReleaseHelp `json:"-"`
6466
Platform *Platform `json:"-"`
6567
Properties *properties.Map `json:"-"`
@@ -407,7 +409,7 @@ func (release *PlatformRelease) MarshalJSON() ([]byte, error) {
407409
ID: release.Platform.String(),
408410
Installed: release.Version.String(),
409411
Latest: latestStr,
410-
Name: release.Platform.Name,
412+
Name: release.Name,
411413
})
412414
}
413415

‎arduino/cores/packageindex/index.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,11 @@ func IndexFromPlatformRelease(pr *cores.PlatformRelease) Index {
222222
URL: pr.Platform.Package.URL,
223223
Email: pr.Platform.Package.Email,
224224
Platforms: []*indexPlatformRelease{{
225-
Name: pr.Platform.Name,
225+
Name: pr.Name,
226226
Architecture: pr.Platform.Architecture,
227227
Version: pr.Version,
228-
Deprecated: pr.Platform.Deprecated,
229-
Category: pr.Platform.Category,
228+
Deprecated: pr.Deprecated,
229+
Category: pr.Category,
230230
URL: pr.Resource.URL,
231231
ArchiveFileName: pr.Resource.ArchiveFileName,
232232
Checksum: pr.Resource.Checksum,
@@ -263,18 +263,13 @@ func (inPackage indexPackage) extractPackageIn(outPackages cores.Packages, trust
263263

264264
func (inPlatformRelease indexPlatformRelease) extractPlatformIn(outPackage *cores.Package, trusted bool, isInstallJSON bool) error {
265265
outPlatform := outPackage.GetOrCreatePlatform(inPlatformRelease.Architecture)
266-
// FIXME: shall we use the Name and Category of the latest release? or maybe move Name and Category in PlatformRelease?
267-
outPlatform.Name = inPlatformRelease.Name
268-
outPlatform.Category = inPlatformRelease.Category
269266
// If the variable `isInstallJSON` is false it means that the index we're reading is coming from the additional-urls.
270267
// Therefore, the `outPlatform.Indexed` will be set at `true`.
271268
outPlatform.Indexed = outPlatform.Indexed || !isInstallJSON
272269

273-
// If the Platform is installed before deprecation installed.json file does not include "deprecated" field.
274-
// The installed.json is read during loading phase of an installed Platform, if the deprecated field is not found
275-
// the package_index.json field would be overwritten and the deprecation info would be lost.
276-
// This check prevents that behaviour.
277-
if !outPlatform.Deprecated {
270+
// If the latest platform release is deprecated, then deprecate the whole platform.
271+
if outPlatform.Latest == nil || outPlatform.Latest.LessThan(inPlatformRelease.Version) {
272+
outPlatform.Latest = inPlatformRelease.Version
278273
outPlatform.Deprecated = inPlatformRelease.Deprecated
279274
}
280275

@@ -283,6 +278,8 @@ func (inPlatformRelease indexPlatformRelease) extractPlatformIn(outPackage *core
283278
return fmt.Errorf(tr("invalid platform archive size: %s"), err)
284279
}
285280
outPlatformRelease := outPlatform.GetOrCreateRelease(inPlatformRelease.Version)
281+
outPlatformRelease.Name = inPlatformRelease.Name
282+
outPlatformRelease.Category = inPlatformRelease.Category
286283
outPlatformRelease.IsTrusted = trusted
287284
outPlatformRelease.Resource = &resources.DownloadResource{
288285
ArchiveFileName: inPlatformRelease.ArchiveFileName,
@@ -296,6 +293,7 @@ func (inPlatformRelease indexPlatformRelease) extractPlatformIn(outPackage *core
296293
outPlatformRelease.ToolDependencies = inPlatformRelease.extractToolDependencies()
297294
outPlatformRelease.DiscoveryDependencies = inPlatformRelease.extractDiscoveryDependencies()
298295
outPlatformRelease.MonitorDependencies = inPlatformRelease.extractMonitorDependencies()
296+
outPlatformRelease.Deprecated = inPlatformRelease.Deprecated
299297
return nil
300298
}
301299

‎arduino/cores/packageindex/index_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,10 @@ func TestIndexFromPlatformRelease(t *testing.T) {
9191
Name: "serial-monitor",
9292
},
9393
},
94+
Name: "Arduino AVR Boards",
95+
Category: "Arduino",
9496
Platform: &cores.Platform{
95-
Name: "Arduino AVR Boards",
9697
Architecture: "avr",
97-
Category: "Arduino",
98-
9998
Package: &cores.Package{
10099
Name: "arduino",
101100
Maintainer: "Arduino",

‎arduino/cores/packagemanager/loader.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,14 @@ func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *pa
323323
platform.Properties.Set("pluggable_monitor.required.serial", "builtin:serial-monitor")
324324
}
325325

326-
if platform.Platform.Name == "" {
326+
if platform.Name == "" {
327327
if name, ok := platform.Properties.GetOk("name"); ok {
328-
platform.Platform.Name = name
328+
platform.Name = name
329329
} else {
330330
// If the platform.txt file doesn't exist for this platform and it's not in any
331331
// package index there is no way of retrieving its name, so we build one using
332332
// the available information, that is the packager name and the architecture.
333-
platform.Platform.Name = fmt.Sprintf("%s-%s", platform.Platform.Package.Name, platform.Platform.Architecture)
333+
platform.Name = fmt.Sprintf("%s-%s", platform.Platform.Package.Name, platform.Platform.Architecture)
334334
}
335335
}
336336

‎arduino/cores/packagemanager/profiles.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (pmb *Builder) LoadHardwareForProfile(p *sketch.Profile, installMissing boo
4545
logrus.WithField("platform", platformRef).WithError(err).Debugf("Error loading platform for profile")
4646
} else {
4747
platformReleases = append(platformReleases, platformRelease)
48-
indexURLs[platformRelease.Platform.Name] = platformRef.PlatformIndexURL
48+
indexURLs[platformRelease.Name] = platformRef.PlatformIndexURL
4949
logrus.WithField("platform", platformRef).Debugf("Loaded platform for profile")
5050
}
5151
}

‎client_example/main.go

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,6 @@ func main() {
145145
log.Println("calling PlatformInstall(arduino:samd@1.6.19)")
146146
callPlatformInstall(client, instance)
147147

148-
// Now list the installed platforms to double check previous installation
149-
// went right.
150-
log.Println("calling PlatformList()")
151-
callPlatformList(client, instance)
152-
153148
// Upgrade the installed platform to the latest version.
154149
log.Println("calling PlatformUpgrade(arduino:samd)")
155150
callPlatformUpgrade(client, instance)
@@ -420,7 +415,7 @@ func callPlatformSearch(client rpc.ArduinoCoreServiceClient, instance *rpc.Insta
420415
for _, plat := range platforms {
421416
// We only print ID and version of the platforms found but you can look
422417
// at the definition for the rpc.Platform struct for more fields.
423-
log.Printf("Search result: %+v - %+v", plat.GetId(), plat.GetLatest())
418+
log.Printf("Search result: %+v - %+v", plat.GetMetadata().GetId(), plat.GetLatestVersion())
424419
}
425420
}
426421

@@ -464,21 +459,6 @@ func callPlatformInstall(client rpc.ArduinoCoreServiceClient, instance *rpc.Inst
464459
}
465460
}
466461

467-
func callPlatformList(client rpc.ArduinoCoreServiceClient, instance *rpc.Instance) {
468-
listResp, err := client.PlatformList(context.Background(),
469-
&rpc.PlatformListRequest{Instance: instance})
470-
471-
if err != nil {
472-
log.Fatalf("List error: %s", err)
473-
}
474-
475-
for _, plat := range listResp.GetInstalledPlatforms() {
476-
// We only print ID and version of the installed platforms but you can look
477-
// at the definition for the rpc.Platform struct for more fields.
478-
log.Printf("Installed platform: %s - %s", plat.GetId(), plat.GetInstalled())
479-
}
480-
}
481-
482462
func callPlatformUpgrade(client rpc.ArduinoCoreServiceClient, instance *rpc.Instance) {
483463
upgradeRespStream, err := client.PlatformUpgrade(context.Background(),
484464
&rpc.PlatformUpgradeRequest{
@@ -546,7 +526,7 @@ func callBoardSearch(client rpc.ArduinoCoreServiceClient, instance *rpc.Instance
546526
}
547527

548528
for _, board := range res.Boards {
549-
log.Printf("Board Name: %s, Board Platform: %s\n", board.Name, board.Platform.Id)
529+
log.Printf("Board Name: %s, Board Platform: %s\n", board.Name, board.Platform.Metadata.Id)
550530
}
551531
}
552532

‎commands/board/details.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetai
3939
return nil, &arduino.InvalidFQBNError{Cause: err}
4040
}
4141

42-
boardPackage, boardPlatform, board, boardProperties, boardRefPlatform, err := pme.ResolveFQBN(fqbn)
42+
boardPackage, boardPlatformRelease, board, boardProperties, boardRefPlatform, err := pme.ResolveFQBN(fqbn)
4343
if err != nil {
4444
return nil, &arduino.UnknownFQBNError{Cause: err}
4545
}
@@ -65,11 +65,11 @@ func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetai
6565
}
6666

6767
details.DebuggingSupported = boardProperties.ContainsKey("debug.executable") ||
68-
boardPlatform.Properties.ContainsKey("debug.executable") ||
68+
boardPlatformRelease.Properties.ContainsKey("debug.executable") ||
6969
(boardRefPlatform != nil && boardRefPlatform.Properties.ContainsKey("debug.executable")) ||
7070
// HOTFIX: Remove me when the `arduino:samd` core is updated
71-
boardPlatform.String() == "arduino:samd@1.8.9" ||
72-
boardPlatform.String() == "arduino:samd@1.8.8"
71+
boardPlatformRelease.String() == "arduino:samd@1.8.9" ||
72+
boardPlatformRelease.String() == "arduino:samd@1.8.8"
7373

7474
details.Package = &rpc.Package{
7575
Name: boardPackage.Name,
@@ -81,16 +81,16 @@ func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetai
8181
}
8282

8383
details.Platform = &rpc.BoardPlatform{
84-
Architecture: boardPlatform.Platform.Architecture,
85-
Category: boardPlatform.Platform.Category,
86-
Name: boardPlatform.Platform.Name,
84+
Architecture: boardPlatformRelease.Platform.Architecture,
85+
Category: boardPlatformRelease.Category,
86+
Name: boardPlatformRelease.Name,
8787
}
8888

89-
if boardPlatform.Resource != nil {
90-
details.Platform.Url = boardPlatform.Resource.URL
91-
details.Platform.ArchiveFilename = boardPlatform.Resource.ArchiveFileName
92-
details.Platform.Checksum = boardPlatform.Resource.Checksum
93-
details.Platform.Size = boardPlatform.Resource.Size
89+
if boardPlatformRelease.Resource != nil {
90+
details.Platform.Url = boardPlatformRelease.Resource.URL
91+
details.Platform.ArchiveFilename = boardPlatformRelease.Resource.ArchiveFileName
92+
details.Platform.Checksum = boardPlatformRelease.Resource.Checksum
93+
details.Platform.Size = boardPlatformRelease.Resource.Size
9494
}
9595

9696
details.ConfigOptions = []*rpc.ConfigOption{}
@@ -118,7 +118,7 @@ func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetai
118118
}
119119

120120
details.ToolsDependencies = []*rpc.ToolsDependencies{}
121-
for _, tool := range boardPlatform.ToolDependencies {
121+
for _, tool := range boardPlatformRelease.ToolDependencies {
122122
toolRelease := pme.FindToolDependency(tool)
123123
var systems []*rpc.Systems
124124
if toolRelease != nil {
@@ -141,9 +141,9 @@ func Details(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetai
141141
}
142142

143143
details.Programmers = []*rpc.Programmer{}
144-
for id, p := range boardPlatform.Programmers {
144+
for id, p := range boardPlatformRelease.Programmers {
145145
details.Programmers = append(details.Programmers, &rpc.Programmer{
146-
Platform: boardPlatform.Platform.Name,
146+
Platform: boardPlatformRelease.Name,
147147
Id: id,
148148
Name: p.Name,
149149
})

‎commands/board/list.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardL
157157

158158
// We need the Platform maintaner for sorting so we set it here
159159
platform := &rpc.Platform{
160-
Maintainer: board.PlatformRelease.Platform.Package.Maintainer,
160+
Metadata: &rpc.PlatformMetadata{
161+
Maintainer: board.PlatformRelease.Platform.Package.Maintainer,
162+
},
161163
}
162164
boards = append(boards, &rpc.BoardListItem{
163165
Name: board.Name(),
@@ -185,7 +187,7 @@ func identify(pme *packagemanager.Explorer, port *discovery.Port) ([]*rpc.BoardL
185187

186188
// Put Arduino boards before others in case there are non Arduino boards with identical VID:PID combination
187189
sort.SliceStable(boards, func(i, j int) bool {
188-
if boards[i].Platform.Maintainer == "Arduino" && boards[j].Platform.Maintainer != "Arduino" {
190+
if boards[i].Platform.Metadata.Maintainer == "Arduino" && boards[j].Platform.Metadata.Maintainer != "Arduino" {
189191
return true
190192
}
191193
return false

‎commands/board/listall.go

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,29 +46,14 @@ func ListAll(ctx context.Context, req *rpc.BoardListAllRequest) (*rpc.BoardListA
4646
continue
4747
}
4848

49-
installedVersion := installedPlatformRelease.Version.String()
50-
51-
latestVersion := ""
52-
if latestPlatformRelease := platform.GetLatestRelease(); latestPlatformRelease != nil {
53-
latestVersion = latestPlatformRelease.Version.String()
54-
}
55-
5649
rpcPlatform := &rpc.Platform{
57-
Id: platform.String(),
58-
Installed: installedVersion,
59-
Latest: latestVersion,
60-
Name: platform.Name,
61-
Maintainer: platform.Package.Maintainer,
62-
Website: platform.Package.WebsiteURL,
63-
Email: platform.Package.Email,
64-
ManuallyInstalled: platform.ManuallyInstalled,
65-
Indexed: platform.Indexed,
66-
MissingMetadata: !installedPlatformRelease.HasMetadata(),
50+
Metadata: commands.PlatformToRPCPlatformMetadata(platform),
51+
Release: commands.PlatformReleaseToRPC(installedPlatformRelease),
6752
}
6853

6954
toTest := []string{
7055
platform.String(),
71-
platform.Name,
56+
installedPlatformRelease.Name,
7257
platform.Architecture,
7358
targetPackage.Name,
7459
targetPackage.Maintainer,

‎commands/board/search.go

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchR
3737
}
3838
defer release()
3939

40-
res := &rpc.BoardSearchResponse{Boards: []*rpc.BoardListItem{}}
40+
foundBoards := []*rpc.BoardListItem{}
4141
for _, targetPackage := range pme.GetPackages() {
4242
for _, platform := range targetPackage.Platforms {
4343
latestPlatformRelease := platform.GetLatestRelease()
@@ -47,23 +47,13 @@ func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchR
4747
continue
4848
}
4949

50-
rpcPlatform := &rpc.Platform{
51-
Id: platform.String(),
52-
Name: platform.Name,
53-
Maintainer: platform.Package.Maintainer,
54-
Website: platform.Package.WebsiteURL,
55-
Email: platform.Package.Email,
56-
ManuallyInstalled: platform.ManuallyInstalled,
57-
Indexed: platform.Indexed,
58-
}
59-
60-
if latestPlatformRelease != nil {
61-
rpcPlatform.Latest = latestPlatformRelease.Version.String()
62-
}
63-
if installedPlatformRelease != nil {
64-
rpcPlatform.Installed = installedPlatformRelease.Version.String()
65-
rpcPlatform.MissingMetadata = !installedPlatformRelease.HasMetadata()
66-
}
50+
// if latestPlatformRelease != nil {
51+
// rpcPlatform.Latest = latestPlatformRelease.Version.String()
52+
// }
53+
// if installedPlatformRelease != nil {
54+
// rpcPlatform.Installed = installedPlatformRelease.Version.String()
55+
// rpcPlatform.MissingMetadata = !installedPlatformRelease.HasMetadata()
56+
// }
6757

6858
// Platforms that are not installed don't have a list of boards
6959
// generated from their boards.txt file so we need two different
@@ -81,11 +71,14 @@ func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchR
8171
continue
8272
}
8373

84-
res.Boards = append(res.Boards, &rpc.BoardListItem{
74+
foundBoards = append(foundBoards, &rpc.BoardListItem{
8575
Name: board.Name(),
8676
Fqbn: board.FQBN(),
8777
IsHidden: board.IsHidden(),
88-
Platform: rpcPlatform,
78+
Platform: &rpc.Platform{
79+
Metadata: commands.PlatformToRPCPlatformMetadata(platform),
80+
Release: commands.PlatformReleaseToRPC(installedPlatformRelease),
81+
},
8982
})
9083
}
9184
} else if latestPlatformRelease != nil {
@@ -95,20 +88,24 @@ func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchR
9588
continue
9689
}
9790

98-
res.Boards = append(res.Boards, &rpc.BoardListItem{
99-
Name: strings.Trim(board.Name, " \n"),
100-
Platform: rpcPlatform,
91+
foundBoards = append(foundBoards, &rpc.BoardListItem{
92+
Name: strings.Trim(board.Name, " \n"),
93+
Platform: &rpc.Platform{
94+
Metadata: commands.PlatformToRPCPlatformMetadata(platform),
95+
Release: commands.PlatformReleaseToRPC(latestPlatformRelease),
96+
},
10197
})
10298
}
10399
}
104100
}
105101
}
106102

107-
sort.Slice(res.Boards, func(i, j int) bool {
108-
if res.Boards[i].Name != res.Boards[j].Name {
109-
return res.Boards[i].Name < res.Boards[j].Name
103+
sort.Slice(foundBoards, func(i, j int) bool {
104+
if foundBoards[i].Name != foundBoards[j].Name {
105+
return foundBoards[i].Name < foundBoards[j].Name
110106
}
111-
return res.Boards[i].Platform.Id < res.Boards[j].Platform.Id
107+
return foundBoards[i].Platform.Metadata.Id < foundBoards[j].Platform.Metadata.Id
112108
})
113-
return res, nil
109+
110+
return &rpc.BoardSearchResponse{Boards: foundBoards}, nil
114111
}

‎commands/core.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func PlatformToRPCPlatformMetadata(platform *cores.Platform) *rpc.PlatformMetada
2828
Website: platform.Package.WebsiteURL,
2929
Email: platform.Package.Email,
3030
ManuallyInstalled: platform.ManuallyInstalled,
31-
Deprecated: platform.Deprecated_,
31+
Deprecated: platform.Deprecated,
3232
Indexed: platform.Indexed,
3333
}
3434
}

‎commands/core/list.go

Lines changed: 0 additions & 89 deletions
This file was deleted.

‎commands/core/search.go

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/arduino/arduino-cli/arduino/cores"
2525
"github.com/arduino/arduino-cli/arduino/utils"
2626
"github.com/arduino/arduino-cli/commands"
27+
f "github.com/arduino/arduino-cli/internal/algorithms"
2728
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
2829
)
2930

@@ -35,19 +36,22 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse
3536
}
3637
defer release()
3738

38-
res := []*cores.PlatformRelease{}
39+
res := []*cores.Platform{}
3940
if isUsb, _ := regexp.MatchString("[0-9a-f]{4}:[0-9a-f]{4}", req.SearchArgs); isUsb {
4041
vid, pid := req.SearchArgs[:4], req.SearchArgs[5:]
41-
res = pme.FindPlatformReleaseProvidingBoardsWithVidPid(vid, pid)
42+
// TODO: De-duplicate return Platforms
43+
// TODO: Inline FindPlatformReleaseProvidingBoardsWithVidPid
44+
res = f.Map(pme.FindPlatformReleaseProvidingBoardsWithVidPid(vid, pid), func(x *cores.PlatformRelease) *cores.Platform {
45+
return x.Platform
46+
})
4247
} else {
4348
searchArgs := utils.SearchTermsFromQueryString(req.SearchArgs)
44-
allVersions := req.AllVersions
4549
for _, targetPackage := range pme.GetPackages() {
4650
for _, platform := range targetPackage.Platforms {
4751
// Users can install platforms manually in the Sketchbook hardware folder,
4852
// the core search command must operate only on platforms installed through
4953
// the PlatformManager, thus we skip the manually installed ones.
50-
if platform == nil || platform.Name == "" || platform.ManuallyInstalled {
54+
if platform == nil || platform.ManuallyInstalled {
5155
continue
5256
}
5357

@@ -56,10 +60,13 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse
5660
if latestRelease == nil {
5761
continue
5862
}
63+
if latestRelease.Name == "" {
64+
continue
65+
}
5966

6067
// Gather all strings that can be used for searching
6168
toTest := platform.String() + " " +
62-
platform.Name + " " +
69+
latestRelease.Name + " " +
6370
platform.Architecture + " " +
6471
targetPackage.Name + " " +
6572
targetPackage.Maintainer + " " +
@@ -73,33 +80,52 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse
7380
continue
7481
}
7582

76-
if allVersions {
77-
res = append(res, platform.GetAllReleases()...)
78-
} else {
79-
res = append(res, latestRelease)
80-
}
83+
res = append(res, platform)
8184
}
8285
}
8386
}
8487

85-
out := make([]*rpc.Platform, len(res))
86-
for i, platformRelease := range res {
87-
out[i] = commands.PlatformReleaseToRPC(platformRelease)
88-
if platformRelease.IsInstalled() {
89-
out[i].Installed = platformRelease.Version.String()
88+
out := []*rpc.PlatformSummary{}
89+
for _, platform := range res {
90+
rpcPlatformSummary := &rpc.PlatformSummary{
91+
Releases: map[string]*rpc.PlatformRelease{},
92+
}
93+
94+
rpcPlatformSummary.Metadata = commands.PlatformToRPCPlatformMetadata(platform)
95+
96+
installed := pme.GetInstalledPlatformRelease(platform)
97+
latest := platform.GetLatestRelease()
98+
if installed != nil {
99+
rpcPlatformSummary.InstalledVersion = installed.Version.String()
100+
}
101+
if latest != nil {
102+
rpcPlatformSummary.LatestVersion = latest.Version.String()
90103
}
104+
if req.AllVersions {
105+
for _, platformRelease := range platform.GetAllReleases() {
106+
rpcPlatformRelease := commands.PlatformReleaseToRPC(platformRelease)
107+
rpcPlatformSummary.Releases[rpcPlatformRelease.Version] = rpcPlatformRelease
108+
}
109+
} else {
110+
if installed != nil {
111+
rpcPlatformRelease := commands.PlatformReleaseToRPC(installed)
112+
rpcPlatformSummary.Releases[installed.Version.String()] = rpcPlatformRelease
113+
}
114+
if latest != nil {
115+
rpcPlatformRelease := commands.PlatformReleaseToRPC(latest)
116+
rpcPlatformSummary.Releases[latest.Version.String()] = rpcPlatformRelease
117+
}
118+
}
119+
out = append(out, rpcPlatformSummary)
91120
}
121+
92122
// Sort result alphabetically and put deprecated platforms at the bottom
93-
sort.Slice(
94-
out, func(i, j int) bool {
95-
return strings.ToLower(out[i].Name) < strings.ToLower(out[j].Name)
96-
})
97-
sort.SliceStable(
98-
out, func(i, j int) bool {
99-
if !out[i].Deprecated && out[j].Deprecated {
100-
return true
101-
}
102-
return false
103-
})
123+
sort.Slice(out, func(i, j int) bool {
124+
return strings.ToLower(out[i].GetReleases()[out[i].GetLatestVersion()].Name) <
125+
strings.ToLower(out[j].GetReleases()[out[j].GetLatestVersion()].Name)
126+
})
127+
sort.SliceStable(out, func(i, j int) bool {
128+
return !out[i].GetMetadata().Deprecated && out[j].GetMetadata().Deprecated
129+
})
104130
return &rpc.PlatformSearchResponse{SearchOutput: out}, nil
105131
}

‎commands/core/search_test.go

Lines changed: 244 additions & 198 deletions
Large diffs are not rendered by default.

‎commands/core/upgrade.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ func PlatformUpgrade(ctx context.Context, req *rpc.PlatformUpgradeRequest, downl
4949
}
5050

5151
var rpcPlatform *rpc.Platform
52-
5352
platformRelease, err := upgrade()
5453
if platformRelease != nil {
55-
rpcPlatform = commands.PlatformReleaseToRPC(platformRelease)
54+
rpcPlatform = &rpc.Platform{
55+
Metadata: commands.PlatformToRPCPlatformMetadata(platformRelease.Platform),
56+
Release: commands.PlatformReleaseToRPC(platformRelease),
57+
}
5658
}
5759
if err != nil {
5860
return &rpc.PlatformUpgradeResponse{Platform: rpcPlatform}, err

‎commands/daemon/daemon.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,12 +258,6 @@ func (s *ArduinoCoreServerImpl) PlatformSearch(ctx context.Context, req *rpc.Pla
258258
return resp, convertErrorToRPCStatus(err)
259259
}
260260

261-
// PlatformList FIXMEDOC
262-
func (s *ArduinoCoreServerImpl) PlatformList(ctx context.Context, req *rpc.PlatformListRequest) (*rpc.PlatformListResponse, error) {
263-
platforms, err := core.PlatformList(req)
264-
return platforms, convertErrorToRPCStatus(err)
265-
}
266-
267261
// Upload FIXMEDOC
268262
func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadRequest, stream rpc.ArduinoCoreService_UploadServer) error {
269263
syncSend := NewSynchronizedSend(stream.Send)

‎internal/cli/arguments/completion.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,18 @@ func GetInstalledProgrammers() []string {
126126
func GetUninstallableCores() []string {
127127
inst := instance.CreateAndInit()
128128

129-
platforms, _ := core.PlatformList(&rpc.PlatformListRequest{
130-
Instance: inst,
131-
UpdatableOnly: false,
132-
All: false,
129+
platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{
130+
Instance: inst,
131+
AllVersions: false,
133132
})
133+
134134
var res []string
135135
// transform the data structure for the completion
136-
for _, i := range platforms.InstalledPlatforms {
137-
res = append(res, i.Id+"\t"+i.Name)
136+
for _, i := range platforms.GetSearchOutput() {
137+
if i.InstalledVersion == "" {
138+
continue
139+
}
140+
res = append(res, i.GetMetadata().GetId()+"\t"+i.GetInstalledRelease().GetName())
138141
}
139142
return res
140143
}
@@ -152,7 +155,7 @@ func GetInstallableCores() []string {
152155
var res []string
153156
// transform the data structure for the completion
154157
for _, i := range platforms.SearchOutput {
155-
res = append(res, i.Id+"\t"+i.Name)
158+
res = append(res, i.GetMetadata().GetId()+"\t"+i.GetReleases()[i.GetLatestVersion()].GetName())
156159
}
157160
return res
158161
}

‎internal/cli/arguments/reference.go

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,42 +66,47 @@ func ParseReference(arg string) (*Reference, error) {
6666
if arg == "" {
6767
return nil, fmt.Errorf(tr("invalid empty core argument"))
6868
}
69-
toks := strings.SplitN(arg, "@", 2)
70-
if toks[0] == "" {
69+
70+
if toks := strings.SplitN(arg, "@", 2); toks[0] == "" {
7171
return nil, fmt.Errorf(tr("invalid empty core reference '%s'"), arg)
72-
}
73-
ret.PackageName = toks[0]
74-
if len(toks) > 1 {
75-
if toks[1] == "" {
76-
return nil, fmt.Errorf(tr("invalid empty core version: '%s'"), arg)
72+
} else {
73+
ret.PackageName = toks[0]
74+
if len(toks) > 1 {
75+
if toks[1] == "" {
76+
return nil, fmt.Errorf(tr("invalid empty core version: '%s'"), arg)
77+
}
78+
ret.Version = toks[1]
7779
}
78-
ret.Version = toks[1]
7980
}
8081

81-
toks = strings.Split(ret.PackageName, ":")
82-
if len(toks) != 2 {
82+
if toks := strings.Split(ret.PackageName, ":"); len(toks) != 2 {
8383
return nil, fmt.Errorf(tr("invalid item %s"), arg)
84+
} else {
85+
if toks[0] == "" {
86+
return nil, fmt.Errorf(tr("invalid empty core name '%s'"), arg)
87+
}
88+
ret.PackageName = toks[0]
89+
if toks[1] == "" {
90+
return nil, fmt.Errorf(tr("invalid empty core architecture '%s'"), arg)
91+
}
92+
ret.Architecture = toks[1]
8493
}
85-
if toks[0] == "" {
86-
return nil, fmt.Errorf(tr("invalid empty core name '%s'"), arg)
87-
}
88-
ret.PackageName = toks[0]
89-
if toks[1] == "" {
90-
return nil, fmt.Errorf(tr("invalid empty core architecture '%s'"), arg)
91-
}
92-
ret.Architecture = toks[1]
9394

9495
// Now that we have the required informations in `ret` we can
9596
// try to use core.PlatformList to optimize what the user typed
9697
// (by replacing the PackageName and Architecture in ret with the content of core.GetPlatform())
97-
platforms, _ := core.PlatformList(&rpc.PlatformListRequest{
98-
Instance: instance.CreateAndInit(),
99-
UpdatableOnly: false,
100-
All: true, // this is true because we want also the installable platforms
98+
platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{
99+
Instance: instance.CreateAndInit(),
100+
AllVersions: false,
101101
})
102102
foundPlatforms := []string{}
103-
for _, platform := range platforms.InstalledPlatforms {
104-
platformID := platform.GetId()
103+
for _, platform := range platforms.GetSearchOutput() {
104+
installedRelease := platform.GetInstalledRelease()
105+
if installedRelease == nil {
106+
continue
107+
}
108+
109+
platformID := platform.GetMetadata().GetId()
105110
platformUser := ret.PackageName + ":" + ret.Architecture
106111
// At first we check if the platform the user is searching for matches an available one,
107112
// this way we do not need to adapt the casing and we can return it directly
@@ -110,7 +115,6 @@ func ParseReference(arg string) (*Reference, error) {
110115
}
111116
if strings.EqualFold(platformUser, platformID) {
112117
logrus.Infof("Found possible match for reference %s -> %s", platformUser, platformID)
113-
toks = strings.Split(platformID, ":")
114118
foundPlatforms = append(foundPlatforms, platformID)
115119
}
116120
}
@@ -122,6 +126,7 @@ func ParseReference(arg string) (*Reference, error) {
122126
if len(foundPlatforms) > 1 {
123127
return nil, &arduino.MultiplePlatformsError{Platforms: foundPlatforms, UserPlatform: arg}
124128
}
129+
toks := strings.Split(foundPlatforms[0], ":")
125130
ret.PackageName = toks[0]
126131
ret.Architecture = toks[1]
127132
return ret, nil

‎internal/cli/board/search.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func (r searchResults) String() string {
8585
if item.IsHidden {
8686
hidden = tr("(hidden)")
8787
}
88-
t.AddRow(item.GetName(), item.GetFqbn(), item.Platform.Id, hidden)
88+
t.AddRow(item.GetName(), item.GetFqbn(), item.Platform.Metadata.Id, hidden)
8989
}
9090
return t.Render()
9191
}

‎internal/cli/core/list.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,32 @@ func List(inst *rpc.Instance, all bool, updatableOnly bool) {
5959
}
6060

6161
// GetList returns a list of installed platforms.
62-
func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.Platform {
63-
platforms, err := core.PlatformList(&rpc.PlatformListRequest{
64-
Instance: inst,
65-
UpdatableOnly: updatableOnly,
66-
All: all,
62+
func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.PlatformSummary {
63+
platforms, err := core.PlatformSearch(&rpc.PlatformSearchRequest{
64+
Instance: inst,
65+
AllVersions: true,
6766
})
6867
if err != nil {
6968
feedback.Fatal(tr("Error listing platforms: %v", err), feedback.ErrGeneric)
7069
}
71-
return platforms.InstalledPlatforms
70+
71+
result := []*rpc.PlatformSummary{}
72+
for _, platform := range platforms.GetSearchOutput() {
73+
if !all && platform.InstalledVersion == "" {
74+
continue
75+
}
76+
if updatableOnly && platform.InstalledVersion == platform.LatestVersion {
77+
continue
78+
}
79+
result = append(result, platform)
80+
}
81+
return result
7282
}
7383

7484
// output from this command requires special formatting, let's create a dedicated
7585
// feedback.Result implementation
7686
type installedResult struct {
77-
platforms []*rpc.Platform
87+
platforms []*rpc.PlatformSummary
7888
}
7989

8090
func (ir installedResult) Data() interface{} {
@@ -87,12 +97,18 @@ func (ir installedResult) String() string {
8797
}
8898
t := table.New()
8999
t.SetHeader(tr("ID"), tr("Installed"), tr("Latest"), tr("Name"))
90-
for _, p := range ir.platforms {
91-
name := p.Name
92-
if p.Deprecated {
100+
for _, platform := range ir.platforms {
101+
installedRelease := platform.GetInstalledRelease()
102+
latestRelease := platform.GetLatestRelease()
103+
104+
name := installedRelease.GetName()
105+
if name == "" {
106+
name = latestRelease.GetName()
107+
}
108+
if platform.Metadata.Deprecated {
93109
name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
94110
}
95-
t.AddRow(p.Id, p.Installed, p.Latest, name)
111+
t.AddRow(platform.Metadata.Id, platform.InstalledVersion, platform.LatestVersion, name)
96112
}
97113

98114
return t.Render()

‎internal/cli/core/search.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) {
8787
// output from this command requires special formatting, let's create a dedicated
8888
// feedback.Result implementation
8989
type searchResults struct {
90-
platforms []*rpc.Platform
90+
platforms []*rpc.PlatformSummary
9191
}
9292

9393
func (sr searchResults) Data() interface{} {
@@ -98,12 +98,14 @@ func (sr searchResults) String() string {
9898
if len(sr.platforms) > 0 {
9999
t := table.New()
100100
t.SetHeader(tr("ID"), tr("Version"), tr("Name"))
101-
for _, item := range sr.platforms {
102-
name := item.GetName()
103-
if item.Deprecated {
101+
for _, platform := range sr.platforms {
102+
name := platform.GetLatestRelease().GetName()
103+
if platform.GetMetadata().Deprecated {
104104
name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
105105
}
106-
t.AddRow(item.GetId(), item.GetLatest(), name)
106+
for _, platformRelease := range platform.GetSortedReleases() {
107+
t.AddRow(platform.GetMetadata().GetId(), platformRelease.GetVersion(), name)
108+
}
107109
}
108110
return t.Render()
109111
}

‎internal/cli/core/upgrade.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,45 @@ func runUpgradeCommand(args []string, skipPostInstall bool, skipPreUninstall boo
6060
func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUninstall bool) {
6161
// if no platform was passed, upgrade allthethings
6262
if len(args) == 0 {
63-
targets, err := core.PlatformList(&rpc.PlatformListRequest{
64-
Instance: inst,
65-
UpdatableOnly: true,
63+
platforms, err := core.PlatformSearch(&rpc.PlatformSearchRequest{
64+
Instance: inst,
65+
AllVersions: false,
6666
})
6767
if err != nil {
6868
feedback.Fatal(tr("Error retrieving core list: %v", err), feedback.ErrGeneric)
6969
}
7070

71-
if len(targets.InstalledPlatforms) == 0 {
71+
targets := []*rpc.Platform{}
72+
for _, platform := range platforms.GetSearchOutput() {
73+
if platform.InstalledVersion == "" {
74+
continue
75+
}
76+
if platform.InstalledVersion == platform.LatestVersion {
77+
// if it's not updatable, skip it
78+
continue
79+
}
80+
targets = append(targets, &rpc.Platform{
81+
Metadata: platform.GetMetadata(),
82+
Release: platform.GetLatestRelease(),
83+
})
84+
}
85+
86+
if len(targets) == 0 {
7287
feedback.Print(tr("All the cores are already at the latest version"))
7388
return
7489
}
7590

76-
for _, t := range targets.InstalledPlatforms {
77-
args = append(args, t.Id)
91+
for _, t := range targets {
92+
args = append(args, t.GetMetadata().Id)
7893
}
7994
}
8095

8196
warningMissingIndex := func(response *rpc.PlatformUpgradeResponse) {
8297
if response == nil || response.Platform == nil {
8398
return
8499
}
85-
if !response.Platform.Indexed {
86-
feedback.Warning(tr("missing package index for %s, future updates cannot be guaranteed", response.Platform.Id))
100+
if !response.Platform.GetMetadata().Indexed {
101+
feedback.Warning(tr("missing package index for %s, future updates cannot be guaranteed", response.Platform.GetMetadata().Id))
87102
}
88103
}
89104

‎internal/cli/outdated/outdated.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func Outdated(inst *rpc.Instance) {
6464
// output from this command requires special formatting, let's create a dedicated
6565
// feedback.Result implementation
6666
type outdatedResult struct {
67-
Platforms []*rpc.Platform `json:"platforms,omitempty"`
67+
Platforms []*rpc.PlatformSummary `json:"platforms,omitempty"`
6868
InstalledLibs []*rpc.InstalledLibrary `json:"libraries,omitempty"`
6969
}
7070

@@ -93,11 +93,11 @@ func (ir outdatedResult) String() string {
9393

9494
// Based on internal/cli/core/list.go
9595
for _, p := range ir.Platforms {
96-
name := p.Name
97-
if p.Deprecated {
96+
name := p.GetLatestRelease().GetName()
97+
if p.GetMetadata().Deprecated {
9898
name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name)
9999
}
100-
t.AddRow(p.Id, name, p.Installed, p.Latest, "", "")
100+
t.AddRow(p.GetMetadata().Id, name, p.InstalledVersion, p.LatestVersion, "", "")
101101
}
102102

103103
// Based on internal/cli/lib/list.go

‎internal/integrationtest/arduino-cli.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -473,10 +473,14 @@ func (inst *ArduinoCLIInstance) PlatformUpgrade(ctx context.Context, packager, a
473473
return installCl, err
474474
}
475475

476-
// PlatformList calls the "PlatformList" gRPC method.
477-
func (inst *ArduinoCLIInstance) PlatformList(ctx context.Context) (*commands.PlatformListResponse, error) {
478-
req := &commands.PlatformListRequest{Instance: inst.instance}
479-
logCallf(">>> PlatformList(%+v)\n", req)
480-
resp, err := inst.cli.daemonClient.PlatformList(ctx, req)
476+
// PlatformSearch calls the "PlatformSearch" gRPC method.
477+
func (inst *ArduinoCLIInstance) PlatformSearch(ctx context.Context, args string, all bool) (*commands.PlatformSearchResponse, error) {
478+
req := &commands.PlatformSearchRequest{
479+
Instance: inst.instance,
480+
SearchArgs: args,
481+
AllVersions: all,
482+
}
483+
logCallf(">>> PlatformSearcg(%+v)\n", req)
484+
resp, err := inst.cli.daemonClient.PlatformSearch(ctx, req)
481485
return resp, err
482486
}

‎internal/integrationtest/daemon/daemon_test.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func TestDaemonAutoUpdateIndexOnFirstInit(t *testing.T) {
104104
fmt.Printf("INIT> %v\n", ir.GetMessage())
105105
}))
106106

107-
_, err := grpcInst.PlatformList(context.Background())
107+
_, err := grpcInst.PlatformSearch(context.Background(), "", true)
108108
require.NoError(t, err)
109109

110110
require.FileExists(t, cli.DataDir().Join("package_index.json").String())
@@ -477,8 +477,8 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) {
477477
platform, upgradeError := analyzePlatformUpgradeClient(plUpgrade)
478478
require.NoError(t, upgradeError)
479479
require.NotNil(t, platform)
480-
require.True(t, platform.Indexed) // the esp866 is present in the additional-urls
481-
require.False(t, platform.MissingMetadata) // install.json is present
480+
require.True(t, platform.Metadata.Indexed) // the esp866 is present in the additional-urls
481+
require.False(t, platform.Release.MissingMetadata) // install.json is present
482482
})
483483
t.Run("and install.json is missing", func(t *testing.T) {
484484
env, cli := createEnvForDaemon(t)
@@ -497,9 +497,8 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) {
497497
platform, upgradeError := analyzePlatformUpgradeClient(plUpgrade)
498498
require.NoError(t, upgradeError)
499499
require.NotNil(t, platform)
500-
require.True(t, platform.Indexed) // the esp866 is not present in the additional-urls
501-
require.False(t, platform.MissingMetadata) // install.json is present because the old version got upgraded
502-
500+
require.True(t, platform.Metadata.Indexed) // the esp866 is not present in the additional-urls
501+
require.False(t, platform.Release.MissingMetadata) // install.json is present because the old version got upgraded
503502
})
504503
})
505504

@@ -521,8 +520,8 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) {
521520
platform, upgradeError := analyzePlatformUpgradeClient(plUpgrade)
522521
require.ErrorIs(t, upgradeError, (&arduino.PlatformAlreadyAtTheLatestVersionError{Platform: "esp8266:esp8266"}).ToRPCStatus().Err())
523522
require.NotNil(t, platform)
524-
require.False(t, platform.Indexed) // the esp866 is not present in the additional-urls
525-
require.False(t, platform.MissingMetadata) // install.json is present
523+
require.False(t, platform.Metadata.Indexed) // the esp866 is not present in the additional-urls
524+
require.False(t, platform.Release.MissingMetadata) // install.json is present
526525
})
527526
t.Run("missing both additional URLs and install.json", func(t *testing.T) {
528527
env, cli := createEnvForDaemon(t)
@@ -546,8 +545,8 @@ func TestDaemonCoreUpgradePlatform(t *testing.T) {
546545
platform, upgradeError := analyzePlatformUpgradeClient(plUpgrade)
547546
require.ErrorIs(t, upgradeError, (&arduino.PlatformAlreadyAtTheLatestVersionError{Platform: "esp8266:esp8266"}).ToRPCStatus().Err())
548547
require.NotNil(t, platform)
549-
require.False(t, platform.Indexed) // the esp866 is not present in the additional-urls
550-
require.True(t, platform.MissingMetadata) // install.json is present
548+
require.False(t, platform.Metadata.Indexed) // the esp866 is not present in the additional-urls
549+
require.True(t, platform.Release.MissingMetadata) // install.json is present
551550
})
552551
})
553552
}

‎rpc/cc/arduino/cli/commands/v1/common.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515

1616
package commands
1717

18+
import (
19+
"sort"
20+
21+
semver "go.bug.st/relaxed-semver"
22+
)
23+
1824
// DownloadProgressCB is a callback to get updates on download progress
1925
type DownloadProgressCB func(curr *DownloadProgress)
2026

@@ -80,3 +86,15 @@ func (s *PlatformSummary) GetInstalledRelease() *PlatformRelease {
8086
}
8187
return s.Releases[s.InstalledVersion]
8288
}
89+
90+
// GetSortedReleases returns the releases in order of version.
91+
func (s *PlatformSummary) GetSortedReleases() []*PlatformRelease {
92+
res := []*PlatformRelease{}
93+
for _, release := range s.GetReleases() {
94+
res = append(res, release)
95+
}
96+
sort.SliceStable(res, func(i, j int) bool {
97+
return semver.ParseRelaxed(res[i].Version).LessThan(semver.ParseRelaxed(res[j].Version))
98+
})
99+
return res
100+
}

0 commit comments

Comments
 (0)
Please sign in to comment.