From 5b641874616abfe5d927a2b029341b7e993cc729 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:10:36 +0200 Subject: [PATCH 01/19] add Incompatible field in PlatformRelease --- arduino/cores/cores.go | 60 +++++++++++++++++++ arduino/cores/packagemanager/download.go | 4 +- .../cores/packagemanager/install_uninstall.go | 2 +- .../cores/packagemanager/package_manager.go | 37 ++++++++++++ 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/arduino/cores/cores.go b/arduino/cores/cores.go index 0c836c20f8d..0c6fb37178e 100644 --- a/arduino/cores/cores.go +++ b/arduino/cores/cores.go @@ -75,6 +75,7 @@ type PlatformRelease struct { PluggableDiscoveryAware bool `json:"-"` // true if the Platform supports pluggable discovery (no compatibility layer required) Monitors map[string]*MonitorDependency `json:"-"` MonitorsDevRecipes map[string]string `json:"-"` + Incompatible bool `json:"-"` // true if at least one ToolDependencies is not available for the current OS/ARCH. } // BoardManifest contains information about a board. These metadata are usually @@ -229,6 +230,30 @@ func (platform *Platform) GetLatestRelease() *PlatformRelease { return platform.FindReleaseWithVersion(latestVersion) } +// GetLatestCompatibleRelease returns the latest compatible release of this platform, or nil if no +// compatible releases are available. +func (platform *Platform) GetLatestCompatibleRelease() *PlatformRelease { + if len(platform.Releases) == 0 { + return nil + } + maximum := &PlatformRelease{Version: &semver.Version{}} + for _, release := range platform.Releases { + if release.Incompatible { + continue + } + if release.Version.GreaterThan(maximum.Version) { + maximum = release + } + } + + // In case no compatible versions found return nil + if maximum.Version.Equal(&semver.Version{}) { + return nil + } + + return maximum +} + // GetAllReleases returns all the releases of this platform, or an empty // slice if no releases are available func (platform *Platform) GetAllReleases() []*PlatformRelease { @@ -249,6 +274,18 @@ func (platform *Platform) GetAllReleasesVersions() []*semver.Version { return versions } +// GetAllCompatibleReleasesVersions returns all the version numbers in this Platform Package that contains compatible tools. +func (platform *Platform) GetAllCompatibleReleasesVersions() []*semver.Version { + versions := []*semver.Version{} + for _, release := range platform.Releases { + if release.Incompatible { + continue + } + versions = append(versions, release.Version) + } + return versions +} + // latestReleaseVersion obtains latest version number, or nil if no release available func (platform *Platform) latestReleaseVersion() *semver.Version { // TODO: Cache latest version using a field in Platform @@ -266,6 +303,23 @@ func (platform *Platform) latestReleaseVersion() *semver.Version { return max } +// latestCompatibleReleaseVersion obtains latest version number, for platforms that contains compatible tools, or nil if no release available +func (platform *Platform) latestCompatibleReleaseVersion() *semver.Version { + versions := platform.GetAllCompatibleReleasesVersions() + if len(versions) == 0 { + return nil + } + max := versions[0] + + for i := 1; i < len(versions); i++ { + if versions[i].GreaterThan(max) { + max = versions[i] + } + } + + return max +} + // GetAllInstalled returns all installed PlatformRelease func (platform *Platform) GetAllInstalled() []*PlatformRelease { res := []*PlatformRelease{} @@ -422,3 +476,9 @@ func (release *PlatformRelease) HasMetadata() bool { installedJSONPath := release.InstallDir.Join("installed.json") return installedJSONPath.Exist() } + +// IsIncompatible returns true if the PlatformRelease contains tool +// dependencies that are not available in the current OS/ARCH. +func (release *PlatformRelease) IsIncompatible() bool { + return release.Incompatible +} diff --git a/arduino/cores/packagemanager/download.go b/arduino/cores/packagemanager/download.go index f3a5877c8a6..b7989b61729 100644 --- a/arduino/cores/packagemanager/download.go +++ b/arduino/cores/packagemanager/download.go @@ -87,9 +87,9 @@ func (pme *Explorer) FindPlatformReleaseDependencies(item *PlatformReference) (* return nil, nil, fmt.Errorf(tr("required version %[1]s not found for platform %[2]s"), item.PlatformVersion, platform.String()) } } else { - release = platform.GetLatestRelease() + release = platform.GetLatestCompatibleRelease() if release == nil { - return nil, nil, fmt.Errorf(tr("platform %s has no available releases"), platform.String()) + return nil, nil, fmt.Errorf(tr("platform %s has no available releases for your OS"), platform.String()) } } diff --git a/arduino/cores/packagemanager/install_uninstall.go b/arduino/cores/packagemanager/install_uninstall.go index 0d8332cb2be..2f396894fa5 100644 --- a/arduino/cores/packagemanager/install_uninstall.go +++ b/arduino/cores/packagemanager/install_uninstall.go @@ -53,7 +53,7 @@ func (pme *Explorer) DownloadAndInstallPlatformUpgrades( if installed == nil { return nil, &arduino.PlatformNotFoundError{Platform: platformRef.String()} } - latest := platform.GetLatestRelease() + latest := platform.GetLatestCompatibleRelease() if !latest.Version.GreaterThan(installed.Version) { return installed, &arduino.PlatformAlreadyAtTheLatestVersionError{Platform: platformRef.String()} } diff --git a/arduino/cores/packagemanager/package_manager.go b/arduino/cores/packagemanager/package_manager.go index 1d6ac17aac0..afa57f5871a 100644 --- a/arduino/cores/packagemanager/package_manager.go +++ b/arduino/cores/packagemanager/package_manager.go @@ -121,6 +121,42 @@ func (pmb *Builder) Build() *PackageManager { } } +func (pmb *Builder) calculateIncompatibleVersions() { + // calculates Incompatible PlatformRelease + for _, op := range pmb.packages { + for _, p := range op.Platforms { + for _, pr := range p.Releases { + platformHasIncompatibleTools := func() bool { + for _, td := range pr.ToolDependencies { + if td == nil { + return true + } + + _, ok := pmb.packages[td.ToolPackager] + if !ok { + return true + } + tool := pmb.packages[td.ToolPackager].Tools[td.ToolName] + if tool == nil { + return true + } + tr := tool.Releases[td.ToolVersion.NormalizedString()] + if tr == nil { + return true + } + + if tr.GetCompatibleFlavour() == nil { + return true + } + } + return false + } + pr.Incompatible = platformHasIncompatibleTools() + } + } + } +} + // NewBuilder creates a Builder with the same configuration // of this PackageManager. A "commit" function callback is returned: calling // this function will make the builder write the new configuration into this @@ -128,6 +164,7 @@ func (pmb *Builder) Build() *PackageManager { func (pm *PackageManager) NewBuilder() (builder *Builder, commit func()) { pmb := NewBuilder(pm.IndexDir, pm.PackagesDir, pm.DownloadDir, pm.tempDir, pm.userAgent) return pmb, func() { + pmb.calculateIncompatibleVersions() pmb.BuildIntoExistingPackageManager(pm) } } From cda34140c64abfec99de0778e927c6caf52c4bbf Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:13:00 +0200 Subject: [PATCH 02/19] cli: core list print to output when all core are updated --- internal/cli/core/list.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/cli/core/list.go b/internal/cli/core/list.go index 1adda2f26bc..fb811028d58 100644 --- a/internal/cli/core/list.go +++ b/internal/cli/core/list.go @@ -56,7 +56,7 @@ func runListCommand(args []string, all bool, updatableOnly bool) { // List gets and prints a list of installed platforms. func List(inst *rpc.Instance, all bool, updatableOnly bool) { platforms := GetList(inst, all, updatableOnly) - feedback.PrintResult(newCoreListResult(platforms)) + feedback.PrintResult(newCoreListResult(platforms, updatableOnly)) } // GetList returns a list of installed platforms. @@ -88,8 +88,8 @@ func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.PlatformSu return result } -func newCoreListResult(in []*rpc.PlatformSummary) *coreListResult { - res := &coreListResult{} +func newCoreListResult(in []*rpc.PlatformSummary, updatableOnly bool) *coreListResult { + res := &coreListResult{updatableOnly: updatableOnly} for _, platformSummary := range in { res.platforms = append(res.platforms, result.NewPlatformSummary(platformSummary)) } @@ -97,7 +97,8 @@ func newCoreListResult(in []*rpc.PlatformSummary) *coreListResult { } type coreListResult struct { - platforms []*result.PlatformSummary + platforms []*result.PlatformSummary + updatableOnly bool } // Data implements Result interface @@ -108,6 +109,9 @@ func (ir coreListResult) Data() interface{} { // String implements Result interface func (ir coreListResult) String() string { if len(ir.platforms) == 0 { + if ir.updatableOnly { + return tr("All platforms are up to date.") + } return tr("No platforms installed.") } t := table.New() From ed70f4d57e6db6ef47bd55f0d04feebaf5b12095 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:14:35 +0200 Subject: [PATCH 03/19] add useful case in the test_index.json --- .../integrationtest/testdata/test_index.json | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/internal/integrationtest/testdata/test_index.json b/internal/integrationtest/testdata/test_index.json index 70de2ac0fee..95d38d202d4 100644 --- a/internal/integrationtest/testdata/test_index.json +++ b/internal/integrationtest/testdata/test_index.json @@ -236,6 +236,174 @@ ] } ] + }, + { + "name": "foo_vendor", + "maintainer": "Foo Developer", + "websiteURL": "http://example.com", + "email": "test@example.com", + "help": { + "online": "http://example.com" + }, + "platforms": [ + { + "name": "Foo Boards", + "architecture": "avr", + "version": "1.0.0", + "category": "Contributed", + "help": { + "online": "http://example.com" + }, + "url": "https://github.com/damellis/attiny/archive/702aa287455f7e052cf94fd4949398fec0ef21b8.zip", + "archiveFileName": "702aa287455f7e052cf94fd4949398fec0ef21b8.zip", + "checksum": "SHA-256:bfffa4a700e42ae993895f5eea22bc369ba5ac3ea36eca18ac5f72a05bb60ab5", + "size": "5005", + "boards": [], + "toolsDependencies": [ + { + "packager": "foo_vendor", + "name": "some_tool", + "version": "1.0.0" + } + ] + }, + { + "name": "Foo Boards", + "architecture": "avr", + "version": "1.0.1", + "category": "Contributed", + "help": { + "online": "http://example.com" + }, + "url": "https://github.com/damellis/attiny/archive/76ca88ce3c195fcba8e8a645084e352965dc80e0.zip", + "archiveFileName": "76ca88ce3c195fcba8e8a645084e352965dc80e0.zip", + "checksum": "SHA-256:49a4dfc3796caf2533050b0b962ae0affb2471b8ded1283936d7b712cc1fdff1", + "size": "5719", + "boards": [], + "toolsDependencies": [ + { + "packager": "foo_vendor", + "name": "some_tool", + "version": "1.0.0" + } + ] + }, + { + "name": "Foo Boards", + "architecture": "avr", + "version": "1.0.2", + "category": "Contributed", + "help": { + "online": "http://example.com" + }, + "url": "https://github.com/damellis/attiny/archive/76ca88ce3c195fcba8e8a645084e352965dc80e0.zip", + "archiveFileName": "76ca88ce3c195fcba8e8a645084e352965dc80e0.zip", + "checksum": "SHA-256:49a4dfc3796caf2533050b0b962ae0affb2471b8ded1283936d7b712cc1fdff1", + "size": "5719", + "boards": [], + "toolsDependencies": [ + { + "packager": "foo_vendor", + "name": "incompatible_tool", + "version": "2.0.0" + } + ] + } + ], + "tools": [ + { + "name": "some_tool", + "version": "1.0.0", + "systems": [ + { + "size": "219631", + "checksum": "SHA-256:2a8e68c5d803aa6f902ef219f177ec3a4c28275d85cbe272962ad2cd374f50d1", + "host": "arm-linux-gnueabihf", + "archiveFileName": "avrdude-6.3.0-arduino17-armhf-pc-linux-gnu.tar.bz2", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-armhf-pc-linux-gnu.tar.bz2" + }, + { + "size": "229852", + "checksum": "SHA-256:6cf948f751acfe7b96684537f2291c766ec8b54b4f7dc95539864821456fa9fc", + "host": "aarch64-linux-gnu", + "archiveFileName": "avrdude-6.3.0-arduino17-aarch64-pc-linux-gnu.tar.bz2", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-aarch64-pc-linux-gnu.tar.bz2" + }, + { + "size": "279045", + "checksum": "SHA-256:120cc9edaae699e7e9ac50b1b8eb0e7d51fdfa555bac54233c2511e6ee5418c9", + "host": "x86_64-apple-darwin12", + "archiveFileName": "avrdude-6.3.0-arduino17-x86_64-apple-darwin12.tar.bz2", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-x86_64-apple-darwin12.tar.bz2" + }, + { + "size": "254271", + "checksum": "SHA-256:accdfb920af2aabf4f7461d2ac73c0751760f525216dc4e7657427a78c60d13d", + "host": "x86_64-linux-gnu", + "archiveFileName": "avrdude-6.3.0-arduino17-x86_64-pc-linux-gnu.tar.bz2", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-x86_64-pc-linux-gnu.tar.bz2" + }, + { + "size": "244550", + "checksum": "SHA-256:5c8cc6c17db9300e1451fe41cd7178b0442b4490ee6fdbc0aed9811aef96c05f", + "host": "i686-linux-gnu", + "archiveFileName": "avrdude-6.3.0-arduino17-i686-pc-linux-gnu.tar.bz2", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-i686-pc-linux-gnu.tar.bz2" + }, + { + "size": "328460", + "checksum": "SHA-256:e99188873c7c5ad8f8f906f068c33600e758b2e36cce3adbd518a21bd266749d", + "host": "i686-mingw32", + "archiveFileName": "avrdude-6.3.0-arduino17-i686-w64-mingw32.zip", + "url": "http://downloads.arduino.cc/tools/avrdude-6.3.0-arduino17-i686-w64-mingw32.zip" + } + ] + }, + { + "name": "incompatible_tool", + "version": "2.0.0", + "systems": [] + } + ] + }, + { + "name": "incompatible_vendor", + "maintainer": "Incompatible Developer", + "websiteURL": "http://example.com", + "email": "test@example.com", + "help": { + "online": "http://example.com" + }, + "platforms": [ + { + "name": "Incompatible Boards", + "architecture": "avr", + "version": "1.0.0", + "category": "Contributed", + "help": { + "online": "http://example.com" + }, + "url": "https://github.com/damellis/attiny/archive/702aa287455f7e052cf94fd4949398fec0ef21b8.zip", + "archiveFileName": "702aa287455f7e052cf94fd4949398fec0ef21b8.zip", + "checksum": "SHA-256:bfffa4a700e42ae993895f5eea22bc369ba5ac3ea36eca18ac5f72a05bb60ab5", + "size": "5005", + "boards": [], + "toolsDependencies": [ + { + "packager": "incompatible_vendor", + "name": "incompatible_tool", + "version": "2.0.0" + } + ] + } + ], + "tools": [ + { + "name": "incompatible_tool", + "version": "2.0.0", + "systems": [] + } + ] } ] } From 729c11c6eb3da2c61b29af0a7b0e464805483cb8 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:14:56 +0200 Subject: [PATCH 04/19] add integration test --- internal/integrationtest/core/core_test.go | 104 ++++++++++++++++++++- 1 file changed, 100 insertions(+), 4 deletions(-) diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index c5762d3beb6..d9379c8e09d 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -191,8 +191,8 @@ func TestCoreSearchNoArgs(t *testing.T) { for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { lines = append(lines, strings.Fields(strings.TrimSpace(v))) } - // Check the presence of test:x86@3.0.0 - require.Contains(t, lines, []string{"test:x86", "3.0.0", "test_core"}) + // Check the absence of test:x86@3.0.0 because it contains incompatible deps + require.NotContains(t, lines, []string{"test:x86", "3.0.0", "test_core"}) numPlatforms = len(lines) - 1 // same thing in JSON format, also check the number of platforms found is the same @@ -695,7 +695,7 @@ func TestCoreSearchSortedResults(t *testing.T) { require.NoError(t, err) out := strings.Split(strings.TrimSpace(string(stdout)), "\n") - var lines, deprecated, notDeprecated [][]string + var lines, deprecated, notDeprecated, incompatibles [][]string for i, v := range out { if i > 0 { v = strings.Join(strings.Fields(v), " ") @@ -705,6 +705,10 @@ func TestCoreSearchSortedResults(t *testing.T) { for _, v := range lines { if strings.HasPrefix(v[2], "[DEPRECATED]") { deprecated = append(deprecated, v) + continue + } + if _, err := semver.Parse(v[1]); err != nil { + incompatibles = append(incompatibles, v) } else { notDeprecated = append(notDeprecated, v) } @@ -717,9 +721,13 @@ func TestCoreSearchSortedResults(t *testing.T) { require.True(t, sort.SliceIsSorted(notDeprecated, func(i, j int) bool { return strings.ToLower(notDeprecated[i][2]) < strings.ToLower(notDeprecated[j][2]) })) + require.True(t, sort.SliceIsSorted(incompatibles, func(i, j int) bool { + return strings.ToLower(incompatibles[i][2]) < strings.ToLower(incompatibles[j][2]) + })) + result := append(notDeprecated, incompatibles...) // verify that deprecated platforms are the last ones - require.Equal(t, lines, append(notDeprecated, deprecated...)) + require.Equal(t, lines, append(result, deprecated...)) // test same behaviour with json output stdout, _, err = cli.Run("core", "search", "--additional-urls="+url.String(), "--format=json") @@ -1111,3 +1119,91 @@ func TestCoreListWhenNoPlatformAreInstalled(t *testing.T) { require.NoError(t, err) require.Equal(t, "No platforms installed.\n", string(stdout)) } + +func TestCoreHavingIncompatibleDepTools(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + url := env.HTTPServeFile(8000, paths.New("..", "testdata", "test_index.json")).String() + additionalURLs := "--additional-urls=" + url + + _, _, err := cli.Run("core", "update-index", additionalURLs) + require.NoError(t, err) + + // check that list shows only compatible versions + stdout, _, err := cli.Run("core", "list", "--all", "--format", "json", additionalURLs) + require.NoError(t, err) + t.Log(string(stdout)) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest`, `"1.0.2"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + + // install latest compatible version + _, _, err = cli.Run("core", "install", "foo_vendor:avr", additionalURLs) + require.NoError(t, err) + stdout, _, err = cli.Run("core", "list", "--all", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + + // install incompatible version + _, stderr, err := cli.Run("core", "install", "foo_vendor:avr@1.0.2", additionalURLs) + require.Error(t, err) + require.Contains(t, string(stderr), "no versions available for the current OS") + + // install compatible version + _, _, err = cli.Run("core", "install", "foo_vendor:avr@1.0.0", additionalURLs) + require.NoError(t, err) + stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.0"`) + + // Lists all updatable cores + stdout, _, err = cli.Run("core", "list", "--updatable", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + + // upgrade to latest compatible (1.0.0 -> 1.0.1) + _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) + require.NoError(t, err) + stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.1"`) + + // upgrade to latest incompatible not possible (1.0.1 -> 1.0.2) + _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) + require.NoError(t, err) + stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.1"`) + + // When no compatible version are found return error + _, stderr, err = cli.Run("core", "install", "incompatible_vendor:avr", additionalURLs) + require.Error(t, err) + require.Contains(t, string(stderr), "has no available releases for your OS") + + // Core search --all shows incompatible field when a version is incompatible + stdout, _, err = cli.Run("core", "search", "--all", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, + `[.[] | select(.id == "foo_vendor:avr") | {latest: .latest, incompatible: .incompatible}] | sort_by(.latest)`, + `[ + {"incompatible":null,"latest":"1.0.0"}, + {"incompatible":null,"latest":"1.0.1"}, + {"incompatible":true,"latest":"1.0.2"} + ]`, + ) + + // Core search shows latest compatible version + stdout, _, err = cli.Run("core", "search", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .incompatible`, `true`) + + // In text mode, core search doesn't show any version if no compatible one are present + stdout, _, err = cli.Run("core", "search", additionalURLs) + require.NoError(t, err) + var lines [][]string + for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { + lines = append(lines, strings.Fields(strings.TrimSpace(v))) + } + require.Contains(t, lines, []string{"incompatible_vendor:avr", "Incompatible", "Boards"}) +} From 851dd017287b93eb7e596623f1f0756526bc05ab Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:32:29 +0200 Subject: [PATCH 05/19] update the gRPC API --- rpc/cc/arduino/cli/commands/v1/common.pb.go | 109 ++++++++++++-------- rpc/cc/arduino/cli/commands/v1/common.proto | 5 + 2 files changed, 72 insertions(+), 42 deletions(-) diff --git a/rpc/cc/arduino/cli/commands/v1/common.pb.go b/rpc/cc/arduino/cli/commands/v1/common.pb.go index fe1f4e1f700..e099750d0b8 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/common.pb.go @@ -562,6 +562,9 @@ type PlatformSummary struct { InstalledVersion string `protobuf:"bytes,3,opt,name=installed_version,json=installedVersion,proto3" json:"installed_version,omitempty"` // The latest available version of the platform, or empty if none available LatestVersion string `protobuf:"bytes,4,opt,name=latest_version,json=latestVersion,proto3" json:"latest_version,omitempty"` + // The latest available version of the platform containing all compatible + // dependencies, or empty if none available + LatestCompatibleVersion string `protobuf:"bytes,5,opt,name=latest_compatible_version,json=latestCompatibleVersion,proto3" json:"latest_compatible_version,omitempty"` } func (x *PlatformSummary) Reset() { @@ -624,6 +627,13 @@ func (x *PlatformSummary) GetLatestVersion() string { return "" } +func (x *PlatformSummary) GetLatestCompatibleVersion() string { + if x != nil { + return x.LatestCompatibleVersion + } + return "" +} + // PlatformMetadata contains generic information about a platform (not // correlated to a specific release). type PlatformMetadata struct { @@ -761,6 +771,8 @@ type PlatformRelease struct { MissingMetadata bool `protobuf:"varint,7,opt,name=missing_metadata,json=missingMetadata,proto3" json:"missing_metadata,omitempty"` // True this release is deprecated Deprecated bool `protobuf:"varint,8,opt,name=deprecated,proto3" json:"deprecated,omitempty"` + // True if the platform contains an incompatible dependency. + Incompatible bool `protobuf:"varint,9,opt,name=incompatible,proto3" json:"incompatible,omitempty"` } func (x *PlatformRelease) Reset() { @@ -851,6 +863,13 @@ func (x *PlatformRelease) GetDeprecated() bool { return false } +func (x *PlatformRelease) GetIncompatible() bool { + if x != nil { + return x.Incompatible + } + return false +} + type InstalledPlatformReference struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1151,7 +1170,7 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x32, 0x2b, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x07, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0xf0, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0xac, 0x03, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x48, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, @@ -1167,47 +1186,53 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, - 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, - 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, - 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, - 0x0a, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, - 0x0a, 0x07, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, - 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2d, - 0x0a, 0x12, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, - 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, - 0x61, 0x6c, 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, - 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x22, 0xb6, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, - 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x63, - 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, - 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, - 0x31, 0x2e, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, - 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x3a, 0x0a, 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, + 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x17, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, + 0x69, 0x62, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x68, 0x0a, 0x0d, 0x52, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, + 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x65, + 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x65, 0x62, + 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x6d, 0x61, + 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, + 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, + 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x65, 0x64, 0x22, 0xda, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x62, 0x6f, 0x61, 0x72, 0x64, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, + 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, + 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x04, 0x68, 0x65, 0x6c, + 0x70, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, + 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, diff --git a/rpc/cc/arduino/cli/commands/v1/common.proto b/rpc/cc/arduino/cli/commands/v1/common.proto index fae80bab09b..1a355ea57c1 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.proto +++ b/rpc/cc/arduino/cli/commands/v1/common.proto @@ -91,6 +91,9 @@ message PlatformSummary { string installed_version = 3; // The latest available version of the platform, or empty if none available string latest_version = 4; + // The latest available version of the platform containing all compatible + // dependencies, or empty if none available + string latest_compatible_version = 5; } // PlatformMetadata contains generic information about a platform (not @@ -141,6 +144,8 @@ message PlatformRelease { bool missing_metadata = 7; // True this release is deprecated bool deprecated = 8; + // True if the platform contains an incompatible dependency. + bool incompatible = 9; } message InstalledPlatformReference { From 9572823154b8c1360c30debcf4cbeb586c0ecb88 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 12:37:59 +0200 Subject: [PATCH 06/19] map the incompatible field in PlatformReleaseToRPC --- commands/core.go | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/core.go b/commands/core.go index 14dc3360e4c..2519401e067 100644 --- a/commands/core.go +++ b/commands/core.go @@ -74,5 +74,6 @@ func PlatformReleaseToRPC(platformRelease *cores.PlatformRelease) *rpc.PlatformR MissingMetadata: missingMetadata, Type: []string{platformRelease.Category}, Deprecated: platformRelease.Deprecated, + Incompatible: platformRelease.IsIncompatible(), } } From 5635fb4fd6fd62bcf6488c51f43035f3a1b7601c Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 14:19:15 +0200 Subject: [PATCH 07/19] core search handles compatible version --- commands/core/search.go | 29 +++---- commands/core/search_test.go | 123 +++++++++++++++------------- internal/cli/core/search.go | 52 +++++++----- internal/cli/feedback/result/rpc.go | 33 +++++--- 4 files changed, 131 insertions(+), 106 deletions(-) diff --git a/commands/core/search.go b/commands/core/search.go index 7d0b5662f31..c766d8637e4 100644 --- a/commands/core/search.go +++ b/commands/core/search.go @@ -86,41 +86,34 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse out := []*rpc.PlatformSummary{} for _, platform := range res { rpcPlatformSummary := &rpc.PlatformSummary{ + Metadata: commands.PlatformToRPCPlatformMetadata(platform), Releases: map[string]*rpc.PlatformRelease{}, } - - rpcPlatformSummary.Metadata = commands.PlatformToRPCPlatformMetadata(platform) - - installed := pme.GetInstalledPlatformRelease(platform) - latest := platform.GetLatestRelease() - if installed != nil { + if installed := pme.GetInstalledPlatformRelease(platform); installed != nil { rpcPlatformSummary.InstalledVersion = installed.Version.String() + rpcPlatformSummary.Releases[installed.Version.String()] = commands.PlatformReleaseToRPC(installed) } - if latest != nil { + if latest := platform.GetLatestRelease(); latest != nil { rpcPlatformSummary.LatestVersion = latest.Version.String() + rpcPlatformSummary.Releases[latest.Version.String()] = commands.PlatformReleaseToRPC(latest) + } + if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { + rpcPlatformSummary.LatestCompatibleVersion = latestCompatible.Version.String() + rpcPlatformSummary.Releases[latestCompatible.Version.String()] = commands.PlatformReleaseToRPC(latestCompatible) } if req.AllVersions { for _, platformRelease := range platform.GetAllReleases() { rpcPlatformRelease := commands.PlatformReleaseToRPC(platformRelease) rpcPlatformSummary.Releases[rpcPlatformRelease.Version] = rpcPlatformRelease } - } else { - if installed != nil { - rpcPlatformRelease := commands.PlatformReleaseToRPC(installed) - rpcPlatformSummary.Releases[installed.Version.String()] = rpcPlatformRelease - } - if latest != nil { - rpcPlatformRelease := commands.PlatformReleaseToRPC(latest) - rpcPlatformSummary.Releases[latest.Version.String()] = rpcPlatformRelease - } } out = append(out, rpcPlatformSummary) } // Sort result alphabetically and put deprecated platforms at the bottom sort.Slice(out, func(i, j int) bool { - return strings.ToLower(out[i].GetReleases()[out[i].GetLatestVersion()].Name) < - strings.ToLower(out[j].GetReleases()[out[j].GetLatestVersion()].Name) + return strings.ToLower(out[i].GetLatestRelease().GetName()) < + strings.ToLower(out[j].GetLatestRelease().GetName()) }) sort.SliceStable(out, func(i, j int) bool { return !out[i].GetMetadata().Deprecated && out[j].GetMetadata().Deprecated diff --git a/commands/core/search_test.go b/commands/core/search_test.go index a695acbd6b4..b3e57859cdc 100644 --- a/commands/core/search_test.go +++ b/commands/core/search_test.go @@ -61,20 +61,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -101,12 +103,13 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -133,20 +136,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -173,20 +178,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -213,20 +220,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -285,7 +294,8 @@ func TestPlatformSearch(t *testing.T) { {Name: "Arduino Industrial 101"}, {Name: "Linino One"}, }, - Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Incompatible: true, }, }, InstalledVersion: "", @@ -344,7 +354,8 @@ func TestPlatformSearch(t *testing.T) { {Name: "Arduino Industrial 101"}, {Name: "Linino One"}, }, - Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Incompatible: true, }, }, InstalledVersion: "", diff --git a/internal/cli/core/search.go b/internal/cli/core/search.go index 30d4f749759..276204f1e6b 100644 --- a/internal/cli/core/search.go +++ b/internal/cli/core/search.go @@ -37,18 +37,17 @@ import ( "github.com/spf13/cobra" ) -var ( - allVersions bool -) - func initSearchCommand() *cobra.Command { + var allVersions bool searchCommand := &cobra.Command{ Use: fmt.Sprintf("search <%s...>", tr("keywords")), Short: tr("Search for a core in Boards Manager."), Long: tr("Search for a core in Boards Manager using the specified keywords."), Example: " " + os.Args[0] + " core search MKRZero -a -v", Args: cobra.ArbitraryArgs, - Run: runSearchCommand, + Run: func(cmd *cobra.Command, args []string) { + runSearchCommand(cmd, args, allVersions) + }, } searchCommand.Flags().BoolVarP(&allVersions, "all", "a", false, tr("Show all available core versions.")) @@ -58,7 +57,7 @@ func initSearchCommand() *cobra.Command { // indexUpdateInterval specifies the time threshold over which indexes are updated const indexUpdateInterval = "24h" -func runSearchCommand(cmd *cobra.Command, args []string) { +func runSearchCommand(cmd *cobra.Command, args []string, allVersions bool) { inst := instance.CreateAndInit() if indexesNeedUpdating(indexUpdateInterval) { @@ -82,19 +81,23 @@ func runSearchCommand(cmd *cobra.Command, args []string) { } coreslist := resp.GetSearchOutput() - feedback.PrintResult(newSearchResult(coreslist)) + feedback.PrintResult(newSearchResult(coreslist, allVersions)) } // output from this command requires special formatting, let's create a dedicated // feedback.Result implementation type searchResults struct { - platforms []*result.PlatformSummary + platforms []*result.PlatformSummary + allVersions bool } -func newSearchResult(in []*rpc.PlatformSummary) *searchResults { - res := &searchResults{} - for _, platformSummary := range in { - res.platforms = append(res.platforms, result.NewPlatformSummary(platformSummary)) +func newSearchResult(in []*rpc.PlatformSummary, allVersions bool) *searchResults { + res := &searchResults{ + platforms: make([]*result.PlatformSummary, len(in)), + allVersions: allVersions, + } + for i, platformSummary := range in { + res.platforms[i] = result.NewPlatformSummary(platformSummary) } return res } @@ -108,15 +111,24 @@ func (sr searchResults) String() string { t := table.New() t.SetHeader(tr("ID"), tr("Version"), tr("Name")) for _, platform := range sr.platforms { - name := "" - if latest := platform.GetLatestRelease(); latest != nil { - name = latest.Name - } - if platform.Deprecated { - name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name) + // When allVersions is not requested we only show the latest compatible version + if !sr.allVersions { + if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { + name := latestCompatible.Name + if latestCompatible.Deprecated { + name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), latestCompatible.Name) + } + t.AddRow(platform.Id, latestCompatible.Version, name) + } + continue } - for _, version := range platform.Releases.Keys() { - t.AddRow(platform.Id, version, name) + + for _, release := range platform.Releases.Values() { + name := release.Name + if platform.Deprecated { + name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), release.Name) + } + t.AddRow(platform.Id, release.Version, name) } } return t.Render() diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go index a632af7737c..4749f66d787 100644 --- a/internal/cli/feedback/result/rpc.go +++ b/internal/cli/feedback/result/rpc.go @@ -37,16 +37,17 @@ func NewPlatformSummary(in *rpc.PlatformSummary) *PlatformSummary { releases.SortKeys((*semver.Version).CompareTo) return &PlatformSummary{ - Id: in.GetMetadata().GetId(), - Maintainer: in.GetMetadata().GetMaintainer(), - Website: in.GetMetadata().GetWebsite(), - Email: in.GetMetadata().GetEmail(), - ManuallyInstalled: in.GetMetadata().GetManuallyInstalled(), - Deprecated: in.GetMetadata().GetDeprecated(), - Indexed: in.GetMetadata().GetIndexed(), - Releases: releases, - InstalledVersion: semver.MustParse(in.GetInstalledVersion()), - LatestVersion: semver.MustParse(in.GetLatestVersion()), + Id: in.GetMetadata().GetId(), + Maintainer: in.GetMetadata().GetMaintainer(), + Website: in.GetMetadata().GetWebsite(), + Email: in.GetMetadata().GetEmail(), + ManuallyInstalled: in.GetMetadata().GetManuallyInstalled(), + Deprecated: in.GetMetadata().GetDeprecated(), + Indexed: in.GetMetadata().GetIndexed(), + Releases: releases, + InstalledVersion: semver.MustParse(in.GetInstalledVersion()), + LatestVersion: semver.MustParse(in.GetLatestVersion()), + LatestCompatibleVersion: semver.MustParse(in.LatestCompatibleVersion), } } @@ -62,8 +63,9 @@ type PlatformSummary struct { Releases orderedmap.Map[*semver.Version, *PlatformRelease] `json:"releases,omitempty"` - InstalledVersion *semver.Version `json:"installed_version,omitempty"` - LatestVersion *semver.Version `json:"latest_version,omitempty"` + InstalledVersion *semver.Version `json:"installed_version,omitempty"` + LatestVersion *semver.Version `json:"latest_version,omitempty"` + LatestCompatibleVersion *semver.Version `json:"latest_compatible_version,omitempty"` } // GetLatestRelease returns the latest relase of this platform or nil if none available. @@ -71,6 +73,11 @@ func (p *PlatformSummary) GetLatestRelease() *PlatformRelease { return p.Releases.Get(p.LatestVersion) } +// GetLatestCompatibleRelease returns the latest relase of this platform or nil if none available. +func (p *PlatformSummary) GetLatestCompatibleRelease() *PlatformRelease { + return p.Releases.Get(p.LatestCompatibleVersion) +} + // GetInstalledRelease returns the installed relase of this platform or nil if none available. func (p *PlatformSummary) GetInstalledRelease() *PlatformRelease { return p.Releases.Get(p.InstalledVersion) @@ -103,6 +110,7 @@ func NewPlatformRelease(in *rpc.PlatformRelease) *PlatformRelease { Help: help, MissingMetadata: in.MissingMetadata, Deprecated: in.Deprecated, + Incompatible: in.Incompatible, } return res } @@ -117,6 +125,7 @@ type PlatformRelease struct { Help *HelpResource `json:"help,omitempty"` MissingMetadata bool `json:"missing_metadata,omitempty"` Deprecated bool `json:"deprecated,omitempty"` + Incompatible bool `json:"incompatible,omitempty"` } // Board maps a rpc.Board From 58192498fc832b0e69d6fc26ac1047bfc379dde2 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 14:28:30 +0200 Subject: [PATCH 08/19] cli: core upgrade handles compatible version --- internal/cli/core/upgrade.go | 4 ++-- rpc/cc/arduino/cli/commands/v1/common.go | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/cli/core/upgrade.go b/internal/cli/core/upgrade.go index 04045cc3bf6..d6dfd243aed 100644 --- a/internal/cli/core/upgrade.go +++ b/internal/cli/core/upgrade.go @@ -73,13 +73,13 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUni if platform.InstalledVersion == "" { continue } - if platform.InstalledVersion == platform.LatestVersion { + if platform.InstalledVersion == platform.LatestCompatibleVersion { // if it's not updatable, skip it continue } targets = append(targets, &rpc.Platform{ Metadata: platform.GetMetadata(), - Release: platform.GetLatestRelease(), + Release: platform.GetLatestCompatibleRelease(), }) } diff --git a/rpc/cc/arduino/cli/commands/v1/common.go b/rpc/cc/arduino/cli/commands/v1/common.go index a04ebff193f..e98b59780d3 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.go +++ b/rpc/cc/arduino/cli/commands/v1/common.go @@ -78,6 +78,15 @@ func (s *PlatformSummary) GetLatestRelease() *PlatformRelease { return s.Releases[s.LatestVersion] } +// GetLatestCompatibleRelease returns the latest compatible release in this PlatformSummary, +// or nil if not available. +func (s *PlatformSummary) GetLatestCompatibleRelease() *PlatformRelease { + if s.LatestCompatibleVersion == "" { + return nil + } + return s.Releases[s.LatestCompatibleVersion] +} + // GetInstalledRelease returns the latest release in this PlatformSummary, // or nil if not available. func (s *PlatformSummary) GetInstalledRelease() *PlatformRelease { From 9063971dcac7bbb6b26fa4016c23f86fbb213748 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 14:34:31 +0200 Subject: [PATCH 09/19] cli: outdated handles only latest compatible --- internal/cli/outdated/outdated.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cli/outdated/outdated.go b/internal/cli/outdated/outdated.go index 39cba04481c..9d4cb39f218 100644 --- a/internal/cli/outdated/outdated.go +++ b/internal/cli/outdated/outdated.go @@ -109,13 +109,13 @@ func (ir outdatedResult) String() string { // Based on internal/cli/core/list.go for _, p := range ir.Platforms { name := "" - if latest := p.GetLatestRelease(); latest != nil { - name = latest.Name + if latestCompatible := p.GetLatestCompatibleRelease(); latestCompatible != nil { + name = latestCompatible.Name } if p.Deprecated { name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name) } - t.AddRow(p.Id, name, p.InstalledVersion, p.LatestVersion, "", "") + t.AddRow(p.Id, name, p.InstalledVersion, p.LatestCompatibleVersion, "", "") } // Based on internal/cli/lib/list.go From e24ed890d8cbe214c76fe3243da589732bea95a2 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 15:46:34 +0200 Subject: [PATCH 10/19] cli: core list handle compatible version --- internal/cli/core/list.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/cli/core/list.go b/internal/cli/core/list.go index fb811028d58..502ce85ac20 100644 --- a/internal/cli/core/list.go +++ b/internal/cli/core/list.go @@ -80,7 +80,7 @@ func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.PlatformSu if platform.InstalledVersion == "" && !platform.GetMetadata().ManuallyInstalled { continue } - if updatableOnly && platform.InstalledVersion == platform.LatestVersion { + if updatableOnly && platform.InstalledVersion == platform.LatestCompatibleVersion { continue } result = append(result, platform) @@ -117,19 +117,22 @@ func (ir coreListResult) String() string { t := table.New() t.SetHeader(tr("ID"), tr("Installed"), tr("Latest"), tr("Name")) for _, platform := range ir.platforms { - name := "" + var name string if installed := platform.GetInstalledRelease(); installed != nil { name = installed.Name } if name == "" { - if latest := platform.GetLatestRelease(); latest != nil { + if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { + name = latestCompatible.Name + } else if latest := platform.GetLatestRelease(); latest != nil && name == "" { name = latest.Name } } if platform.Deprecated { name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name) } - t.AddRow(platform.Id, platform.InstalledVersion, platform.LatestVersion, name) + + t.AddRow(platform.Id, platform.InstalledVersion, platform.LatestCompatibleVersion, name) } return t.Render() From ffb8c94c7d27521f8fec45befbd6e229cd03bfe3 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 16:28:42 +0200 Subject: [PATCH 11/19] cli: update completition --- internal/cli/arguments/completion.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/cli/arguments/completion.go b/internal/cli/arguments/completion.go index 2139e415fe1..c6d2753e1cc 100644 --- a/internal/cli/arguments/completion.go +++ b/internal/cli/arguments/completion.go @@ -112,8 +112,11 @@ func GetInstallableCores() []string { }) var res []string // transform the data structure for the completion - for _, i := range platforms.SearchOutput { - res = append(res, i.GetMetadata().GetId()+"\t"+i.GetReleases()[i.GetLatestVersion()].GetName()) + for _, i := range platforms.GetSearchOutput() { + if i.GetLatestCompatibleVersion() == "" { + continue + } + res = append(res, i.GetMetadata().GetId()+"\t"+i.GetLatestCompatibleRelease().GetName()) } return res } From 85fedd2d7b44488290cc28a389ac1f002705f4de Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 19 Oct 2023 16:28:50 +0200 Subject: [PATCH 12/19] docs: update --- docs/UPGRADING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 037f4992058..26d1813bb63 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -4,6 +4,28 @@ Here you can find a list of migration guides to handle breaking changes between ## 0.36.0 +### The gRPC `cc.arduino.cli.commands.v1.PlatformRelease` has been changed. + +We've added a new field called `incompatible`. This field indicates if the current platform release is installable or +not. It may happen that a platform doesn't have a dependency available for an OS, in such cases, if we try to install +the platform it will fail. The new field can be used to know upfront if a specific release is installable. + +### The gRPC `cc.arduino.cli.commands.v1.PlatformSummary` has been changed. + +We've added a new field called `latest_compatible_version`. This field indicates the latest version that can be +successfully installed for the current OS. The `latest_version` field cannot guarantee such property. + +### `core list` now returns only the latest version that can be installed. + +Previously, we showed the latest version without checking if all the dependencies were available in the current OS. Now, +the latest version will always point to an installable one even if a newer incompatible one is present. + +### `core upgrade` and `core install` will install the latest compatible version. + +Previously, we'd have tried the installation/upgrade of a core even if all the required tools weren't available in the +current OS. Now we check this upfront, and allowing the installation of incompatible versions only if a user explicitly +provides it like: `core install arduino:renesas_uno@1.0.2` + ### gRPC service `cc.arduino.cli.settings.v1` has been removed, and all RPC calls have been migrated to `cc.arduino.cli.commands.v1` The service `cc.arduino.cli.settings.v1` no longer exists and all existing RPC calls have been moved to the From 834214815aafbb082a3ec90e22b8c78b185ccae2 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Mon, 23 Oct 2023 10:47:24 +0200 Subject: [PATCH 13/19] fix integration tests --- internal/integrationtest/core/core_test.go | 60 +++++++++++----------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index d9379c8e09d..f61d870a553 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -178,11 +178,11 @@ func TestCoreSearchNoArgs(t *testing.T) { require.Contains(t, lines, []string{"test:x86", "2.0.0", "test_core"}) numPlatforms := len(lines) - 1 - // same thing in JSON format, also check the number of platforms found is the same + // Same thing in JSON format, also check the number of platforms found is the same stdout, _, err = cli.Run("core", "search", "--format", "json") require.NoError(t, err) requirejson.Contains(t, stdout, `[{"id": "test:x86", "releases": { "2.0.0": {"name":"test_core"}}}]`) - requirejson.Query(t, stdout, "length", fmt.Sprint(numPlatforms)) + requirejson.Query(t, stdout, `[.[] | select(.latest_compatible_version != "")] | length`, fmt.Sprint(numPlatforms)) // list all with additional urls, check the test core is there stdout, _, err = cli.Run("core", "search", "--additional-urls="+url.String()) @@ -199,9 +199,7 @@ func TestCoreSearchNoArgs(t *testing.T) { stdout, _, err = cli.Run("core", "search", "--format", "json", "--additional-urls="+url.String()) require.NoError(t, err) requirejson.Contains(t, stdout, `[{"id": "test:x86", "releases": { "3.0.0": {"name":"test_core"}}}]`) - // A platform could contain multiple releases, we get the length of how many releases are present for each platform - // and we sum them to see if the expected numers matches. - requirejson.Query(t, stdout, `[.[].releases | length] | add`, fmt.Sprint(numPlatforms)) + requirejson.Query(t, stdout, `[.[] | select(.latest_compatible_version != "")] | length`, fmt.Sprint(numPlatforms)) } func TestCoreUpdateIndexUrlNotFound(t *testing.T) { @@ -695,7 +693,7 @@ func TestCoreSearchSortedResults(t *testing.T) { require.NoError(t, err) out := strings.Split(strings.TrimSpace(string(stdout)), "\n") - var lines, deprecated, notDeprecated, incompatibles [][]string + var lines, deprecated, notDeprecated [][]string for i, v := range out { if i > 0 { v = strings.Join(strings.Fields(v), " ") @@ -707,11 +705,7 @@ func TestCoreSearchSortedResults(t *testing.T) { deprecated = append(deprecated, v) continue } - if _, err := semver.Parse(v[1]); err != nil { - incompatibles = append(incompatibles, v) - } else { - notDeprecated = append(notDeprecated, v) - } + notDeprecated = append(notDeprecated, v) } // verify that results are already sorted correctly @@ -721,13 +715,9 @@ func TestCoreSearchSortedResults(t *testing.T) { require.True(t, sort.SliceIsSorted(notDeprecated, func(i, j int) bool { return strings.ToLower(notDeprecated[i][2]) < strings.ToLower(notDeprecated[j][2]) })) - require.True(t, sort.SliceIsSorted(incompatibles, func(i, j int) bool { - return strings.ToLower(incompatibles[i][2]) < strings.ToLower(incompatibles[j][2]) - })) - result := append(notDeprecated, incompatibles...) // verify that deprecated platforms are the last ones - require.Equal(t, lines, append(result, deprecated...)) + require.Equal(t, lines, append(notDeprecated, deprecated...)) // test same behaviour with json output stdout, _, err = cli.Run("core", "search", "--additional-urls="+url.String(), "--format=json") @@ -1134,15 +1124,15 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { stdout, _, err := cli.Run("core", "list", "--all", "--format", "json", additionalURLs) require.NoError(t, err) t.Log(string(stdout)) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest`, `"1.0.2"`) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_version`, `"1.0.2"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) // install latest compatible version _, _, err = cli.Run("core", "install", "foo_vendor:avr", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--all", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) // install incompatible version _, stderr, err := cli.Run("core", "install", "foo_vendor:avr@1.0.2", additionalURLs) @@ -1154,26 +1144,34 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.0"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.0"`) // Lists all updatable cores stdout, _, err = cli.Run("core", "list", "--updatable", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) + + // Show outdated cores, must show latest compatible + stdout, _, err = cli.Run("outdated", "--format", "json", additionalURLs) + require.NoError(t, err) + requirejson.Query(t, stdout, + `.platforms | .[] | select(.id == "foo_vendor:avr") | {latest_compatible: .latest_compatible_version, latest: .latest_version}`, + `{"latest_compatible": "1.0.1", "latest": "1.0.2"}`, + ) // upgrade to latest compatible (1.0.0 -> 1.0.1) _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.1"`) // upgrade to latest incompatible not possible (1.0.1 -> 1.0.2) _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed`, `"1.0.1"`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.1"`) // When no compatible version are found return error _, stderr, err = cli.Run("core", "install", "incompatible_vendor:avr", additionalURLs) @@ -1184,19 +1182,19 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { stdout, _, err = cli.Run("core", "search", "--all", "--format", "json", additionalURLs) require.NoError(t, err) requirejson.Query(t, stdout, - `[.[] | select(.id == "foo_vendor:avr") | {latest: .latest, incompatible: .incompatible}] | sort_by(.latest)`, + `[.[] | select(.id == "foo_vendor:avr") | .releases | map(.) | .[] | {version: .version, incompatible: .incompatible}] | sort_by(.version)`, `[ - {"incompatible":null,"latest":"1.0.0"}, - {"incompatible":null,"latest":"1.0.1"}, - {"incompatible":true,"latest":"1.0.2"} + {"incompatible":null,"version":"1.0.0"}, + {"incompatible":null,"version":"1.0.1"}, + {"incompatible":true,"version":"1.0.2"} ]`, ) - // Core search shows latest compatible version + // Core search shows latest compatible version even if incompatible stdout, _, err = cli.Run("core", "search", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest`, `"1.0.1"`) - requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .incompatible`, `true`) + requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_version`, `"1.0.2"`) + requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .releases[.latest_version].incompatible`, `true`) // In text mode, core search doesn't show any version if no compatible one are present stdout, _, err = cli.Run("core", "search", additionalURLs) @@ -1205,5 +1203,5 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { lines = append(lines, strings.Fields(strings.TrimSpace(v))) } - require.Contains(t, lines, []string{"incompatible_vendor:avr", "Incompatible", "Boards"}) + require.NotContains(t, lines, []string{"incompatible_vendor:avr"}) } From 2fca930dbf38429d9ddc13fdf9c310c25c782fbf Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Mon, 23 Oct 2023 17:16:55 +0200 Subject: [PATCH 14/19] rename 'incompatible' field to 'compatible' --- arduino/cores/cores.go | 14 +- .../cores/packagemanager/package_manager.go | 22 +-- .../packagemanager/package_manager_test.go | 1 + commands/core.go | 2 +- commands/core/search_test.go | 134 +++++++++--------- docs/UPGRADING.md | 6 +- internal/cli/feedback/result/rpc.go | 4 +- internal/integrationtest/core/core_test.go | 10 +- rpc/cc/arduino/cli/commands/v1/common.pb.go | 63 ++++---- rpc/cc/arduino/cli/commands/v1/common.proto | 5 +- 10 files changed, 132 insertions(+), 129 deletions(-) diff --git a/arduino/cores/cores.go b/arduino/cores/cores.go index 0c6fb37178e..a03d9875db8 100644 --- a/arduino/cores/cores.go +++ b/arduino/cores/cores.go @@ -75,7 +75,7 @@ type PlatformRelease struct { PluggableDiscoveryAware bool `json:"-"` // true if the Platform supports pluggable discovery (no compatibility layer required) Monitors map[string]*MonitorDependency `json:"-"` MonitorsDevRecipes map[string]string `json:"-"` - Incompatible bool `json:"-"` // true if at least one ToolDependencies is not available for the current OS/ARCH. + Compatible bool `json:"-"` // true if at all ToolDependencies are available for the current OS/ARCH. } // BoardManifest contains information about a board. These metadata are usually @@ -238,7 +238,7 @@ func (platform *Platform) GetLatestCompatibleRelease() *PlatformRelease { } maximum := &PlatformRelease{Version: &semver.Version{}} for _, release := range platform.Releases { - if release.Incompatible { + if !release.IsCompatible() { continue } if release.Version.GreaterThan(maximum.Version) { @@ -278,7 +278,7 @@ func (platform *Platform) GetAllReleasesVersions() []*semver.Version { func (platform *Platform) GetAllCompatibleReleasesVersions() []*semver.Version { versions := []*semver.Version{} for _, release := range platform.Releases { - if release.Incompatible { + if !release.IsCompatible() { continue } versions = append(versions, release.Version) @@ -477,8 +477,8 @@ func (release *PlatformRelease) HasMetadata() bool { return installedJSONPath.Exist() } -// IsIncompatible returns true if the PlatformRelease contains tool -// dependencies that are not available in the current OS/ARCH. -func (release *PlatformRelease) IsIncompatible() bool { - return release.Incompatible +// IsCompatible returns true if all the tools dependencies of a PlatformRelease +// are available in the current OS/ARCH. +func (release *PlatformRelease) IsCompatible() bool { + return release.Compatible } diff --git a/arduino/cores/packagemanager/package_manager.go b/arduino/cores/packagemanager/package_manager.go index afa57f5871a..1f2b380e08a 100644 --- a/arduino/cores/packagemanager/package_manager.go +++ b/arduino/cores/packagemanager/package_manager.go @@ -121,37 +121,37 @@ func (pmb *Builder) Build() *PackageManager { } } -func (pmb *Builder) calculateIncompatibleVersions() { - // calculates Incompatible PlatformRelease +// calculate Compatible PlatformRelease +func (pmb *Builder) calculateCompatibleReleases() { for _, op := range pmb.packages { for _, p := range op.Platforms { for _, pr := range p.Releases { - platformHasIncompatibleTools := func() bool { + platformHasAllCompatibleTools := func() bool { for _, td := range pr.ToolDependencies { if td == nil { - return true + return false } _, ok := pmb.packages[td.ToolPackager] if !ok { - return true + return false } tool := pmb.packages[td.ToolPackager].Tools[td.ToolName] if tool == nil { - return true + return false } tr := tool.Releases[td.ToolVersion.NormalizedString()] if tr == nil { - return true + return false } if tr.GetCompatibleFlavour() == nil { - return true + return false } } - return false + return true } - pr.Incompatible = platformHasIncompatibleTools() + pr.Compatible = platformHasAllCompatibleTools() } } } @@ -164,7 +164,7 @@ func (pmb *Builder) calculateIncompatibleVersions() { func (pm *PackageManager) NewBuilder() (builder *Builder, commit func()) { pmb := NewBuilder(pm.IndexDir, pm.PackagesDir, pm.DownloadDir, pm.tempDir, pm.userAgent) return pmb, func() { - pmb.calculateIncompatibleVersions() + pmb.calculateCompatibleReleases() pmb.BuildIntoExistingPackageManager(pm) } } diff --git a/arduino/cores/packagemanager/package_manager_test.go b/arduino/cores/packagemanager/package_manager_test.go index c02fa34eaa6..8a5fc877850 100644 --- a/arduino/cores/packagemanager/package_manager_test.go +++ b/arduino/cores/packagemanager/package_manager_test.go @@ -744,6 +744,7 @@ func TestFindToolsRequiredFromPlatformRelease(t *testing.T) { func TestFindPlatformReleaseDependencies(t *testing.T) { pmb := NewBuilder(nil, nil, nil, nil, "test") pmb.LoadPackageIndexFromFile(paths.New("testdata", "package_tooltest_index.json")) + pmb.calculateCompatibleReleases() pm := pmb.Build() pme, release := pm.NewExplorer() defer release() diff --git a/commands/core.go b/commands/core.go index 2519401e067..1881519ef38 100644 --- a/commands/core.go +++ b/commands/core.go @@ -74,6 +74,6 @@ func PlatformReleaseToRPC(platformRelease *cores.PlatformRelease) *rpc.PlatformR MissingMetadata: missingMetadata, Type: []string{platformRelease.Category}, Deprecated: platformRelease.Deprecated, - Incompatible: platformRelease.IsIncompatible(), + Compatible: platformRelease.IsCompatible(), } } diff --git a/commands/core/search_test.go b/commands/core/search_test.go index b3e57859cdc..2babe57ea81 100644 --- a/commands/core/search_test.go +++ b/commands/core/search_test.go @@ -61,22 +61,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, }, InstalledVersion: "", @@ -103,13 +103,13 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, }, InstalledVersion: "", @@ -136,22 +136,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, }, InstalledVersion: "", @@ -178,22 +178,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, }, InstalledVersion: "", @@ -220,22 +220,22 @@ func TestPlatformSearch(t *testing.T) { }, Releases: map[string]*rpc.PlatformRelease{ "1.0.5": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.5", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.5", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Incompatible: true, + Name: "RK002", + Type: []string{"Contributed"}, + Installed: false, + Version: "1.0.6", + Boards: []*rpc.Board{{Name: "RK002"}}, + Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, + Compatible: false, }, }, InstalledVersion: "", @@ -294,8 +294,8 @@ func TestPlatformSearch(t *testing.T) { {Name: "Arduino Industrial 101"}, {Name: "Linino One"}, }, - Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, - Incompatible: true, + Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Compatible: false, }, }, InstalledVersion: "", @@ -354,8 +354,8 @@ func TestPlatformSearch(t *testing.T) { {Name: "Arduino Industrial 101"}, {Name: "Linino One"}, }, - Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, - Incompatible: true, + Help: &rpc.HelpResources{Online: "http://www.arduino.cc/en/Reference/HomePage"}, + Compatible: false, }, }, InstalledVersion: "", diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index 26d1813bb63..d329a804e62 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -6,9 +6,9 @@ Here you can find a list of migration guides to handle breaking changes between ### The gRPC `cc.arduino.cli.commands.v1.PlatformRelease` has been changed. -We've added a new field called `incompatible`. This field indicates if the current platform release is installable or -not. It may happen that a platform doesn't have a dependency available for an OS, in such cases, if we try to install -the platform it will fail. The new field can be used to know upfront if a specific release is installable. +We've added a new field called `compatible`. This field indicates if the current platform release is installable or not. +It may happen that a platform doesn't have a dependency available for an OS, in such cases, if we try to install the +platform it will fail. The new field can be used to know upfront if a specific release is installable. ### The gRPC `cc.arduino.cli.commands.v1.PlatformSummary` has been changed. diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go index 4749f66d787..1d9664f9cec 100644 --- a/internal/cli/feedback/result/rpc.go +++ b/internal/cli/feedback/result/rpc.go @@ -110,7 +110,7 @@ func NewPlatformRelease(in *rpc.PlatformRelease) *PlatformRelease { Help: help, MissingMetadata: in.MissingMetadata, Deprecated: in.Deprecated, - Incompatible: in.Incompatible, + Compatible: in.Compatible, } return res } @@ -125,7 +125,7 @@ type PlatformRelease struct { Help *HelpResource `json:"help,omitempty"` MissingMetadata bool `json:"missing_metadata,omitempty"` Deprecated bool `json:"deprecated,omitempty"` - Incompatible bool `json:"incompatible,omitempty"` + Compatible bool `json:"compatible"` } // Board maps a rpc.Board diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index f61d870a553..6406bf3854d 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -1182,11 +1182,11 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { stdout, _, err = cli.Run("core", "search", "--all", "--format", "json", additionalURLs) require.NoError(t, err) requirejson.Query(t, stdout, - `[.[] | select(.id == "foo_vendor:avr") | .releases | map(.) | .[] | {version: .version, incompatible: .incompatible}] | sort_by(.version)`, + `[.[] | select(.id == "foo_vendor:avr") | .releases | map(.) | .[] | {version: .version, compatible: .compatible}] | sort_by(.version)`, `[ - {"incompatible":null,"version":"1.0.0"}, - {"incompatible":null,"version":"1.0.1"}, - {"incompatible":true,"version":"1.0.2"} + {"compatible":true,"version":"1.0.0"}, + {"compatible":true,"version":"1.0.1"}, + {"compatible":false,"version":"1.0.2"} ]`, ) @@ -1194,7 +1194,7 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { stdout, _, err = cli.Run("core", "search", "--format", "json", additionalURLs) require.NoError(t, err) requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_version`, `"1.0.2"`) - requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .releases[.latest_version].incompatible`, `true`) + requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .releases[.latest_version].compatible`, `false`) // In text mode, core search doesn't show any version if no compatible one are present stdout, _, err = cli.Run("core", "search", additionalURLs) diff --git a/rpc/cc/arduino/cli/commands/v1/common.pb.go b/rpc/cc/arduino/cli/commands/v1/common.pb.go index e099750d0b8..66f1cd1d14b 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/common.pb.go @@ -771,8 +771,9 @@ type PlatformRelease struct { MissingMetadata bool `protobuf:"varint,7,opt,name=missing_metadata,json=missingMetadata,proto3" json:"missing_metadata,omitempty"` // True this release is deprecated Deprecated bool `protobuf:"varint,8,opt,name=deprecated,proto3" json:"deprecated,omitempty"` - // True if the platform contains an incompatible dependency. - Incompatible bool `protobuf:"varint,9,opt,name=incompatible,proto3" json:"incompatible,omitempty"` + // True if the platform dependencies are available for the current OS. This + // also means that the platform is installable. + Compatible bool `protobuf:"varint,9,opt,name=compatible,proto3" json:"compatible,omitempty"` } func (x *PlatformRelease) Reset() { @@ -863,9 +864,9 @@ func (x *PlatformRelease) GetDeprecated() bool { return false } -func (x *PlatformRelease) GetIncompatible() bool { +func (x *PlatformRelease) GetCompatible() bool { if x != nil { - return x.Incompatible + return x.Compatible } return false } @@ -1211,7 +1212,7 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x65, 0x64, 0x22, 0xda, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x78, 0x65, 0x64, 0x22, 0xd6, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, @@ -1230,32 +1231,32 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, - 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, - 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x2f, 0x0a, 0x05, 0x42, - 0x6f, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x31, 0x0a, 0x07, - 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, - 0x27, 0x0a, 0x0d, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, - 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x22, 0x88, 0x01, 0x0a, + 0x1a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x2f, 0x0a, 0x05, 0x42, 0x6f, 0x61, 0x72, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x31, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x48, + 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x6e, + 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, + 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/cc/arduino/cli/commands/v1/common.proto b/rpc/cc/arduino/cli/commands/v1/common.proto index 1a355ea57c1..13befb5bf82 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.proto +++ b/rpc/cc/arduino/cli/commands/v1/common.proto @@ -144,8 +144,9 @@ message PlatformRelease { bool missing_metadata = 7; // True this release is deprecated bool deprecated = 8; - // True if the platform contains an incompatible dependency. - bool incompatible = 9; + // True if the platform dependencies are available for the current OS. This + // also means that the platform is installable. + bool compatible = 9; } message InstalledPlatformReference { From 55401e9b04dbe6c4935a4c803a7749363ccbf3a3 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Tue, 7 Nov 2023 16:06:24 +0100 Subject: [PATCH 15/19] apply CR suggestions --- arduino/cores/cores.go | 25 ++++----------- internal/cli/arguments/completion.go | 5 ++- internal/cli/core/search.go | 48 +++++++++++++++------------- 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/arduino/cores/cores.go b/arduino/cores/cores.go index a03d9875db8..e6111345e00 100644 --- a/arduino/cores/cores.go +++ b/arduino/cores/cores.go @@ -236,21 +236,15 @@ func (platform *Platform) GetLatestCompatibleRelease() *PlatformRelease { if len(platform.Releases) == 0 { return nil } - maximum := &PlatformRelease{Version: &semver.Version{}} + var maximum *PlatformRelease for _, release := range platform.Releases { if !release.IsCompatible() { continue } - if release.Version.GreaterThan(maximum.Version) { + if maximum == nil || release.Version.GreaterThan(maximum.Version) { maximum = release } } - - // In case no compatible versions found return nil - if maximum.Version.Equal(&semver.Version{}) { - return nil - } - return maximum } @@ -306,18 +300,13 @@ func (platform *Platform) latestReleaseVersion() *semver.Version { // latestCompatibleReleaseVersion obtains latest version number, for platforms that contains compatible tools, or nil if no release available func (platform *Platform) latestCompatibleReleaseVersion() *semver.Version { versions := platform.GetAllCompatibleReleasesVersions() - if len(versions) == 0 { - return nil - } - max := versions[0] - - for i := 1; i < len(versions); i++ { - if versions[i].GreaterThan(max) { - max = versions[i] + var maxVer *semver.Version + for _, v := range versions { + if maxVer == nil || v.GreaterThan(maxVer) { + maxVer = v } } - - return max + return maxVer } // GetAllInstalled returns all installed PlatformRelease diff --git a/internal/cli/arguments/completion.go b/internal/cli/arguments/completion.go index c6d2753e1cc..843f200c42b 100644 --- a/internal/cli/arguments/completion.go +++ b/internal/cli/arguments/completion.go @@ -113,10 +113,9 @@ func GetInstallableCores() []string { var res []string // transform the data structure for the completion for _, i := range platforms.GetSearchOutput() { - if i.GetLatestCompatibleVersion() == "" { - continue + if latest := i.GetLatestCompatibleRelease(); latest != nil { + res = append(res, i.GetMetadata().GetId()+"\t"+latest.GetName()) } - res = append(res, i.GetMetadata().GetId()+"\t"+i.GetLatestCompatibleRelease().GetName()) } return res } diff --git a/internal/cli/core/search.go b/internal/cli/core/search.go index 276204f1e6b..4e20a129368 100644 --- a/internal/cli/core/search.go +++ b/internal/cli/core/search.go @@ -107,33 +107,35 @@ func (sr searchResults) Data() interface{} { } func (sr searchResults) String() string { - if len(sr.platforms) > 0 { - t := table.New() - t.SetHeader(tr("ID"), tr("Version"), tr("Name")) - for _, platform := range sr.platforms { - // When allVersions is not requested we only show the latest compatible version - if !sr.allVersions { - if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { - name := latestCompatible.Name - if latestCompatible.Deprecated { - name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), latestCompatible.Name) - } - t.AddRow(platform.Id, latestCompatible.Version, name) - } - continue - } + if len(sr.platforms) == 0 { + return tr("No platforms matching your search.") + } + + t := table.New() + t.SetHeader(tr("ID"), tr("Version"), tr("Name")) - for _, release := range platform.Releases.Values() { - name := release.Name - if platform.Deprecated { - name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), release.Name) - } - t.AddRow(platform.Id, release.Version, name) + addRow := func(platform *result.PlatformSummary, release *result.PlatformRelease) { + name := release.Name + if release.Deprecated { + name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), release.Name) + } + t.AddRow(platform.Id, release.Version, name) + } + + for _, platform := range sr.platforms { + // When allVersions is not requested we only show the latest compatible version + if !sr.allVersions { + if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { + addRow(platform, latestCompatible) } + continue + } + + for _, release := range platform.Releases.Values() { + addRow(platform, release) } - return t.Render() } - return tr("No platforms matching your search.") + return t.Render() } // indexesNeedUpdating returns whether one or more index files need updating. From ffbd9a839ced190f5d8f4d040cf44b4b40ea9e27 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Wed, 8 Nov 2023 11:35:07 +0100 Subject: [PATCH 16/19] cr: remove `latest_compatible_version` from gRPC api. We leave only the `latest_compatible` field from the API. This field will have the same meaning the the former `latest_compatible_version`. Meaning that if the `latest_compatible` contains a version it is a release that can be installed. However it might happen that we have newer releases that cannot be installed. If the client is interested to show newer-non-installable-releases, the `releases` field can be used to infer that. --- arduino/cores/packagemanager/download.go | 2 +- commands/board/search.go | 2 +- commands/core/search.go | 24 +-- commands/core/search_test.go | 78 ++------- internal/cli/arguments/completion.go | 8 +- internal/cli/arguments/reference.go | 3 +- internal/cli/compile/compile.go | 5 +- internal/cli/core/list.go | 23 +-- internal/cli/core/search.go | 17 +- internal/cli/core/upgrade.go | 17 +- internal/cli/feedback/result/rpc.go | 59 ++++--- internal/cli/outdated/outdated.go | 6 +- internal/cli/upload/upload.go | 5 +- internal/integrationtest/arduino-cli.go | 5 +- internal/integrationtest/board/board_test.go | 82 ++++------ internal/integrationtest/core/core_test.go | 157 ++++++++++++------- rpc/cc/arduino/cli/commands/v1/common.go | 9 -- rpc/cc/arduino/cli/commands/v1/common.pb.go | 155 +++++++++--------- rpc/cc/arduino/cli/commands/v1/common.proto | 10 +- rpc/cc/arduino/cli/commands/v1/core.pb.go | 48 +++--- rpc/cc/arduino/cli/commands/v1/core.proto | 5 +- 21 files changed, 324 insertions(+), 396 deletions(-) diff --git a/arduino/cores/packagemanager/download.go b/arduino/cores/packagemanager/download.go index b7989b61729..43d13c11ea0 100644 --- a/arduino/cores/packagemanager/download.go +++ b/arduino/cores/packagemanager/download.go @@ -89,7 +89,7 @@ func (pme *Explorer) FindPlatformReleaseDependencies(item *PlatformReference) (* } else { release = platform.GetLatestCompatibleRelease() if release == nil { - return nil, nil, fmt.Errorf(tr("platform %s has no available releases for your OS"), platform.String()) + return nil, nil, fmt.Errorf(tr("platform is not available for your OS")) } } diff --git a/commands/board/search.go b/commands/board/search.go index 007867775e3..bd8702504d7 100644 --- a/commands/board/search.go +++ b/commands/board/search.go @@ -41,7 +41,7 @@ func Search(ctx context.Context, req *rpc.BoardSearchRequest) (*rpc.BoardSearchR foundBoards := []*rpc.BoardListItem{} for _, targetPackage := range pme.GetPackages() { for _, platform := range targetPackage.Platforms { - latestPlatformRelease := platform.GetLatestRelease() + latestPlatformRelease := platform.GetLatestCompatibleRelease() installedPlatformRelease := pme.GetInstalledPlatformRelease(platform) if latestPlatformRelease == nil && installedPlatformRelease == nil { diff --git a/commands/core/search.go b/commands/core/search.go index c766d8637e4..c0341b40a91 100644 --- a/commands/core/search.go +++ b/commands/core/search.go @@ -55,10 +55,7 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse // Discard platforms with no releases latestRelease := platform.GetLatestRelease() - if latestRelease == nil { - continue - } - if latestRelease.Name == "" { + if latestRelease == nil || latestRelease.Name == "" { continue } @@ -91,29 +88,20 @@ func PlatformSearch(req *rpc.PlatformSearchRequest) (*rpc.PlatformSearchResponse } if installed := pme.GetInstalledPlatformRelease(platform); installed != nil { rpcPlatformSummary.InstalledVersion = installed.Version.String() - rpcPlatformSummary.Releases[installed.Version.String()] = commands.PlatformReleaseToRPC(installed) - } - if latest := platform.GetLatestRelease(); latest != nil { - rpcPlatformSummary.LatestVersion = latest.Version.String() - rpcPlatformSummary.Releases[latest.Version.String()] = commands.PlatformReleaseToRPC(latest) } if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { - rpcPlatformSummary.LatestCompatibleVersion = latestCompatible.Version.String() - rpcPlatformSummary.Releases[latestCompatible.Version.String()] = commands.PlatformReleaseToRPC(latestCompatible) + rpcPlatformSummary.LatestVersion = latestCompatible.Version.String() } - if req.AllVersions { - for _, platformRelease := range platform.GetAllReleases() { - rpcPlatformRelease := commands.PlatformReleaseToRPC(platformRelease) - rpcPlatformSummary.Releases[rpcPlatformRelease.Version] = rpcPlatformRelease - } + for _, platformRelease := range platform.GetAllReleases() { + rpcPlatformRelease := commands.PlatformReleaseToRPC(platformRelease) + rpcPlatformSummary.Releases[rpcPlatformRelease.Version] = rpcPlatformRelease } out = append(out, rpcPlatformSummary) } // Sort result alphabetically and put deprecated platforms at the bottom sort.Slice(out, func(i, j int) bool { - return strings.ToLower(out[i].GetLatestRelease().GetName()) < - strings.ToLower(out[j].GetLatestRelease().GetName()) + return strings.ToLower(out[i].GetMetadata().GetId()) < strings.ToLower(out[j].GetMetadata().GetId()) }) sort.SliceStable(out, func(i, j int) bool { return !out[i].GetMetadata().Deprecated && out[j].GetMetadata().Deprecated diff --git a/commands/core/search_test.go b/commands/core/search_test.go index 2babe57ea81..ea3fdc4ef9d 100644 --- a/commands/core/search_test.go +++ b/commands/core/search_test.go @@ -43,9 +43,8 @@ func TestPlatformSearch(t *testing.T) { t.Run("SearchAllVersions", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "retrokit", - AllVersions: true, + Instance: inst, + SearchArgs: "retrokit", }) require.Nil(t, stat) require.NotNil(t, res) @@ -80,48 +79,13 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.0.6", - }) - }) - - t.Run("SearchNoAllVersions", func(t *testing.T) { - res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "retrokit", - AllVersions: false, - }) - require.Nil(t, stat) - require.NotNil(t, res) - require.Len(t, res.SearchOutput, 1) - require.Contains(t, res.SearchOutput, &rpc.PlatformSummary{ - Metadata: &rpc.PlatformMetadata{ - Id: "Retrokits-RK002:arm", - Maintainer: "Retrokits (www.retrokits.com)", - Website: "https://www.retrokits.com", - Email: "info@retrokits.com", - Indexed: true, - }, - Releases: map[string]*rpc.PlatformRelease{ - "1.0.6": { - Name: "RK002", - Type: []string{"Contributed"}, - Installed: false, - Version: "1.0.6", - Boards: []*rpc.Board{{Name: "RK002"}}, - Help: &rpc.HelpResources{Online: "https://www.retrokits.com/rk002/arduino"}, - Compatible: false, - }, - }, - InstalledVersion: "", - LatestVersion: "1.0.6", }) }) t.Run("SearchThePackageMaintainer", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "Retrokits (www.retrokits.com)", - AllVersions: true, + Instance: inst, + SearchArgs: "Retrokits (www.retrokits.com)", }) require.Nil(t, stat) require.NotNil(t, res) @@ -155,15 +119,13 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.0.6", }) }) t.Run("SearchPackageName", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "Retrokits-RK002", - AllVersions: true, + Instance: inst, + SearchArgs: "Retrokits-RK002", }) require.Nil(t, stat) require.NotNil(t, res) @@ -197,15 +159,13 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.0.6", }) }) t.Run("SearchPlatformName", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "rk002", - AllVersions: true, + Instance: inst, + SearchArgs: "rk002", }) require.Nil(t, stat) require.NotNil(t, res) @@ -239,15 +199,13 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.0.6", }) }) t.Run("SearchBoardName", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "Yún", - AllVersions: true, + Instance: inst, + SearchArgs: "Yún", }) require.Nil(t, stat) require.NotNil(t, res) @@ -299,15 +257,13 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.8.3", }) }) t.Run("SearchBoardName2", func(t *testing.T) { res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "yun", - AllVersions: true, + Instance: inst, + SearchArgs: "yun", }) require.Nil(t, stat) require.NotNil(t, res) @@ -359,7 +315,6 @@ func TestPlatformSearch(t *testing.T) { }, }, InstalledVersion: "", - LatestVersion: "1.8.3", }) }) } @@ -381,17 +336,16 @@ func TestPlatformSearchSorting(t *testing.T) { require.NotNil(t, inst) res, stat := PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "", - AllVersions: false, + Instance: inst, + SearchArgs: "", }) require.Nil(t, stat) require.NotNil(t, res) require.Len(t, res.SearchOutput, 3) - require.Equal(t, res.SearchOutput[0].GetLatestRelease().Name, "Arduino AVR Boards") + require.Equal(t, res.SearchOutput[0].GetSortedReleases()[0].Name, "Arduino AVR Boards") require.Equal(t, res.SearchOutput[0].Metadata.Deprecated, false) - require.Equal(t, res.SearchOutput[1].GetLatestRelease().Name, "RK002") + require.Equal(t, res.SearchOutput[1].GetSortedReleases()[0].Name, "RK002") require.Equal(t, res.SearchOutput[1].Metadata.Deprecated, false) require.Equal(t, res.SearchOutput[2].GetLatestRelease().Name, "Platform") require.Equal(t, res.SearchOutput[2].Metadata.Deprecated, true) diff --git a/internal/cli/arguments/completion.go b/internal/cli/arguments/completion.go index 843f200c42b..89423edd1a7 100644 --- a/internal/cli/arguments/completion.go +++ b/internal/cli/arguments/completion.go @@ -85,7 +85,6 @@ func GetUninstallableCores() []string { platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{ Instance: inst, - AllVersions: false, ManuallyInstalled: true, }) @@ -106,14 +105,13 @@ func GetInstallableCores() []string { inst := instance.CreateAndInit() platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: "", - AllVersions: false, + Instance: inst, + SearchArgs: "", }) var res []string // transform the data structure for the completion for _, i := range platforms.GetSearchOutput() { - if latest := i.GetLatestCompatibleRelease(); latest != nil { + if latest := i.GetLatestRelease(); latest != nil { res = append(res, i.GetMetadata().GetId()+"\t"+latest.GetName()) } } diff --git a/internal/cli/arguments/reference.go b/internal/cli/arguments/reference.go index f9d8737d415..ed6152af5b8 100644 --- a/internal/cli/arguments/reference.go +++ b/internal/cli/arguments/reference.go @@ -96,8 +96,7 @@ func ParseReference(arg string) (*Reference, error) { // try to use core.PlatformList to optimize what the user typed // (by replacing the PackageName and Architecture in ret with the content of core.GetPlatform()) platforms, _ := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: instance.CreateAndInit(), - AllVersions: false, + Instance: instance.CreateAndInit(), }) foundPlatforms := []string{} for _, platform := range platforms.GetSearchOutput() { diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index 1204b529f17..7cd66de7663 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -370,9 +370,8 @@ func runCompileCommand(cmd *cobra.Command, args []string) { res.Error += fmt.Sprintln() if platform, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: platformErr.Platform, - AllVersions: false, + Instance: inst, + SearchArgs: platformErr.Platform, }); err != nil { res.Error += err.Error() } else if len(platform.GetSearchOutput()) > 0 { diff --git a/internal/cli/core/list.go b/internal/cli/core/list.go index 502ce85ac20..40ac933f027 100644 --- a/internal/cli/core/list.go +++ b/internal/cli/core/list.go @@ -16,7 +16,6 @@ package core import ( - "fmt" "os" "github.com/arduino/arduino-cli/commands/core" @@ -63,7 +62,6 @@ func List(inst *rpc.Instance, all bool, updatableOnly bool) { func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.PlatformSummary { platforms, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ Instance: inst, - AllVersions: true, ManuallyInstalled: true, }) if err != nil { @@ -80,7 +78,7 @@ func GetList(inst *rpc.Instance, all bool, updatableOnly bool) []*rpc.PlatformSu if platform.InstalledVersion == "" && !platform.GetMetadata().ManuallyInstalled { continue } - if updatableOnly && platform.InstalledVersion == platform.LatestCompatibleVersion { + if updatableOnly && platform.InstalledVersion == platform.LatestVersion { continue } result = append(result, platform) @@ -117,22 +115,11 @@ func (ir coreListResult) String() string { t := table.New() t.SetHeader(tr("ID"), tr("Installed"), tr("Latest"), tr("Name")) for _, platform := range ir.platforms { - var name string - if installed := platform.GetInstalledRelease(); installed != nil { - name = installed.Name + latestVersion := platform.LatestVersion.String() + if latestVersion == "" { + latestVersion = "n/a" } - if name == "" { - if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { - name = latestCompatible.Name - } else if latest := platform.GetLatestRelease(); latest != nil && name == "" { - name = latest.Name - } - } - if platform.Deprecated { - name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name) - } - - t.AddRow(platform.Id, platform.InstalledVersion, platform.LatestCompatibleVersion, name) + t.AddRow(platform.Id, platform.InstalledVersion, latestVersion, platform.GetPlatformName()) } return t.Render() diff --git a/internal/cli/core/search.go b/internal/cli/core/search.go index 4e20a129368..0fc2389cdd8 100644 --- a/internal/cli/core/search.go +++ b/internal/cli/core/search.go @@ -72,9 +72,8 @@ func runSearchCommand(cmd *cobra.Command, args []string, allVersions bool) { logrus.Infof("Executing `arduino-cli core search` with args: '%s'", arguments) resp, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: arguments, - AllVersions: allVersions, + Instance: inst, + SearchArgs: arguments, }) if err != nil { feedback.Fatal(tr("Error searching for platforms: %v", err), feedback.ErrGeneric) @@ -115,19 +114,17 @@ func (sr searchResults) String() string { t.SetHeader(tr("ID"), tr("Version"), tr("Name")) addRow := func(platform *result.PlatformSummary, release *result.PlatformRelease) { - name := release.Name - if release.Deprecated { - name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), release.Name) + if release == nil { + t.AddRow(platform.Id, "n/a", platform.GetPlatformName()) + return } - t.AddRow(platform.Id, release.Version, name) + t.AddRow(platform.Id, release.Version, release.FormatName()) } for _, platform := range sr.platforms { // When allVersions is not requested we only show the latest compatible version if !sr.allVersions { - if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { - addRow(platform, latestCompatible) - } + addRow(platform, platform.GetLatestRelease()) continue } diff --git a/internal/cli/core/upgrade.go b/internal/cli/core/upgrade.go index d6dfd243aed..93bc6c0720f 100644 --- a/internal/cli/core/upgrade.go +++ b/internal/cli/core/upgrade.go @@ -61,8 +61,7 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUni // if no platform was passed, upgrade allthethings if len(args) == 0 { platforms, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - AllVersions: false, + Instance: inst, }) if err != nil { feedback.Fatal(tr("Error retrieving core list: %v", err), feedback.ErrGeneric) @@ -73,14 +72,14 @@ func Upgrade(inst *rpc.Instance, args []string, skipPostInstall bool, skipPreUni if platform.InstalledVersion == "" { continue } - if platform.InstalledVersion == platform.LatestCompatibleVersion { - // if it's not updatable, skip it - continue + // if it's not updatable, skip it + latestRelease := platform.GetLatestRelease() + if latestRelease != nil && platform.InstalledVersion != latestRelease.Version { + targets = append(targets, &rpc.Platform{ + Metadata: platform.GetMetadata(), + Release: latestRelease, + }) } - targets = append(targets, &rpc.Platform{ - Metadata: platform.GetMetadata(), - Release: platform.GetLatestCompatibleRelease(), - }) } if len(targets) == 0 { diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go index 1d9664f9cec..63291754fe7 100644 --- a/internal/cli/feedback/result/rpc.go +++ b/internal/cli/feedback/result/rpc.go @@ -17,13 +17,17 @@ package result import ( "cmp" + "fmt" + "github.com/arduino/arduino-cli/i18n" f "github.com/arduino/arduino-cli/internal/algorithms" "github.com/arduino/arduino-cli/internal/orderedmap" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" semver "go.bug.st/relaxed-semver" ) +var tr = i18n.Tr + // NewPlatformSummary creates a new result.PlatformSummary from rpc.PlatformSummary func NewPlatformSummary(in *rpc.PlatformSummary) *PlatformSummary { if in == nil { @@ -37,17 +41,16 @@ func NewPlatformSummary(in *rpc.PlatformSummary) *PlatformSummary { releases.SortKeys((*semver.Version).CompareTo) return &PlatformSummary{ - Id: in.GetMetadata().GetId(), - Maintainer: in.GetMetadata().GetMaintainer(), - Website: in.GetMetadata().GetWebsite(), - Email: in.GetMetadata().GetEmail(), - ManuallyInstalled: in.GetMetadata().GetManuallyInstalled(), - Deprecated: in.GetMetadata().GetDeprecated(), - Indexed: in.GetMetadata().GetIndexed(), - Releases: releases, - InstalledVersion: semver.MustParse(in.GetInstalledVersion()), - LatestVersion: semver.MustParse(in.GetLatestVersion()), - LatestCompatibleVersion: semver.MustParse(in.LatestCompatibleVersion), + Id: in.GetMetadata().GetId(), + Maintainer: in.GetMetadata().GetMaintainer(), + Website: in.GetMetadata().GetWebsite(), + Email: in.GetMetadata().GetEmail(), + ManuallyInstalled: in.GetMetadata().GetManuallyInstalled(), + Deprecated: in.GetMetadata().GetDeprecated(), + Indexed: in.GetMetadata().GetIndexed(), + Releases: releases, + InstalledVersion: semver.MustParse(in.GetInstalledVersion()), + LatestVersion: semver.MustParse(in.GetLatestVersion()), } } @@ -63,9 +66,8 @@ type PlatformSummary struct { Releases orderedmap.Map[*semver.Version, *PlatformRelease] `json:"releases,omitempty"` - InstalledVersion *semver.Version `json:"installed_version,omitempty"` - LatestVersion *semver.Version `json:"latest_version,omitempty"` - LatestCompatibleVersion *semver.Version `json:"latest_compatible_version,omitempty"` + InstalledVersion *semver.Version `json:"installed_version,omitempty"` + LatestVersion *semver.Version `json:"latest_version,omitempty"` } // GetLatestRelease returns the latest relase of this platform or nil if none available. @@ -73,16 +75,28 @@ func (p *PlatformSummary) GetLatestRelease() *PlatformRelease { return p.Releases.Get(p.LatestVersion) } -// GetLatestCompatibleRelease returns the latest relase of this platform or nil if none available. -func (p *PlatformSummary) GetLatestCompatibleRelease() *PlatformRelease { - return p.Releases.Get(p.LatestCompatibleVersion) -} - // GetInstalledRelease returns the installed relase of this platform or nil if none available. func (p *PlatformSummary) GetInstalledRelease() *PlatformRelease { return p.Releases.Get(p.InstalledVersion) } +// GetPlatformName compute the name of the platform based on the installed/available releases. +func (p *PlatformSummary) GetPlatformName() string { + var name string + if installed := p.GetInstalledRelease(); installed != nil { + name = installed.FormatName() + } + if name == "" { + if latest := p.GetLatestRelease(); latest != nil { + name = latest.FormatName() + } else { + keys := p.Releases.Keys() + name = p.Releases.Get(keys[len(keys)-1]).FormatName() + } + } + return name +} + // NewPlatformRelease creates a new result.PlatformRelease from rpc.PlatformRelease func NewPlatformRelease(in *rpc.PlatformRelease) *PlatformRelease { if in == nil { @@ -128,6 +142,13 @@ type PlatformRelease struct { Compatible bool `json:"compatible"` } +func (p *PlatformRelease) FormatName() string { + if p.Deprecated { + return fmt.Sprintf("[%s] %s", tr("DEPRECATED"), p.Name) + } + return p.Name +} + // Board maps a rpc.Board type Board struct { Name string `json:"name,omitempty"` diff --git a/internal/cli/outdated/outdated.go b/internal/cli/outdated/outdated.go index 9d4cb39f218..39cba04481c 100644 --- a/internal/cli/outdated/outdated.go +++ b/internal/cli/outdated/outdated.go @@ -109,13 +109,13 @@ func (ir outdatedResult) String() string { // Based on internal/cli/core/list.go for _, p := range ir.Platforms { name := "" - if latestCompatible := p.GetLatestCompatibleRelease(); latestCompatible != nil { - name = latestCompatible.Name + if latest := p.GetLatestRelease(); latest != nil { + name = latest.Name } if p.Deprecated { name = fmt.Sprintf("[%s] %s", tr("DEPRECATED"), name) } - t.AddRow(p.Id, name, p.InstalledVersion, p.LatestCompatibleVersion, "", "") + t.AddRow(p.Id, name, p.InstalledVersion, p.LatestVersion, "", "") } // Based on internal/cli/lib/list.go diff --git a/internal/cli/upload/upload.go b/internal/cli/upload/upload.go index 73e6166aaaa..7bbc868bf9b 100644 --- a/internal/cli/upload/upload.go +++ b/internal/cli/upload/upload.go @@ -138,9 +138,8 @@ func runUploadCommand(args []string, uploadFieldsArgs map[string]string) { msg += "\n" if platform, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ - Instance: inst, - SearchArgs: platformErr.Platform, - AllVersions: false, + Instance: inst, + SearchArgs: platformErr.Platform, }); err != nil { msg += err.Error() } else if len(platform.GetSearchOutput()) > 0 { diff --git a/internal/integrationtest/arduino-cli.go b/internal/integrationtest/arduino-cli.go index 78ed4dbb3e9..c2b10f7e121 100644 --- a/internal/integrationtest/arduino-cli.go +++ b/internal/integrationtest/arduino-cli.go @@ -576,9 +576,8 @@ func (inst *ArduinoCLIInstance) PlatformUpgrade(ctx context.Context, packager, a // PlatformSearch calls the "PlatformSearch" gRPC method. func (inst *ArduinoCLIInstance) PlatformSearch(ctx context.Context, args string, all bool) (*commands.PlatformSearchResponse, error) { req := &commands.PlatformSearchRequest{ - Instance: inst.instance, - SearchArgs: args, - AllVersions: all, + Instance: inst.instance, + SearchArgs: args, } logCallf(">>> PlatformSearch(%+v)\n", req) resp, err := inst.cli.daemonClient.PlatformSearch(ctx, req) diff --git a/internal/integrationtest/board/board_test.go b/internal/integrationtest/board/board_test.go index 70c53de9039..2faadee644e 100644 --- a/internal/integrationtest/board/board_test.go +++ b/internal/integrationtest/board/board_test.go @@ -16,7 +16,6 @@ package board_test import ( - "encoding/json" "os" "strings" "testing" @@ -25,7 +24,6 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/stretchr/testify/require" - semver "go.bug.st/relaxed-semver" "go.bug.st/testifyjson/requirejson" ) @@ -182,26 +180,36 @@ func TestBoardListall(t *testing.T) { "name": "Arduino Yún", "fqbn": "arduino:avr:yun", "platform": { - "id": "arduino:avr", - "installed": "1.8.3", - "name": "Arduino AVR Boards" + "metadata": { + "id": "arduino:avr" + }, + "release": { + "name": "Arduino AVR Boards", + "version": "1.8.3", + "installed": true + } } }, { "name": "Arduino Uno", "fqbn": "arduino:avr:uno", "platform": { - "id": "arduino:avr", - "installed": "1.8.3", - "name": "Arduino AVR Boards" + "metadata": { + "id": "arduino:avr" + }, + "release": { + "name": "Arduino AVR Boards", + "version": "1.8.3", + "installed": true + } } } ] }`) - // Check if the boards' "latest" value is not empty + // Check if the boards' "version" value is not empty requirejson.Parse(t, stdout). - Query(`[ .boards | .[] | .platform | select(.latest == "") ]`). + Query(`[ .boards | .[] | .platform | select(.version == "") ]`). MustBeEmpty() } @@ -232,20 +240,28 @@ func TestBoardListallWithManuallyInstalledPlatform(t *testing.T) { "name": "Arduino MKR1000", "fqbn": "arduino-beta-development:samd:mkr1000", "platform": { - "id": "arduino-beta-development:samd", - "installed": "1.8.11", - "latest": "1.8.11", - "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards", + "metadata": { + "id": "arduino-beta-development:samd", + }, + "release": { + "installed": true, + "version": "1.8.11", + "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" + }, } }, { "name": "Arduino NANO 33 IoT", "fqbn": "arduino-beta-development:samd:nano_33_iot", "platform": { - "id": "arduino-beta-development:samd", - "installed": "1.8.11", - "latest": "1.8.11", - "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" + "metadata": { + "id": "arduino-beta-development:samd", + }, + "release": { + "installed": true, + "version": "1.8.11", + "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" + }, } } ] @@ -575,36 +591,6 @@ func TestBoardAttach(t *testing.T) { } } -func TestBoardSearchWithOutdatedCore(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("update") - require.NoError(t, err) - - // Install an old core version - _, _, err = cli.Run("core", "install", "arduino:samd@1.8.6") - require.NoError(t, err) - - stdout, _, err := cli.Run("board", "search", "arduino:samd:mkrwifi1010", "--format", "json") - require.NoError(t, err) - requirejson.Len(t, stdout, 1) - var data []map[string]interface{} - err = json.Unmarshal(stdout, &data) - require.NoError(t, err) - board := data[0] - require.Equal(t, board["name"], "Arduino MKR WiFi 1010") - require.Equal(t, board["fqbn"], "arduino:samd:mkrwifi1010") - samdCore := board["platform"].(map[string]interface{}) - require.Equal(t, samdCore["id"], "arduino:samd") - installedVersion, err := semver.Parse(samdCore["installed"].(string)) - require.NoError(t, err) - latestVersion, err := semver.Parse(samdCore["latest"].(string)) - require.NoError(t, err) - // Installed version must be older than latest - require.True(t, installedVersion.LessThan(latestVersion)) -} - func TestBoardListWithFailedBuiltinInstallation(t *testing.T) { env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) defer env.CleanUp() diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index 6406bf3854d..c9db2e7701e 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -182,7 +182,7 @@ func TestCoreSearchNoArgs(t *testing.T) { stdout, _, err = cli.Run("core", "search", "--format", "json") require.NoError(t, err) requirejson.Contains(t, stdout, `[{"id": "test:x86", "releases": { "2.0.0": {"name":"test_core"}}}]`) - requirejson.Query(t, stdout, `[.[] | select(.latest_compatible_version != "")] | length`, fmt.Sprint(numPlatforms)) + requirejson.Len(t, stdout, numPlatforms) // list all with additional urls, check the test core is there stdout, _, err = cli.Run("core", "search", "--additional-urls="+url.String()) @@ -191,15 +191,27 @@ func TestCoreSearchNoArgs(t *testing.T) { for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { lines = append(lines, strings.Fields(strings.TrimSpace(v))) } - // Check the absence of test:x86@3.0.0 because it contains incompatible deps + // Check the absence of test:x86@3.0.0 because it contains incompatible deps. The latest available should be the 2.0.0 require.NotContains(t, lines, []string{"test:x86", "3.0.0", "test_core"}) + require.Contains(t, lines, []string{"test:x86", "2.0.0", "test_core"}) numPlatforms = len(lines) - 1 // same thing in JSON format, also check the number of platforms found is the same stdout, _, err = cli.Run("core", "search", "--format", "json", "--additional-urls="+url.String()) require.NoError(t, err) - requirejson.Contains(t, stdout, `[{"id": "test:x86", "releases": { "3.0.0": {"name":"test_core"}}}]`) - requirejson.Query(t, stdout, `[.[] | select(.latest_compatible_version != "")] | length`, fmt.Sprint(numPlatforms)) + requirejson.Contains(t, stdout, `[ + { + "id": "test:x86", + "installed_version": "2.0.0", + "latest_version": "2.0.0", + "releases": { + "1.0.0": {"name":"test_core", "compatible": true}, + "2.0.0": {"name":"test_core", "compatible": true}, + "3.0.0": {"name":"test_core", "compatible": false} + } + } + ]`) + requirejson.Len(t, stdout, numPlatforms) } func TestCoreUpdateIndexUrlNotFound(t *testing.T) { @@ -710,10 +722,10 @@ func TestCoreSearchSortedResults(t *testing.T) { // verify that results are already sorted correctly require.True(t, sort.SliceIsSorted(deprecated, func(i, j int) bool { - return strings.ToLower(deprecated[i][2]) < strings.ToLower(deprecated[j][2]) + return strings.ToLower(deprecated[i][0]) < strings.ToLower(deprecated[j][0]) })) require.True(t, sort.SliceIsSorted(notDeprecated, func(i, j int) bool { - return strings.ToLower(notDeprecated[i][2]) < strings.ToLower(notDeprecated[j][2]) + return strings.ToLower(notDeprecated[i][0]) < strings.ToLower(notDeprecated[j][0]) })) // verify that deprecated platforms are the last ones @@ -725,20 +737,20 @@ func TestCoreSearchSortedResults(t *testing.T) { // verify that results are already sorted correctly sortedDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated == true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name] | sort").String() + "[ .[] | select(.deprecated == true) | .id |=ascii_downcase | .id] | sort").String() notSortedDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated == true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | select(.deprecated == true) | .id |=ascii_downcase | .id]").String() require.Equal(t, sortedDeprecated, notSortedDeprecated) sortedNotDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated != true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name] | sort").String() + "[ .[] | select(.deprecated != true) | .id |=ascii_downcase | .id] | sort").String() notSortedNotDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated != true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | select(.deprecated != true) | .id |=ascii_downcase | .id]").String() require.Equal(t, sortedNotDeprecated, notSortedNotDeprecated) // verify that deprecated platforms are the last ones platform := requirejson.Parse(t, stdout).Query( - "[ .[] | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | .id |=ascii_downcase | .id]").String() require.Equal(t, platform, strings.TrimRight(notSortedNotDeprecated, "]")+","+strings.TrimLeft(notSortedDeprecated, "[")) } @@ -781,10 +793,10 @@ func TestCoreListSortedResults(t *testing.T) { // verify that results are already sorted correctly require.True(t, sort.SliceIsSorted(deprecated, func(i, j int) bool { - return strings.ToLower(deprecated[i][3]) < strings.ToLower(deprecated[j][3]) + return strings.ToLower(deprecated[i][0]) < strings.ToLower(deprecated[j][0]) })) require.True(t, sort.SliceIsSorted(notDeprecated, func(i, j int) bool { - return strings.ToLower(notDeprecated[i][3]) < strings.ToLower(notDeprecated[j][3]) + return strings.ToLower(notDeprecated[i][0]) < strings.ToLower(notDeprecated[j][0]) })) // verify that deprecated platforms are the last ones @@ -797,20 +809,20 @@ func TestCoreListSortedResults(t *testing.T) { // verify that results are already sorted correctly sortedDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated == true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name] | sort").String() + "[ .[] | select(.deprecated == true) | .id |=ascii_downcase | .id] | sort").String() notSortedDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated == true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | select(.deprecated == true) | .id |=ascii_downcase | .id]").String() require.Equal(t, sortedDeprecated, notSortedDeprecated) sortedNotDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated != true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name] | sort").String() + "[ .[] | select(.deprecated != true) | .id |=ascii_downcase | .id] | sort").String() notSortedNotDeprecated := requirejson.Parse(t, stdout).Query( - "[ .[] | select(.deprecated != true) | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | select(.deprecated != true) | .id |=ascii_downcase | .id]").String() require.Equal(t, sortedNotDeprecated, notSortedNotDeprecated) // verify that deprecated platforms are the last ones platform := requirejson.Parse(t, stdout).Query( - "[ .[] | {name: .releases[.latest_version].name} | .name |=ascii_downcase | .name]").String() + "[ .[] | .id |=ascii_downcase | .id]").String() require.Equal(t, platform, strings.TrimRight(notSortedNotDeprecated, "]")+","+strings.TrimLeft(notSortedDeprecated, "[")) } @@ -1120,51 +1132,70 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { _, _, err := cli.Run("core", "update-index", additionalURLs) require.NoError(t, err) - // check that list shows only compatible versions + // the `latest_version` must point to an installable release. In the releases field the latest entry, points to an incompatible version. stdout, _, err := cli.Run("core", "list", "--all", "--format", "json", additionalURLs) require.NoError(t, err) - t.Log(string(stdout)) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_version`, `"1.0.2"`) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr")`). + MustContain(`{ + "installed_version": "", + "latest_version": "1.0.1", + "releases": { + "1.0.0": {"compatible": true}, + "1.0.1": {"compatible": true}, + "1.0.2": {"compatible": false} + } + }`) // install latest compatible version _, _, err = cli.Run("core", "install", "foo_vendor:avr", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--all", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr")`). + MustContain(`{ + "latest_version": "1.0.1", + "installed_version": "1.0.1", + "releases": {"1.0.1": {"compatible": true}} + }`) - // install incompatible version + // install a specific incompatible version _, stderr, err := cli.Run("core", "install", "foo_vendor:avr@1.0.2", additionalURLs) require.Error(t, err) require.Contains(t, string(stderr), "no versions available for the current OS") - // install compatible version + // install a specific compatible version _, _, err = cli.Run("core", "install", "foo_vendor:avr@1.0.0", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.0"`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr")`). + MustContain(`{"installed_version": "1.0.0", "releases": {"1.0.0": {"compatible": true}}}`) // Lists all updatable cores stdout, _, err = cli.Run("core", "list", "--updatable", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_compatible_version`, `"1.0.1"`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr")`). + MustContain(`{"latest_version": "1.0.1", "releases": {"1.0.1": {"compatible": true}}}`) // Show outdated cores, must show latest compatible stdout, _, err = cli.Run("outdated", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, - `.platforms | .[] | select(.id == "foo_vendor:avr") | {latest_compatible: .latest_compatible_version, latest: .latest_version}`, - `{"latest_compatible": "1.0.1", "latest": "1.0.2"}`, - ) + requirejson.Parse(t, stdout). + Query(`.platforms | .[] | select(.id == "foo_vendor:avr")`). + MustContain(`{"latest_version": "1.0.1", "releases":{"1.0.1": {"compatible": true}}}`) // upgrade to latest compatible (1.0.0 -> 1.0.1) _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) require.NoError(t, err) stdout, _, err = cli.Run("core", "list", "--format", "json", additionalURLs) require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.1"`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr") | .releases[.installed_version]`). + MustContain(`{"version": "1.0.1", "compatible": true}`) // upgrade to latest incompatible not possible (1.0.1 -> 1.0.2) _, _, err = cli.Run("core", "upgrade", "foo_vendor:avr", "--format", "json", additionalURLs) @@ -1174,34 +1205,44 @@ func TestCoreHavingIncompatibleDepTools(t *testing.T) { requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .installed_version`, `"1.0.1"`) // When no compatible version are found return error + // When trying to install a platform with no compatible version fails _, stderr, err = cli.Run("core", "install", "incompatible_vendor:avr", additionalURLs) require.Error(t, err) - require.Contains(t, string(stderr), "has no available releases for your OS") - - // Core search --all shows incompatible field when a version is incompatible - stdout, _, err = cli.Run("core", "search", "--all", "--format", "json", additionalURLs) - require.NoError(t, err) - requirejson.Query(t, stdout, - `[.[] | select(.id == "foo_vendor:avr") | .releases | map(.) | .[] | {version: .version, compatible: .compatible}] | sort_by(.version)`, - `[ - {"compatible":true,"version":"1.0.0"}, - {"compatible":true,"version":"1.0.1"}, - {"compatible":false,"version":"1.0.2"} - ]`, - ) + require.Contains(t, string(stderr), "is not available for your OS") - // Core search shows latest compatible version even if incompatible - stdout, _, err = cli.Run("core", "search", "--format", "json", additionalURLs) - require.NoError(t, err) - requirejson.Query(t, stdout, `.[] | select(.id == "foo_vendor:avr") | .latest_version`, `"1.0.2"`) - requirejson.Query(t, stdout, `.[] | select(.id == "incompatible_vendor:avr") | .releases[.latest_version].compatible`, `false`) - - // In text mode, core search doesn't show any version if no compatible one are present - stdout, _, err = cli.Run("core", "search", additionalURLs) - require.NoError(t, err) - var lines [][]string - for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { - lines = append(lines, strings.Fields(strings.TrimSpace(v))) + // Core search + { + // core search with and without --all produces the same results. + stdoutSearchAll, _, err := cli.Run("core", "search", "--all", "--format", "json", additionalURLs) + require.NoError(t, err) + stdoutSearch, _, err := cli.Run("core", "search", "--format", "json", additionalURLs) + require.NoError(t, err) + require.Equal(t, stdoutSearchAll, stdoutSearch) + for _, stdout := range [][]byte{stdoutSearchAll, stdoutSearch} { + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "foo_vendor:avr")`). + MustContain(`{ + "latest_version": "1.0.1", + "releases": { + "1.0.0": {"compatible": true}, + "1.0.1": {"compatible": true}, + "1.0.2": {"compatible": false} + } + }`) + requirejson.Parse(t, stdout). + Query(`.[] | select(.id == "incompatible_vendor:avr")`). + MustContain(`{"latest_version": "", "releases": { "1.0.0": {"compatible": false}}}`) + } + // In text mode, core search shows `n/a` for core that doesn't have any compatible version + stdout, _, err := cli.Run("core", "search", additionalURLs) + require.NoError(t, err) + var lines [][]string + for _, v := range strings.Split(strings.TrimSpace(string(stdout)), "\n") { + lines = append(lines, strings.Fields(strings.TrimSpace(v))) + if strings.Contains(v, "incompatible_vendor:avr") { + t.Log(strings.Fields(strings.TrimSpace(v))) + } + } + require.Contains(t, lines, []string{"incompatible_vendor:avr", "n/a", "Incompatible", "Boards"}) } - require.NotContains(t, lines, []string{"incompatible_vendor:avr"}) } diff --git a/rpc/cc/arduino/cli/commands/v1/common.go b/rpc/cc/arduino/cli/commands/v1/common.go index e98b59780d3..a04ebff193f 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.go +++ b/rpc/cc/arduino/cli/commands/v1/common.go @@ -78,15 +78,6 @@ func (s *PlatformSummary) GetLatestRelease() *PlatformRelease { return s.Releases[s.LatestVersion] } -// GetLatestCompatibleRelease returns the latest compatible release in this PlatformSummary, -// or nil if not available. -func (s *PlatformSummary) GetLatestCompatibleRelease() *PlatformRelease { - if s.LatestCompatibleVersion == "" { - return nil - } - return s.Releases[s.LatestCompatibleVersion] -} - // GetInstalledRelease returns the latest release in this PlatformSummary, // or nil if not available. func (s *PlatformSummary) GetInstalledRelease() *PlatformRelease { diff --git a/rpc/cc/arduino/cli/commands/v1/common.pb.go b/rpc/cc/arduino/cli/commands/v1/common.pb.go index 66f1cd1d14b..28bc1b6ed68 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/common.pb.go @@ -560,11 +560,9 @@ type PlatformSummary struct { Releases map[string]*PlatformRelease `protobuf:"bytes,2,rep,name=releases,proto3" json:"releases,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // The installed version of the platform, or empty string if none installed InstalledVersion string `protobuf:"bytes,3,opt,name=installed_version,json=installedVersion,proto3" json:"installed_version,omitempty"` - // The latest available version of the platform, or empty if none available + // The latest available version of the platform that can be installable, or + // empty if none available. LatestVersion string `protobuf:"bytes,4,opt,name=latest_version,json=latestVersion,proto3" json:"latest_version,omitempty"` - // The latest available version of the platform containing all compatible - // dependencies, or empty if none available - LatestCompatibleVersion string `protobuf:"bytes,5,opt,name=latest_compatible_version,json=latestCompatibleVersion,proto3" json:"latest_compatible_version,omitempty"` } func (x *PlatformSummary) Reset() { @@ -627,13 +625,6 @@ func (x *PlatformSummary) GetLatestVersion() string { return "" } -func (x *PlatformSummary) GetLatestCompatibleVersion() string { - if x != nil { - return x.LatestCompatibleVersion - } - return "" -} - // PlatformMetadata contains generic information about a platform (not // correlated to a specific release). type PlatformMetadata struct { @@ -771,8 +762,8 @@ type PlatformRelease struct { MissingMetadata bool `protobuf:"varint,7,opt,name=missing_metadata,json=missingMetadata,proto3" json:"missing_metadata,omitempty"` // True this release is deprecated Deprecated bool `protobuf:"varint,8,opt,name=deprecated,proto3" json:"deprecated,omitempty"` - // True if the platform dependencies are available for the current OS. This - // also means that the platform is installable. + // True if the platform dependencies are available for the current OS/ARCH. + // This also means that the platform is installable. Compatible bool `protobuf:"varint,9,opt,name=compatible,proto3" json:"compatible,omitempty"` } @@ -1171,7 +1162,7 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x32, 0x2b, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x07, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0xac, 0x03, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0xf0, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x48, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, @@ -1187,76 +1178,72 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x3a, 0x0a, 0x19, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, - 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x17, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x74, - 0x69, 0x62, 0x6c, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x68, 0x0a, 0x0d, 0x52, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, - 0x72, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x61, - 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x77, 0x65, - 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x77, 0x65, 0x62, - 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2d, 0x0a, 0x12, 0x6d, 0x61, - 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, - 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, - 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x65, 0x64, 0x22, 0xd6, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x6e, - 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x62, 0x6f, 0x61, 0x72, 0x64, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, - 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, 0x62, 0x6f, 0x61, 0x72, - 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, - 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x65, - 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x04, 0x68, 0x65, 0x6c, - 0x70, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, - 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, - 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x22, 0x88, 0x01, 0x0a, - 0x1a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, - 0x72, 0x6d, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, - 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x2f, 0x0a, 0x05, 0x42, 0x6f, 0x61, 0x72, 0x64, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x31, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x66, - 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x27, 0x0a, 0x0d, 0x48, - 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x6e, - 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, - 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, 0x72, - 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, + 0x68, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, + 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, + 0x0a, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2d, + 0x0a, 0x12, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, + 0x61, 0x6c, 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1e, 0x0a, + 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, + 0x07, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x22, 0xd6, 0x02, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x39, 0x0a, 0x06, 0x62, + 0x6f, 0x61, 0x72, 0x64, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x63, + 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x68, 0x65, 0x6c, 0x70, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, + 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, + 0x04, 0x68, 0x65, 0x6c, 0x70, 0x12, 0x29, 0x0a, 0x10, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, + 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0f, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, + 0x22, 0x88, 0x01, 0x0a, 0x1a, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6c, 0x6c, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x44, 0x69, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x55, 0x72, 0x6c, 0x22, 0x2f, 0x0a, 0x05, 0x42, + 0x6f, 0x61, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, 0x31, 0x0a, 0x07, + 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, + 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x22, + 0x27, 0x0a, 0x0d, 0x48, 0x65, 0x6c, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, + 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, + 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/cc/arduino/cli/commands/v1/common.proto b/rpc/cc/arduino/cli/commands/v1/common.proto index 13befb5bf82..9a324985d54 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.proto +++ b/rpc/cc/arduino/cli/commands/v1/common.proto @@ -89,11 +89,9 @@ message PlatformSummary { map releases = 2; // The installed version of the platform, or empty string if none installed string installed_version = 3; - // The latest available version of the platform, or empty if none available + // The latest available version of the platform that can be installable, or + // empty if none available. string latest_version = 4; - // The latest available version of the platform containing all compatible - // dependencies, or empty if none available - string latest_compatible_version = 5; } // PlatformMetadata contains generic information about a platform (not @@ -144,8 +142,8 @@ message PlatformRelease { bool missing_metadata = 7; // True this release is deprecated bool deprecated = 8; - // True if the platform dependencies are available for the current OS. This - // also means that the platform is installable. + // True if the platform dependencies are available for the current OS/ARCH. + // This also means that the platform is installable. bool compatible = 9; } diff --git a/rpc/cc/arduino/cli/commands/v1/core.pb.go b/rpc/cc/arduino/cli/commands/v1/core.pb.go index dca289c80fd..6c3bcb7c5ed 100644 --- a/rpc/cc/arduino/cli/commands/v1/core.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/core.pb.go @@ -682,12 +682,9 @@ type PlatformSearchRequest struct { Instance *Instance `protobuf:"bytes,1,opt,name=instance,proto3" json:"instance,omitempty"` // Keywords for the search. SearchArgs string `protobuf:"bytes,2,opt,name=search_args,json=searchArgs,proto3" json:"search_args,omitempty"` - // Whether to show all available versions. `false` causes only the newest - // versions of the cores to be listed in the search results. - AllVersions bool `protobuf:"varint,3,opt,name=all_versions,json=allVersions,proto3" json:"all_versions,omitempty"` // Whether to show manually installed platforms. `false` causes to skip // manually installed platforms. - ManuallyInstalled bool `protobuf:"varint,4,opt,name=manually_installed,json=manuallyInstalled,proto3" json:"manually_installed,omitempty"` + ManuallyInstalled bool `protobuf:"varint,3,opt,name=manually_installed,json=manuallyInstalled,proto3" json:"manually_installed,omitempty"` } func (x *PlatformSearchRequest) Reset() { @@ -736,13 +733,6 @@ func (x *PlatformSearchRequest) GetSearchArgs() string { return "" } -func (x *PlatformSearchRequest) GetAllVersions() bool { - if x != nil { - return x.AllVersions - } - return false -} - func (x *PlatformSearchRequest) GetManuallyInstalled() bool { if x != nil { return x.ManuallyInstalled @@ -913,7 +903,7 @@ var file_cc_arduino_cli_commands_v1_core_proto_rawDesc = []byte{ 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0xcc, 0x01, + 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0xa9, 0x01, 0x0a, 0x15, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, @@ -921,24 +911,22 @@ var file_cc_arduino_cli_commands_v1_core_proto_rawDesc = []byte{ 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x72, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x6c, - 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0b, 0x61, 0x6c, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2d, 0x0a, - 0x12, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, - 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x61, - 0x6c, 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x22, 0x6a, 0x0a, 0x16, - 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, - 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, - 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, - 0x63, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x72, 0x67, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x6d, 0x61, + 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, + 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x22, 0x6a, 0x0a, 0x16, 0x50, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x63, 0x63, 0x2e, + 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, + 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x42, 0x48, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, + 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x63, 0x2f, 0x61, + 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x73, 0x2f, 0x76, 0x31, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/cc/arduino/cli/commands/v1/core.proto b/rpc/cc/arduino/cli/commands/v1/core.proto index 67aa0b214c7..e44331dada8 100644 --- a/rpc/cc/arduino/cli/commands/v1/core.proto +++ b/rpc/cc/arduino/cli/commands/v1/core.proto @@ -115,12 +115,9 @@ message PlatformSearchRequest { Instance instance = 1; // Keywords for the search. string search_args = 2; - // Whether to show all available versions. `false` causes only the newest - // versions of the cores to be listed in the search results. - bool all_versions = 3; // Whether to show manually installed platforms. `false` causes to skip // manually installed platforms. - bool manually_installed = 4; + bool manually_installed = 3; } message PlatformSearchResponse { From 14e0d5cf4c57e5466904674f371a8b6cb89dd36d Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Wed, 8 Nov 2023 18:21:55 +0100 Subject: [PATCH 17/19] update docs --- docs/UPGRADING.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index d329a804e62..8b8ebcf7790 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -7,24 +7,30 @@ Here you can find a list of migration guides to handle breaking changes between ### The gRPC `cc.arduino.cli.commands.v1.PlatformRelease` has been changed. We've added a new field called `compatible`. This field indicates if the current platform release is installable or not. -It may happen that a platform doesn't have a dependency available for an OS, in such cases, if we try to install the -platform it will fail. The new field can be used to know upfront if a specific release is installable. +It may happen that a platform doesn't have a dependency available for an OS/ARCH, in such cases, if we try to install +the platform it will fail. The new field can be used to know upfront if a specific release is installable. ### The gRPC `cc.arduino.cli.commands.v1.PlatformSummary` has been changed. -We've added a new field called `latest_compatible_version`. This field indicates the latest version that can be -successfully installed for the current OS. The `latest_version` field cannot guarantee such property. +We've modified the behavior of `latest_version`. Now this field indicates the latest version that can be installed in +the current OS/ARCH. ### `core list` now returns only the latest version that can be installed. -Previously, we showed the latest version without checking if all the dependencies were available in the current OS. Now, -the latest version will always point to an installable one even if a newer incompatible one is present. +Previously, we showed the latest version without checking if all the dependencies were available in the current OS/ARCH. +Now, the latest version will always point to an installable one even if a newer incompatible one is present. + +### `core search` now returns the latest installable version of a core. + +We now show in the `version` column the latest installable version. If none are available then we show a `n/a` label. +The corresponding command with `--format json` now returns the same output of +`arduino-cli core search --all --format json`. ### `core upgrade` and `core install` will install the latest compatible version. Previously, we'd have tried the installation/upgrade of a core even if all the required tools weren't available in the -current OS. Now we check this upfront, and allowing the installation of incompatible versions only if a user explicitly -provides it like: `core install arduino:renesas_uno@1.0.2` +current OS/ARCH. Now we check this upfront, and allowing the installation of incompatible versions only if a user +explicitly provides it like: `core install arduino:renesas_uno@1.0.2` ### gRPC service `cc.arduino.cli.settings.v1` has been removed, and all RPC calls have been migrated to `cc.arduino.cli.commands.v1` From b946506ef3c12d31a0bd3668b03d0459e488d8fc Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 9 Nov 2023 17:14:34 +0100 Subject: [PATCH 18/19] fix flaky test --- internal/integrationtest/board/board_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/integrationtest/board/board_test.go b/internal/integrationtest/board/board_test.go index 2faadee644e..e4163c749c6 100644 --- a/internal/integrationtest/board/board_test.go +++ b/internal/integrationtest/board/board_test.go @@ -17,6 +17,7 @@ package board_test import ( "os" + "runtime" "strings" "testing" @@ -602,10 +603,14 @@ func TestBoardListWithFailedBuiltinInstallation(t *testing.T) { _, _, err = cli.Run("board", "list") require.NoError(t, err) + ext := "" + if runtime.GOOS == "windows" { + ext = ".exe" + } // remove files from serial-discovery directory to simulate a failed installation serialDiscovery, err := cli.DataDir().Join("packages", "builtin", "tools", "serial-discovery").ReadDir() require.NoError(t, err) - require.NoError(t, serialDiscovery[0].Join("serial-discovery.exe").Remove()) + require.NoError(t, serialDiscovery[0].Join("serial-discovery"+ext).Remove()) // board list should install serial-discovery again stdout, stderr, err := cli.Run("board", "list") From 2977bc48e62b20aab4f5e790c7da29f3d577fb25 Mon Sep 17 00:00:00 2001 From: Alessio Perugini Date: Thu, 9 Nov 2023 18:34:58 +0100 Subject: [PATCH 19/19] apply CR suggestion --- arduino/cores/cores.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/arduino/cores/cores.go b/arduino/cores/cores.go index e6111345e00..c3e09adac79 100644 --- a/arduino/cores/cores.go +++ b/arduino/cores/cores.go @@ -233,9 +233,6 @@ func (platform *Platform) GetLatestRelease() *PlatformRelease { // GetLatestCompatibleRelease returns the latest compatible release of this platform, or nil if no // compatible releases are available. func (platform *Platform) GetLatestCompatibleRelease() *PlatformRelease { - if len(platform.Releases) == 0 { - return nil - } var maximum *PlatformRelease for _, release := range platform.Releases { if !release.IsCompatible() {