From 12e6f5e524ffdf989b2f46072d25374193dee494 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 2 Dec 2024 19:14:54 +0100 Subject: [PATCH 01/11] Simplified platforms loader using a 'managed' flag --- .../arduino/cores/packagemanager/loader.go | 112 +++++++++--------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index 14e1d6df912..154515fd81a 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -63,6 +63,13 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error { return append(merr, errors.New(i18n.Tr("%s is not a directory", path))) } + // If the hardware directory is inside, or equals, the sketchbook/hardware directory + // it's not a managed package, otherwise it is. + managed := true + if userInstalled, err := path.IsInsideDir(pm.userPackagesDir.Parent()); err == nil && userInstalled { + managed = false + } + // Scan subdirs packagersPaths, err := path.ReadDir() if err != nil { @@ -85,43 +92,39 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error { for _, packagerPath := range packagersPaths { packager := packagerPath.Base() - // Skip tools, they're not packages and don't contain Platforms if packager == "tools" { pm.log.Infof("Excluding directory: %s", packagerPath) continue } + targetPackage := pm.packages.GetOrCreatePackage(packager) // Follow symlinks - err := packagerPath.FollowSymLink() // ex: .arduino15/packages/arduino/ - if err != nil { + // (for example: .arduino15/packages/arduino/ could point to a dev directory) + if err := packagerPath.FollowSymLink(); err != nil { merr = append(merr, fmt.Errorf("%s: %w", i18n.Tr("following symlink %s", path), err)) continue } // There are two possible package directory structures: - // - PACKAGER/ARCHITECTURE-1/boards.txt... (ex: arduino/avr/...) - // PACKAGER/ARCHITECTURE-2/boards.txt... (ex: arduino/sam/...) - // PACKAGER/ARCHITECTURE-3/boards.txt... (ex: arduino/samd/...) - // or - // - PACKAGER/hardware/ARCHITECTURE-1/VERSION/boards.txt... (ex: arduino/hardware/avr/1.6.15/...) - // PACKAGER/hardware/ARCHITECTURE-2/VERSION/boards.txt... (ex: arduino/hardware/sam/1.6.6/...) - // PACKAGER/hardware/ARCHITECTURE-3/VERSION/boards.txt... (ex: arduino/hardware/samd/1.6.12/...) - // PACKAGER/tools/... (ex: arduino/tools/...) - // in the latter case we just move into "hardware" directory and continue - var architectureParentPath *paths.Path - hardwareSubdirPath := packagerPath.Join("hardware") // ex: .arduino15/packages/arduino/hardware - if hardwareSubdirPath.IsDir() { - // we found the "hardware" directory move down into that - architectureParentPath = hardwareSubdirPath // ex: .arduino15/packages/arduino/ + if managed { + // 1. Inside the Boards Manager .arduino15/packages directory: + // PACKAGER/hardware/ARCHITECTURE-1/VERSION/boards.txt... (ex: arduino/hardware/avr/1.6.15/...) + // PACKAGER/hardware/ARCHITECTURE-2/VERSION/boards.txt... (ex: arduino/hardware/sam/1.6.6/...) + // PACKAGER/hardware/ARCHITECTURE-3/VERSION/boards.txt... (ex: arduino/hardware/samd/1.6.12/...) + // PACKAGER/tools/... (ex: arduino/tools/...) + if p := packagerPath.Join("hardware"); p.IsDir() { + merr = append(merr, pm.loadPlatforms(targetPackage, p, managed)...) + } } else { - // we are already at the correct level - architectureParentPath = packagerPath + // 2. Inside the sketchbook/hardware directory: + // PACKAGER/ARCHITECTURE-1/boards.txt... (ex: arduino/avr/...) + // PACKAGER/ARCHITECTURE-2/boards.txt... (ex: arduino/sam/...) + // PACKAGER/ARCHITECTURE-3/boards.txt... (ex: arduino/samd/...) + // ex: .arduino15/packages/arduino/hardware/... + merr = append(merr, pm.loadPlatforms(targetPackage, packagerPath, managed)...) } - targetPackage := pm.packages.GetOrCreatePackage(packager) - merr = append(merr, pm.loadPlatforms(targetPackage, architectureParentPath)...) - // Check if we have tools to load, the directory structure is as follows: // - PACKAGER/tools/TOOL-NAME/TOOL-VERSION/... (ex: arduino/tools/bossac/1.7.0/...) toolsSubdirPath := packagerPath.Join("tools") @@ -141,8 +144,8 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error { // loadPlatforms load plaftorms from the specified directory assuming that they belongs // to the targetPackage object passed as parameter. // A list of gRPC Status error is returned for each Platform failed to load. -func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths.Path) []error { - pm.log.Infof("Loading package %s from: %s", targetPackage.Name, packageDir) +func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths.Path, managed bool) []error { + pm.log.Infof("Loading package %s from: %s (managed=%v)", targetPackage.Name, packageDir, managed) var merr []error @@ -162,7 +165,7 @@ func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths if targetArchitecture == "tools" { continue } - if err := pm.loadPlatform(targetPackage, targetArchitecture, platformPath); err != nil { + if err := pm.loadPlatform(targetPackage, targetArchitecture, platformPath, managed); err != nil { merr = append(merr, err) } } @@ -173,46 +176,18 @@ func (pm *Builder) loadPlatforms(targetPackage *cores.Package, packageDir *paths // loadPlatform loads a single platform and all its installed releases given a platformPath. // platformPath must be a directory. // Returns a gRPC Status error in case of failures. -func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture string, platformPath *paths.Path) error { +func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture string, platformPath *paths.Path, managed bool) error { // This is not a platform if platformPath.IsNotDir() { return errors.New(i18n.Tr("path is not a platform directory: %s", platformPath)) } // There are two possible platform directory structures: - // - ARCHITECTURE/boards.txt - // - ARCHITECTURE/VERSION/boards.txt - // We identify them by checking where is the bords.txt file - possibleBoardTxtPath := platformPath.Join("boards.txt") - if exist, err := possibleBoardTxtPath.ExistCheck(); err != nil { - return fmt.Errorf("%s: %w", i18n.Tr("looking for boards.txt in %s", possibleBoardTxtPath), err) - } else if exist { - // case: ARCHITECTURE/boards.txt + if managed { + // 1. Inside the Boards Manager .arduino15/packages/PACKAGER/hardware/ARCHITECTURE directory: + // - ARCHITECTURE/VERSION/boards.txt - platformTxtPath := platformPath.Join("platform.txt") - platformProperties, err := properties.SafeLoad(platformTxtPath.String()) - if err != nil { - return fmt.Errorf("%s: %w", i18n.Tr("loading platform.txt"), err) - } - - versionString := platformProperties.ExpandPropsInString(platformProperties.Get("version")) - version, err := semver.Parse(versionString) - if err != nil { - return &cmderrors.InvalidVersionError{Cause: fmt.Errorf("%s: %s", platformTxtPath, err)} - } - - platform := targetPackage.GetOrCreatePlatform(architecture) - platform.ManuallyInstalled = true - release := platform.GetOrCreateRelease(version) - if err := pm.loadPlatformRelease(release, platformPath); err != nil { - return fmt.Errorf("%s: %w", i18n.Tr("loading platform release %s", release), err) - } - pm.log.WithField("platform", release).Infof("Loaded platform") - - } else { - // case: ARCHITECTURE/VERSION/boards.txt // let's dive into VERSION directories - versionDirs, err := platformPath.ReadDir() if err != nil { return fmt.Errorf("%s: %w", i18n.Tr("reading directory %s", platformPath), err) @@ -237,6 +212,29 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin } pm.log.WithField("platform", release).Infof("Loaded platform") } + } else { + // 2. Inside the sketchbook/hardware/PACKAGER/ARCHITECTURE directory: + // - ARCHITECTURE/boards.txt + + // Determine platform version from the platform.txt metadata + platformTxtPath := platformPath.Join("platform.txt") + platformProperties, err := properties.SafeLoad(platformTxtPath.String()) + if err != nil { + return fmt.Errorf("%s: %w", i18n.Tr("loading platform.txt"), err) + } + + versionString := platformProperties.ExpandPropsInString(platformProperties.Get("version")) + version, err := semver.Parse(versionString) + if err != nil { + return &cmderrors.InvalidVersionError{Cause: fmt.Errorf("%s: %s", platformTxtPath, err)} + } + + platform := targetPackage.GetOrCreatePlatform(architecture) + release := platform.GetOrCreateRelease(version) + if err := pm.loadPlatformRelease(release, platformPath); err != nil { + return fmt.Errorf("%s: %w", i18n.Tr("loading platform release %s", release), err) + } + pm.log.WithField("platform", release).Infof("Loaded platform") } return nil From 10ad7de92b3b3ac37c333f956104e188fe93e411 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 3 Dec 2024 10:24:35 +0100 Subject: [PATCH 02/11] Added integration test --- internal/integrationtest/core/core_test.go | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index a27b5f6d15a..ec93ee89a02 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -1383,3 +1383,30 @@ func TestCoreInstallWithMissingOrInvalidChecksumAndUnsafeInstallEnabled(t *testi "--additional-urls", "https://raw.githubusercontent.com/keyboardio/ArduinoCore-GD32-Keyboardio/refs/heads/main/package_gd32_index.json", "core", "install", "GD32Community:gd32") require.NoError(t, err) } + +func TestCoreOverrideIfInstalledInSketchbook(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + defer env.CleanUp() + + _, _, err := cli.Run("core", "update-index") + require.NoError(t, err) + + // Install avr@1.8.5 + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.5") + require.NoError(t, err) + + // Copy it in the sketchbook hardware folder (simulate a user installed core) + // avrCore := cli.DataDir().Join("packages", "arduino", "hardware", "avr", "1.8.5") + // avrCoreCopy := cli.SketchbookDir().Join("hardware", "arduino", "avr") + // require.NoError(t, avrCoreCopy.Parent().MkdirAll()) + // require.NoError(t, avrCore.CopyDirTo(avrCoreCopy)) + + // Install avr@1.8.6 + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.6") + require.NoError(t, err) + + // List cores and check that version 1.8.5 is listed + stdout, _, err := cli.Run("core", "list", "--json") + require.NoError(t, err) + requirejson.Query(t, stdout, `.platforms.[] | select(.id=="arduino:avr") | .installed_version`, `"1.8.5"`) +} From 794a000ac0d86701b5286a2a2b6c39c5335aeb68 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 3 Dec 2024 16:00:16 +0100 Subject: [PATCH 03/11] Manually installed platforms should not have version info --- internal/arduino/cores/packagemanager/loader.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index 154515fd81a..c6fbf77774f 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -22,7 +22,6 @@ import ( "strconv" "strings" - "github.com/arduino/arduino-cli/commands/cmderrors" "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/i18n" "github.com/arduino/go-paths-helper" @@ -216,19 +215,7 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin // 2. Inside the sketchbook/hardware/PACKAGER/ARCHITECTURE directory: // - ARCHITECTURE/boards.txt - // Determine platform version from the platform.txt metadata - platformTxtPath := platformPath.Join("platform.txt") - platformProperties, err := properties.SafeLoad(platformTxtPath.String()) - if err != nil { - return fmt.Errorf("%s: %w", i18n.Tr("loading platform.txt"), err) - } - - versionString := platformProperties.ExpandPropsInString(platformProperties.Get("version")) - version, err := semver.Parse(versionString) - if err != nil { - return &cmderrors.InvalidVersionError{Cause: fmt.Errorf("%s: %s", platformTxtPath, err)} - } - + version := semver.MustParse("") platform := targetPackage.GetOrCreatePlatform(architecture) release := platform.GetOrCreateRelease(version) if err := pm.loadPlatformRelease(release, platformPath); err != nil { From a74ddd92f323bd12fe9c263b0a5afa86a67da691 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 3 Dec 2024 16:03:20 +0100 Subject: [PATCH 04/11] Moved code in a more logical grouping --- internal/arduino/cores/packagemanager/loader.go | 8 +++----- internal/arduino/cores/packagemanager/profiles.go | 8 ++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index c6fbf77774f..a6c4d8fbf47 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -228,21 +228,19 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin } func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *paths.Path) error { - platform.InstallDir = path - // If the installed.json file is found load it, this is done to handle the // case in which the platform's index and its url have been deleted locally, // if we don't load it some information about the platform is lost installedJSONPath := path.Join("installed.json") - platform.Timestamps.AddFile(installedJSONPath) if installedJSONPath.Exist() { if _, err := pm.LoadPackageIndexFromFile(installedJSONPath); err != nil { return errors.New(i18n.Tr("loading %[1]s: %[2]s", installedJSONPath, err)) } } - // TODO: why CLONE? - platform.Properties = platform.Properties.Clone() + platform.InstallDir = path + platform.Timestamps.AddFile(installedJSONPath) + platform.Properties = platform.Properties.Clone() // TODO: why CLONE? // Create platform properties platformTxtPath := path.Join("platform.txt") diff --git a/internal/arduino/cores/packagemanager/profiles.go b/internal/arduino/cores/packagemanager/profiles.go index d11682b32c0..035fe9f6e43 100644 --- a/internal/arduino/cores/packagemanager/profiles.go +++ b/internal/arduino/cores/packagemanager/profiles.go @@ -72,10 +72,6 @@ func (pmb *Builder) LoadHardwareForProfile(ctx context.Context, p *sketch.Profil } func (pmb *Builder) loadProfilePlatform(ctx context.Context, platformRef *sketch.ProfilePlatformReference, installMissing bool, downloadCB rpc.DownloadProgressCB, taskCB rpc.TaskProgressCB, settings *configuration.Settings) (*cores.PlatformRelease, error) { - targetPackage := pmb.packages.GetOrCreatePackage(platformRef.Packager) - platform := targetPackage.GetOrCreatePlatform(platformRef.Architecture) - release := platform.GetOrCreateRelease(platformRef.Version) - uid := platformRef.InternalUniqueIdentifier() destDir := settings.ProfilesCacheDir().Join(uid) if !destDir.IsDir() && installMissing { @@ -84,6 +80,10 @@ func (pmb *Builder) loadProfilePlatform(ctx context.Context, platformRef *sketch return nil, err } } + + targetPackage := pmb.packages.GetOrCreatePackage(platformRef.Packager) + platform := targetPackage.GetOrCreatePlatform(platformRef.Architecture) + release := platform.GetOrCreateRelease(platformRef.Version) return release, pmb.loadPlatformRelease(release, destDir) } From 949f83a98a041f2f8f4d563807250b58762ea872 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 3 Dec 2024 16:03:53 +0100 Subject: [PATCH 05/11] Renamed a couple of variables for clarity --- .../arduino/cores/packagemanager/loader.go | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index a6c4d8fbf47..dc83e61bde9 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -227,99 +227,99 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin return nil } -func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *paths.Path) error { +func (pm *Builder) loadPlatformRelease(platformRelease *cores.PlatformRelease, platformPath *paths.Path) error { // If the installed.json file is found load it, this is done to handle the // case in which the platform's index and its url have been deleted locally, // if we don't load it some information about the platform is lost - installedJSONPath := path.Join("installed.json") + installedJSONPath := platformPath.Join("installed.json") if installedJSONPath.Exist() { if _, err := pm.LoadPackageIndexFromFile(installedJSONPath); err != nil { return errors.New(i18n.Tr("loading %[1]s: %[2]s", installedJSONPath, err)) } } - platform.InstallDir = path - platform.Timestamps.AddFile(installedJSONPath) - platform.Properties = platform.Properties.Clone() // TODO: why CLONE? + platformRelease.InstallDir = platformPath + platformRelease.Timestamps.AddFile(installedJSONPath) + platformRelease.Properties = platformRelease.Properties.Clone() // TODO: why CLONE? // Create platform properties - platformTxtPath := path.Join("platform.txt") - platform.Timestamps.AddFile(platformTxtPath) + platformTxtPath := platformPath.Join("platform.txt") + platformRelease.Timestamps.AddFile(platformTxtPath) if p, err := properties.SafeLoadFromPath(platformTxtPath); err == nil { - platform.Properties.Merge(p) + platformRelease.Properties.Merge(p) } else { return errors.New(i18n.Tr("loading %[1]s: %[2]s", platformTxtPath, err)) } - platformTxtLocalPath := path.Join("platform.local.txt") - platform.Timestamps.AddFile(platformTxtLocalPath) + platformTxtLocalPath := platformPath.Join("platform.local.txt") + platformRelease.Timestamps.AddFile(platformTxtLocalPath) if p, err := properties.SafeLoadFromPath(platformTxtLocalPath); err == nil { - platform.Properties.Merge(p) + platformRelease.Properties.Merge(p) } else { return errors.New(i18n.Tr("loading %[1]s: %[2]s", platformTxtLocalPath, err)) } - if platform.Properties.SubTree("pluggable_discovery").Size() > 0 || platform.Properties.SubTree("pluggable_monitor").Size() > 0 { - platform.PluggableDiscoveryAware = true + if platformRelease.Properties.SubTree("pluggable_discovery").Size() > 0 || platformRelease.Properties.SubTree("pluggable_monitor").Size() > 0 { + platformRelease.PluggableDiscoveryAware = true } else { - platform.Properties.Set("pluggable_discovery.required.0", "builtin:serial-discovery") - platform.Properties.Set("pluggable_discovery.required.1", "builtin:mdns-discovery") - platform.Properties.Set("pluggable_monitor.required.serial", "builtin:serial-monitor") + platformRelease.Properties.Set("pluggable_discovery.required.0", "builtin:serial-discovery") + platformRelease.Properties.Set("pluggable_discovery.required.1", "builtin:mdns-discovery") + platformRelease.Properties.Set("pluggable_monitor.required.serial", "builtin:serial-monitor") } - if platform.Name == "" { - if name, ok := platform.Properties.GetOk("name"); ok { - platform.Name = name + if platformRelease.Name == "" { + if name, ok := platformRelease.Properties.GetOk("name"); ok { + platformRelease.Name = name } else { // If the platform.txt file doesn't exist for this platform and it's not in any // package index there is no way of retrieving its name, so we build one using // the available information, that is the packager name and the architecture. - platform.Name = fmt.Sprintf("%s-%s", platform.Platform.Package.Name, platform.Platform.Architecture) + platformRelease.Name = fmt.Sprintf("%s-%s", platformRelease.Platform.Package.Name, platformRelease.Platform.Architecture) } } // Create programmers properties - programmersTxtPath := path.Join("programmers.txt") - platform.Timestamps.AddFile(programmersTxtPath) + programmersTxtPath := platformPath.Join("programmers.txt") + platformRelease.Timestamps.AddFile(programmersTxtPath) if programmersProperties, err := properties.SafeLoadFromPath(programmersTxtPath); err == nil { for programmerID, programmerProps := range programmersProperties.FirstLevelOf() { - if !platform.PluggableDiscoveryAware { + if !platformRelease.PluggableDiscoveryAware { convertUploadToolsToPluggableDiscovery(programmerProps) } - platform.Programmers[programmerID] = pm.loadProgrammer(programmerProps) - platform.Programmers[programmerID].PlatformRelease = platform + platformRelease.Programmers[programmerID] = pm.loadProgrammer(programmerProps) + platformRelease.Programmers[programmerID].PlatformRelease = platformRelease } } else { return err } - if err := pm.loadBoards(platform); err != nil { + if err := pm.loadBoards(platformRelease); err != nil { return errors.New(i18n.Tr("loading boards: %s", err)) } - if !platform.PluggableDiscoveryAware { - convertLegacyPlatformToPluggableDiscovery(platform) + if !platformRelease.PluggableDiscoveryAware { + convertLegacyPlatformToPluggableDiscovery(platformRelease) } // Build pluggable monitor references - platform.Monitors = map[string]*cores.MonitorDependency{} - for protocol, ref := range platform.Properties.SubTree("pluggable_monitor.required").AsMap() { + platformRelease.Monitors = map[string]*cores.MonitorDependency{} + for protocol, ref := range platformRelease.Properties.SubTree("pluggable_monitor.required").AsMap() { split := strings.Split(ref, ":") if len(split) != 2 { return errors.New(i18n.Tr("invalid pluggable monitor reference: %s", ref)) } pm.log.WithField("protocol", protocol).WithField("tool", ref).Info("Adding monitor tool") - platform.Monitors[protocol] = &cores.MonitorDependency{ + platformRelease.Monitors[protocol] = &cores.MonitorDependency{ Packager: split[0], Name: split[1], } } // Support for pluggable monitors in debugging/development environments - platform.MonitorsDevRecipes = map[string]string{} - for protocol, recipe := range platform.Properties.SubTree("pluggable_monitor.pattern").AsMap() { + platformRelease.MonitorsDevRecipes = map[string]string{} + for protocol, recipe := range platformRelease.Properties.SubTree("pluggable_monitor.pattern").AsMap() { pm.log.WithField("protocol", protocol).WithField("recipe", recipe).Info("Adding monitor recipe") - platform.MonitorsDevRecipes[protocol] = recipe + platformRelease.MonitorsDevRecipes[protocol] = recipe } return nil From 3ce0ffd0d6a9c2f3c082ce868c361b6655eb3682 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 10 Dec 2024 16:33:29 +0100 Subject: [PATCH 06/11] draft --- commands/instances.go | 2 +- commands/service_board_listall.go | 2 +- commands/service_board_search.go | 2 +- commands/service_platform_install.go | 1 + commands/service_platform_search.go | 5 +- commands/service_platform_uninstall.go | 2 +- commands/service_upload.go | 2 +- internal/arduino/cores/cores.go | 15 +- internal/arduino/cores/packageindex/index.go | 5 +- .../cores/packagemanager/install_uninstall.go | 2 +- .../arduino/cores/packagemanager/loader.go | 6 +- .../cores/packagemanager/package_manager.go | 30 +- internal/cli/core/list.go | 10 +- internal/cli/feedback/result/rpc.go | 26 +- rpc/cc/arduino/cli/commands/v1/common.pb.go | 271 +++++++++--------- rpc/cc/arduino/cli/commands/v1/common.proto | 8 +- 16 files changed, 226 insertions(+), 163 deletions(-) diff --git a/commands/instances.go b/commands/instances.go index 5b5fe09fcdb..a3a0d3eecf3 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -320,7 +320,7 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor // Load libraries for _, pack := range pme.GetPackages() { for _, platform := range pack.Platforms { - if platformRelease := pme.GetInstalledPlatformRelease(platform); platformRelease != nil { + if platformRelease := pme.GetBestInstalledPlatformRelease(platform); platformRelease != nil { lmb.AddLibrariesDir(librariesmanager.LibrariesDir{ PlatformRelease: platformRelease, Path: platformRelease.GetLibrariesDir(), diff --git a/commands/service_board_listall.go b/commands/service_board_listall.go index 93df1f4e338..4ec82ea2700 100644 --- a/commands/service_board_listall.go +++ b/commands/service_board_listall.go @@ -39,7 +39,7 @@ func (s *arduinoCoreServerImpl) BoardListAll(ctx context.Context, req *rpc.Board list := &rpc.BoardListAllResponse{Boards: []*rpc.BoardListItem{}} for _, targetPackage := range toSortedPackageArray(pme.GetPackages()) { for _, platform := range toSortedPlatformArray(targetPackage.Platforms) { - installedPlatformRelease := pme.GetInstalledPlatformRelease(platform) + installedPlatformRelease := pme.GetBestInstalledPlatformRelease(platform) // We only want to list boards for installed platforms if installedPlatformRelease == nil { continue diff --git a/commands/service_board_search.go b/commands/service_board_search.go index bbe4ca22529..0b3f7049822 100644 --- a/commands/service_board_search.go +++ b/commands/service_board_search.go @@ -40,7 +40,7 @@ func (s *arduinoCoreServerImpl) BoardSearch(ctx context.Context, req *rpc.BoardS for _, targetPackage := range pme.GetPackages() { for _, platform := range targetPackage.Platforms { latestPlatformRelease := platform.GetLatestCompatibleRelease() - installedPlatformRelease := pme.GetInstalledPlatformRelease(platform) + installedPlatformRelease := pme.GetBestInstalledPlatformRelease(platform) if latestPlatformRelease == nil && installedPlatformRelease == nil { continue diff --git a/commands/service_platform_install.go b/commands/service_platform_install.go index 9e268339bc8..873e73d2d0c 100644 --- a/commands/service_platform_install.go +++ b/commands/service_platform_install.go @@ -77,6 +77,7 @@ func (s *arduinoCoreServerImpl) PlatformInstall(req *rpc.PlatformInstallRequest, PlatformArchitecture: req.GetArchitecture(), PlatformVersion: version, } + fmt.Println(ref) platformRelease, tools, err := pme.FindPlatformReleaseDependencies(ref) if err != nil { return &cmderrors.PlatformNotFoundError{Platform: ref.String(), Cause: err} diff --git a/commands/service_platform_search.go b/commands/service_platform_search.go index 4117bf7be18..d5f71ec7190 100644 --- a/commands/service_platform_search.go +++ b/commands/service_platform_search.go @@ -41,7 +41,7 @@ func (s *arduinoCoreServerImpl) PlatformSearch(_ context.Context, req *rpc.Platf res = pme.FindPlatformReleaseProvidingBoardsWithVidPid(vid, pid) } else { searchArgs := utils.SearchTermsFromQueryString(req.GetSearchArgs()) - for _, targetPackage := range pme.GetPackages() { + for _, targetPackage := range pme.AllPackages() { for _, platform := range targetPackage.Platforms { if platform == nil { continue @@ -91,6 +91,9 @@ func (s *arduinoCoreServerImpl) PlatformSearch(_ context.Context, req *rpc.Platf if latestCompatible := platform.GetLatestCompatibleRelease(); latestCompatible != nil { rpcPlatformSummary.LatestVersion = latestCompatible.Version.String() } + if _, has := platform.GetManuallyInstalledRelease(); has { + rpcPlatformSummary.HasManuallyInstalledRelease = true + } for _, platformRelease := range platform.GetAllReleases() { rpcPlatformRelease := platformReleaseToRPC(platformRelease) rpcPlatformSummary.Releases[rpcPlatformRelease.GetVersion()] = rpcPlatformRelease diff --git a/commands/service_platform_uninstall.go b/commands/service_platform_uninstall.go index cf21d91a8ad..3407127d16a 100644 --- a/commands/service_platform_uninstall.go +++ b/commands/service_platform_uninstall.go @@ -77,7 +77,7 @@ func platformUninstall(_ context.Context, req *rpc.PlatformUninstallRequest, tas if platform == nil { return &cmderrors.PlatformNotFoundError{Platform: ref.String()} } - platformRelease := pme.GetInstalledPlatformRelease(platform) + platformRelease := pme.GetBestInstalledPlatformRelease(platform) if platformRelease == nil { return &cmderrors.PlatformNotFoundError{Platform: ref.String()} } diff --git a/commands/service_upload.go b/commands/service_upload.go index 2e5e9272d51..803149eb9c0 100644 --- a/commands/service_upload.go +++ b/commands/service_upload.go @@ -362,7 +362,7 @@ func (s *arduinoCoreServerImpl) runProgramAction(ctx context.Context, pme *packa return nil, &cmderrors.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} } uploadToolID = split[1] - uploadToolPlatform = pme.GetInstalledPlatformRelease(p) + uploadToolPlatform = pme.GetBestInstalledPlatformRelease(p) if uploadToolPlatform == nil { return nil, &cmderrors.PlatformNotFoundError{Platform: split[0] + ":" + boardPlatform.Platform.Architecture} } diff --git a/internal/arduino/cores/cores.go b/internal/arduino/cores/cores.go index 25c73508b76..9ec2201989a 100644 --- a/internal/arduino/cores/cores.go +++ b/internal/arduino/cores/cores.go @@ -40,7 +40,7 @@ type Platform struct { Architecture string // The name of the architecture of this package. Releases map[semver.NormalizedString]*PlatformRelease // The Releases of this platform, labeled by version. Package *Package `json:"-"` - ManuallyInstalled bool // true if the Platform has been installed without the CLI + ManuallyInstalled bool // true if the Platform exists due to a manually installed release Deprecated bool // true if the latest PlatformRelease of this Platform has been deprecated Indexed bool // true if the Platform has been indexed from additional-urls Latest *semver.Version `json:"-"` @@ -238,10 +238,10 @@ func (d *MonitorDependency) String() string { // GetOrCreateRelease returns the specified release corresponding the provided version, // or creates a new one if not found. func (platform *Platform) GetOrCreateRelease(version *semver.Version) *PlatformRelease { - var tag semver.NormalizedString - if version != nil { - tag = version.NormalizedString() + if version == nil { + version = semver.MustParse("") } + tag := version.NormalizedString() if release, ok := platform.Releases[tag]; ok { return release } @@ -257,6 +257,13 @@ func (platform *Platform) GetOrCreateRelease(version *semver.Version) *PlatformR return release } +// GetManuallyInstalledRelease returns (*PlatformRelease, true) if the Platform has +// a manually installed release or (nil, false) otherwise. +func (platform *Platform) GetManuallyInstalledRelease() (*PlatformRelease, bool) { + res, ok := platform.Releases[semver.MustParse("").NormalizedString()] + return res, ok +} + // FindReleaseWithVersion returns the specified release corresponding the provided version, // or nil if not found. func (platform *Platform) FindReleaseWithVersion(version *semver.Version) *PlatformRelease { diff --git a/internal/arduino/cores/packageindex/index.go b/internal/arduino/cores/packageindex/index.go index c2c601c500b..d5f84ec2f7b 100644 --- a/internal/arduino/cores/packageindex/index.go +++ b/internal/arduino/cores/packageindex/index.go @@ -263,7 +263,10 @@ func (inPlatformRelease indexPlatformRelease) extractPlatformIn(outPackage *core outPlatform := outPackage.GetOrCreatePlatform(inPlatformRelease.Architecture) // If the variable `isInstallJSON` is false it means that the index we're reading is coming from the additional-urls. // Therefore, the `outPlatform.Indexed` will be set at `true`. - outPlatform.Indexed = outPlatform.Indexed || !isInstallJSON + if !isInstallJSON { + outPlatform.Indexed = true + outPlatform.ManuallyInstalled = false + } // If the latest platform release is deprecated, then deprecate the whole platform. if outPlatform.Latest == nil || outPlatform.Latest.LessThan(inPlatformRelease.Version) { diff --git a/internal/arduino/cores/packagemanager/install_uninstall.go b/internal/arduino/cores/packagemanager/install_uninstall.go index 977e03d8bb0..ad58e24a933 100644 --- a/internal/arduino/cores/packagemanager/install_uninstall.go +++ b/internal/arduino/cores/packagemanager/install_uninstall.go @@ -441,7 +441,7 @@ func (pme *Explorer) IsToolRequired(toolRelease *cores.ToolRelease) bool { // Search in all installed platforms for _, targetPackage := range pme.packages { for _, platform := range targetPackage.Platforms { - if platformRelease := pme.GetInstalledPlatformRelease(platform); platformRelease != nil { + if platformRelease := pme.GetBestInstalledPlatformRelease(platform); platformRelease != nil { if platformRelease.RequiresToolRelease(toolRelease) { return true } diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index dc83e61bde9..d0e46f08667 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -215,9 +215,11 @@ func (pm *Builder) loadPlatform(targetPackage *cores.Package, architecture strin // 2. Inside the sketchbook/hardware/PACKAGER/ARCHITECTURE directory: // - ARCHITECTURE/boards.txt - version := semver.MustParse("") platform := targetPackage.GetOrCreatePlatform(architecture) - release := platform.GetOrCreateRelease(version) + if !platform.Indexed { + platform.ManuallyInstalled = true + } + release := platform.GetOrCreateRelease(nil) if err := pm.loadPlatformRelease(release, platformPath); err != nil { return fmt.Errorf("%s: %w", i18n.Tr("loading platform release %s", release), err) } diff --git a/internal/arduino/cores/packagemanager/package_manager.go b/internal/arduino/cores/packagemanager/package_manager.go index 3281a3ad9e9..174f5f9f2ad 100644 --- a/internal/arduino/cores/packagemanager/package_manager.go +++ b/internal/arduino/cores/packagemanager/package_manager.go @@ -16,6 +16,7 @@ package packagemanager import ( + "cmp" "errors" "net/url" "os" @@ -229,6 +230,17 @@ func (pme *Explorer) GetPackages() cores.Packages { return pme.packages } +func (pme *Explorer) AllPackages() []*cores.Package { + packages := make([]*cores.Package, 0, len(pme.packages)) + for _, p := range pme.packages { + packages = append(packages, p) + } + slices.SortFunc(packages, func(i, j *cores.Package) int { + return cmp.Compare(i.String(), j.String()) + }) + return packages +} + // GetCustomGlobalProperties returns the user defined custom global // properties for installed platforms. func (pme *Explorer) GetCustomGlobalProperties() *properties.Map { @@ -302,7 +314,7 @@ func (pme *Explorer) ResolveFQBN(fqbn *fqbn.FQBN) ( return targetPackage, nil, nil, nil, nil, errors.New(i18n.Tr("unknown platform %s:%s", targetPackage, fqbn.Architecture)) } - boardPlatformRelease := pme.GetInstalledPlatformRelease(platform) + boardPlatformRelease := pme.GetBestInstalledPlatformRelease(platform) if boardPlatformRelease == nil { return targetPackage, nil, nil, nil, nil, errors.New(i18n.Tr("platform %s is not installed", platform)) @@ -433,7 +445,7 @@ func (pme *Explorer) determineReferencedPlatformRelease(boardBuildProperties *pr return "", nil, "", nil, errors.New(i18n.Tr("missing platform %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.Architecture, fqbn)) } - referredPlatformRelease = pme.GetInstalledPlatformRelease(referredPlatform) + referredPlatformRelease = pme.GetBestInstalledPlatformRelease(referredPlatform) if referredPlatformRelease == nil { return "", nil, "", nil, errors.New(i18n.Tr("missing platform release %[1]s:%[2]s referenced by board %[3]s", referredPackageName, fqbn.Architecture, fqbn)) @@ -592,8 +604,20 @@ func (tr *ToolReleaseActions) Get() (*cores.ToolRelease, error) { return tr.release, nil } -// GetInstalledPlatformRelease returns the PlatformRelease installed (it is chosen) +// GetInstalledPlatformRelease return the PlatformRelease installed through the package manager +// or nil if the PlatformRelease is not installed. Platforms installed manually are ignored. func (pme *Explorer) GetInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease { + for _, release := range platform.GetAllInstalled() { + if release.IsInstalled() && pme.IsManagedPlatformRelease(release) { + return release + } + } + return nil +} + +// GetBestInstalledPlatformRelease returns the PlatformRelease installed (it is chosen between +// the platform installed through the package manager and the one installed manually) +func (pme *Explorer) GetBestInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease { releases := platform.GetAllInstalled() if len(releases) == 0 { return nil diff --git a/internal/cli/core/list.go b/internal/cli/core/list.go index 4fe1661b0e5..5551ee86b0b 100644 --- a/internal/cli/core/list.go +++ b/internal/cli/core/list.go @@ -76,7 +76,7 @@ func GetList(ctx context.Context, srv rpc.ArduinoCoreServiceServer, inst *rpc.In result := []*rpc.PlatformSummary{} for _, platform := range platforms.GetSearchOutput() { - if platform.GetInstalledVersion() == "" && !platform.GetMetadata().GetManuallyInstalled() { + if platform.GetInstalledVersion() == "" && !platform.GetHasManuallyInstalledRelease() { continue } if updatableOnly && platform.GetInstalledVersion() == platform.GetLatestVersion() { @@ -117,10 +117,12 @@ func (ir coreListResult) String() string { t.SetHeader(i18n.Tr("ID"), i18n.Tr("Installed"), i18n.Tr("Latest"), i18n.Tr("Name")) for _, platform := range ir.Platforms { latestVersion := platform.LatestVersion.String() - if latestVersion == "" { - latestVersion = "n/a" + if platform.HasManuallyInstalledRelease { + t.AddRow(platform.Id, i18n.Tr("(in sketchbook)"), "", platform.GetPlatformName()) + } + if !platform.HasManuallyInstalledRelease || platform.InstalledVersion.String() != "" { + t.AddRow(platform.Id, platform.InstalledVersion, latestVersion, platform.GetPlatformName()) } - t.AddRow(platform.Id, platform.InstalledVersion, latestVersion, platform.GetPlatformName()) } return t.Render() diff --git a/internal/cli/feedback/result/rpc.go b/internal/cli/feedback/result/rpc.go index 9798e59584a..2e18ac803e2 100644 --- a/internal/cli/feedback/result/rpc.go +++ b/internal/cli/feedback/result/rpc.go @@ -40,16 +40,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()), + HasManuallyInstalledRelease: in.GetHasManuallyInstalledRelease(), } } @@ -65,8 +66,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"` + HasManuallyInstalledRelease bool `json:"has_manually_installed_release,omitempty"` } // GetLatestRelease returns the latest relase of this platform or nil if none available. diff --git a/rpc/cc/arduino/cli/commands/v1/common.pb.go b/rpc/cc/arduino/cli/commands/v1/common.pb.go index 1d8d47f0af0..65e3fcfe86e 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/common.pb.go @@ -603,13 +603,17 @@ type PlatformSummary struct { // Generic information about a platform. Metadata *PlatformMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // Maps version to the corresponding PlatformRelease. + // Maps version to the corresponding PlatformRelease. The platforms that are + // manually installed by the user have an empty version string. 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 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"` + // If true this Platform has a manually installed release in the sketchbook + // hardware folder. + HasManuallyInstalledRelease bool `protobuf:"varint,5,opt,name=has_manually_installed_release,json=hasManuallyInstalledRelease,proto3" json:"has_manually_installed_release,omitempty"` } func (x *PlatformSummary) Reset() { @@ -672,6 +676,13 @@ func (x *PlatformSummary) GetLatestVersion() string { return "" } +func (x *PlatformSummary) GetHasManuallyInstalledRelease() bool { + if x != nil { + return x.HasManuallyInstalledRelease + } + return false +} + // PlatformMetadata contains generic information about a platform (not // correlated to a specific release). type PlatformMetadata struct { @@ -688,7 +699,7 @@ type PlatformMetadata struct { Website string `protobuf:"bytes,3,opt,name=website,proto3" json:"website,omitempty"` // Email of the maintainer of the platform's package. Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` - // If true this Platform has been installed manually in the user' sketchbook + // If true this Platform has a manually installed release in the sketchbook // hardware folder. ManuallyInstalled bool `protobuf:"varint,5,opt,name=manually_installed,json=manuallyInstalled,proto3" json:"manually_installed,omitempty"` // True if the latest release of this Platform has been deprecated. @@ -1500,7 +1511,7 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 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, 0x6f, 0x72, 0x6d, 0x53, 0x75, 0x6d, + 0x22, 0xb5, 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, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, @@ -1516,133 +1527,137 @@ var file_cc_arduino_cli_commands_v1_common_proto_rawDesc = []byte{ 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, + 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x1e, 0x68, 0x61, 0x73, + 0x5f, 0x6d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x1b, 0x68, 0x61, 0x73, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x49, 0x6e, + 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 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, 0xd8, 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, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 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, 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, 0x22, 0xf0, 0x04, 0x0a, 0x06, 0x53, 0x6b, 0x65, 0x74, 0x63, + 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x61, 0x69, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, + 0x0a, 0x0d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x2c, 0x0a, 0x12, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x6b, 0x65, + 0x74, 0x63, 0x68, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x10, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, + 0x73, 0x12, 0x29, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x64, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, + 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x74, 0x46, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x71, 0x62, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x29, + 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 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, 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, 0xd8, 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, 0x14, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 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, + 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x50, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x18, 0x0a, 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, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, + 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, + 0x6d, 0x65, 0x72, 0x12, 0x64, 0x0a, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, + 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x34, 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, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, + 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 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, 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, 0x22, 0xf0, 0x04, 0x0a, 0x06, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x09, - 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x6d, 0x61, 0x69, 0x6e, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6c, 0x6f, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x2c, - 0x0a, 0x12, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x5f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x74, 0x68, 0x65, - 0x72, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x10, - 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x6f, 0x6f, 0x74, 0x5f, - 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0f, 0x72, 0x6f, 0x6f, 0x74, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x46, 0x69, - 0x6c, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, - 0x71, 0x62, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x46, 0x71, 0x62, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x45, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x18, 0x09, 0x20, 0x03, 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, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x64, - 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0a, - 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, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, - 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, - 0x2d, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x12, 0x64, - 0x0a, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 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, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, - 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x22, 0x66, 0x0a, 0x18, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, - 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x4a, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x2e, 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, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x49, 0x0a, 0x12, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x49, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xde, 0x01, 0x0a, 0x0d, 0x53, 0x6b, 0x65, 0x74, - 0x63, 0x68, 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, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, - 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x55, 0x0a, 0x0b, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 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, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, - 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 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, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x22, 0x49, 0x0a, 0x12, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xde, 0x01, 0x0a, + 0x0d, 0x53, 0x6b, 0x65, 0x74, 0x63, 0x68, 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, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x55, 0x0a, 0x0b, 0x70, 0x6f, + 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x34, 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, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x6f, 0x72, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 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 bc8ed2e7263..5050d7aaf54 100644 --- a/rpc/cc/arduino/cli/commands/v1/common.proto +++ b/rpc/cc/arduino/cli/commands/v1/common.proto @@ -96,13 +96,17 @@ message Platform { message PlatformSummary { // Generic information about a platform. PlatformMetadata metadata = 1; - // Maps version to the corresponding PlatformRelease. + // Maps version to the corresponding PlatformRelease. The platforms that are + // manually installed by the user have an empty version string. 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 that can be installable, or // empty if none available. string latest_version = 4; + // If true this Platform has a manually installed release in the sketchbook + // hardware folder. + bool has_manually_installed_release = 5; } // PlatformMetadata contains generic information about a platform (not @@ -117,7 +121,7 @@ message PlatformMetadata { string website = 3; // Email of the maintainer of the platform's package. string email = 4; - // If true this Platform has been installed manually in the user' sketchbook + // If true this Platform has a manually installed release in the sketchbook // hardware folder. bool manually_installed = 5; // True if the latest release of this Platform has been deprecated. From 39383d4a19c75a0517d48a2516babce905d51a2d Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 16 Jan 2025 12:10:32 +0100 Subject: [PATCH 07/11] Fixed unit test --- commands/service_debug_test.go | 2 +- internal/arduino/cores/packagemanager/loader.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/commands/service_debug_test.go b/commands/service_debug_test.go index f389d1486dc..ad869fbe154 100644 --- a/commands/service_debug_test.go +++ b/commands/service_debug_test.go @@ -37,7 +37,7 @@ func TestGetCommandLine(t *testing.T) { sketchPath := paths.New("testdata", "debug", sketch) require.NoError(t, sketchPath.ToAbs()) - pmb := packagemanager.NewBuilder(nil, nil, nil, nil, nil, "test", downloader.GetDefaultConfig()) + pmb := packagemanager.NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) pmb.LoadHardwareFromDirectory(dataDir) diff --git a/internal/arduino/cores/packagemanager/loader.go b/internal/arduino/cores/packagemanager/loader.go index d0e46f08667..ae02d4901fc 100644 --- a/internal/arduino/cores/packagemanager/loader.go +++ b/internal/arduino/cores/packagemanager/loader.go @@ -65,8 +65,12 @@ func (pm *Builder) LoadHardwareFromDirectory(path *paths.Path) []error { // If the hardware directory is inside, or equals, the sketchbook/hardware directory // it's not a managed package, otherwise it is. managed := true - if userInstalled, err := path.IsInsideDir(pm.userPackagesDir.Parent()); err == nil && userInstalled { - managed = false + if pm.userPackagesDir != nil { + if path.EquivalentTo(pm.userPackagesDir) { + managed = false + } else if userInstalled, err := path.IsInsideDir(pm.userPackagesDir); err == nil && userInstalled { + managed = false + } } // Scan subdirs From dd727cf247d5dd50063ff7d7d3400cc4520b6cd6 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 3 Feb 2025 17:51:20 +0100 Subject: [PATCH 08/11] Fixed Explorer.IsManagedPlatformRelease It has been replaced by a much simpler check on the version field. --- internal/arduino/cores/cores.go | 5 ++++ .../cores/packagemanager/install_uninstall.go | 19 +-------------- .../cores/packagemanager/package_manager.go | 23 ++++++------------- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/internal/arduino/cores/cores.go b/internal/arduino/cores/cores.go index 9ec2201989a..75f7881dbf4 100644 --- a/internal/arduino/cores/cores.go +++ b/internal/arduino/cores/cores.go @@ -117,6 +117,11 @@ func (t *TimestampsStore) Dirty() bool { return false } +// IsManaged returns true if the platform release is managed by the package manager. +func (release *PlatformRelease) IsManaged() bool { + return release.Version.String() != "" +} + // Dirty returns true if one of the files of this PlatformRelease has been changed // (it means that the PlatformRelease should be rebuilt to be used correctly). func (release *PlatformRelease) Dirty() bool { diff --git a/internal/arduino/cores/packagemanager/install_uninstall.go b/internal/arduino/cores/packagemanager/install_uninstall.go index ad58e24a933..b969487cdf6 100644 --- a/internal/arduino/cores/packagemanager/install_uninstall.go +++ b/internal/arduino/cores/packagemanager/install_uninstall.go @@ -257,23 +257,6 @@ func (pme *Explorer) RunPreOrPostScript(installDir *paths.Path, prefix string) ( return []byte{}, []byte{}, nil } -// IsManagedPlatformRelease returns true if the PlatforRelease is managed by the PackageManager -func (pme *Explorer) IsManagedPlatformRelease(platformRelease *cores.PlatformRelease) bool { - if pme.PackagesDir == nil { - return false - } - installDir := platformRelease.InstallDir.Clone() - if installDir.FollowSymLink() != nil { - return false - } - packagesDir := pme.PackagesDir.Clone() - if packagesDir.FollowSymLink() != nil { - return false - } - managed, _ := installDir.IsInsideDir(packagesDir) - return managed -} - // UninstallPlatform remove a PlatformRelease. func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, taskCB rpc.TaskProgressCB, skipPreUninstall bool) error { log := pme.log.WithField("platform", platformRelease) @@ -288,7 +271,7 @@ func (pme *Explorer) UninstallPlatform(platformRelease *cores.PlatformRelease, t } // Safety measure - if !pme.IsManagedPlatformRelease(platformRelease) { + if !platformRelease.IsManaged() { err := errors.New(i18n.Tr("%s is not managed by package manager", platformRelease)) log.WithError(err).Error("Error uninstalling") return &cmderrors.FailedUninstallError{Message: err.Error()} diff --git a/internal/arduino/cores/packagemanager/package_manager.go b/internal/arduino/cores/packagemanager/package_manager.go index 174f5f9f2ad..ec6fd15724c 100644 --- a/internal/arduino/cores/packagemanager/package_manager.go +++ b/internal/arduino/cores/packagemanager/package_manager.go @@ -608,7 +608,7 @@ func (tr *ToolReleaseActions) Get() (*cores.ToolRelease, error) { // or nil if the PlatformRelease is not installed. Platforms installed manually are ignored. func (pme *Explorer) GetInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease { for _, release := range platform.GetAllInstalled() { - if release.IsInstalled() && pme.IsManagedPlatformRelease(release) { + if release.IsInstalled() && release.IsManaged() { return release } } @@ -625,33 +625,24 @@ func (pme *Explorer) GetBestInstalledPlatformRelease(platform *cores.Platform) * debug := func(msg string, pl *cores.PlatformRelease) { pme.log.WithField("version", pl.Version). - WithField("managed", pme.IsManagedPlatformRelease(pl)). + WithField("managed", pl.IsManaged()). Debugf("%s: %s", msg, pl) } best := releases[0] - bestIsManaged := pme.IsManagedPlatformRelease(best) - debug("current best", best) - for _, candidate := range releases[1:] { - candidateIsManaged := pme.IsManagedPlatformRelease(candidate) + debug("current best", best) debug("candidate", candidate) - if !candidateIsManaged && !bestIsManaged { - if candidate.Version.GreaterThan(best.Version) { - best = candidate - } + if candidate.IsManaged() && !best.IsManaged() { continue } - if !candidateIsManaged { + if !candidate.IsManaged() && best.IsManaged() { + best = candidate continue } - if !bestIsManaged { - best = candidate - bestIsManaged = true - } else if candidate.Version.GreaterThan(best.Version) { + if candidate.Version.GreaterThan(best.Version) { best = candidate } - debug("current best", best) } return best } From 3620a0db1cc9959f0a5eca6e5f1ca8aa68f5fc7c Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Tue, 4 Feb 2025 01:24:18 +0100 Subject: [PATCH 09/11] Fix output of 'core uninstall' completion --- internal/cli/arguments/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/cli/arguments/completion.go b/internal/cli/arguments/completion.go index 9b6678fe9ac..446df574ee2 100644 --- a/internal/cli/arguments/completion.go +++ b/internal/cli/arguments/completion.go @@ -82,7 +82,7 @@ func GetUninstallableCores(ctx context.Context, srv rpc.ArduinoCoreServiceServer platforms, _ := srv.PlatformSearch(ctx, &rpc.PlatformSearchRequest{ Instance: inst, - ManuallyInstalled: true, + ManuallyInstalled: false, }) var res []string From 13342eb15b458196546c8a88e58253cced375a4e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 16 Jan 2025 13:05:39 +0100 Subject: [PATCH 10/11] Fixed unit tests --- commands/service_upload_test.go | 8 +- .../packagemanager/package_manager_test.go | 220 +++++++++--------- 2 files changed, 120 insertions(+), 108 deletions(-) diff --git a/commands/service_upload_test.go b/commands/service_upload_test.go index 4a86a0f274b..e0f7ada23c4 100644 --- a/commands/service_upload_test.go +++ b/commands/service_upload_test.go @@ -132,10 +132,12 @@ func TestDetermineBuildPathAndSketchName(t *testing.T) { } func TestUploadPropertiesComposition(t *testing.T) { - pmb := packagemanager.NewBuilder(nil, nil, nil, nil, nil, "test", downloader.GetDefaultConfig()) - errs := pmb.LoadHardwareFromDirectory(paths.New("testdata", "upload", "hardware")) + userdir := paths.New("testdata", "upload") + hwdir := userdir.Join("hardware") + pmb := packagemanager.NewBuilder(nil, nil, hwdir, nil, nil, "test", downloader.GetDefaultConfig()) + errs := pmb.LoadHardwareFromDirectory(hwdir) require.Len(t, errs, 0) - buildPath1 := paths.New("testdata", "upload", "build_path_1") + buildPath1 := userdir.Join("build_path_1") logrus.SetLevel(logrus.TraceLevel) type test struct { importDir *paths.Path diff --git a/internal/arduino/cores/packagemanager/package_manager_test.go b/internal/arduino/cores/packagemanager/package_manager_test.go index 92530af6dc3..292abdd7219 100644 --- a/internal/arduino/cores/packagemanager/package_manager_test.go +++ b/internal/arduino/cores/packagemanager/package_manager_test.go @@ -39,7 +39,7 @@ var dataDir1 = paths.New("testdata", "data_dir_1") var extraHardware = paths.New("testdata", "extra_hardware") func TestFindBoardWithFQBN(t *testing.T) { - pmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) + pmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) pm := pmb.Build() pme, release := pm.NewExplorer() @@ -55,15 +55,118 @@ func TestFindBoardWithFQBN(t *testing.T) { require.Equal(t, board.Name(), "Arduino/Genuino Mega or Mega 2560") } +func TestResolveFQBNWithRefCores(t *testing.T) { + // Pass nil, since these paths are only used for installing + pmb := NewBuilder(nil, nil, extraHardware, nil, nil, "test", downloader.GetDefaultConfig()) + // Hardware from main packages directory + pmb.LoadHardwareFromDirectory(dataDir1.Join("packages")) + // This contains the referenced:avr core + pmb.LoadHardwareFromDirectory(extraHardware) + pm := pmb.Build() + pme, release := pm.NewExplorer() + defer release() + + t.Run("BoardAndBuildPropertiesForReferencedArduinoUno", func(t *testing.T) { + // Test a board referenced from the main AVR arduino platform + fqbn, err := fqbn.Parse("referenced:avr:uno") + require.Nil(t, err) + require.NotNil(t, fqbn) + pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) + require.Nil(t, err) + require.Equal(t, pkg, platformRelease.Platform.Package) + require.NotNil(t, platformRelease) + require.NotNil(t, platformRelease.Platform) + require.Equal(t, platformRelease.Platform.String(), "referenced:avr") + require.NotNil(t, board) + require.Equal(t, board.Name(), "Referenced Uno") + require.NotNil(t, props) + require.NotNil(t, buildPlatformRelease) + require.NotNil(t, buildPlatformRelease.Platform) + require.Equal(t, buildPlatformRelease.Platform.String(), "arduino:avr") + }) + + t.Run("BoardAndBuildPropertiesForReferencedFeatherM0", func(t *testing.T) { + // Test a board referenced from the Adafruit SAMD core (this tests + // deriving where the package and core name are different) + fqbn, err := fqbn.Parse("referenced:samd:feather_m0") + require.Nil(t, err) + require.NotNil(t, fqbn) + pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) + require.Nil(t, err) + require.Equal(t, pkg, platformRelease.Platform.Package) + require.NotNil(t, platformRelease) + require.NotNil(t, platformRelease.Platform) + require.Equal(t, platformRelease.Platform.String(), "referenced:samd") + require.NotNil(t, board) + require.Equal(t, board.Name(), "Referenced Feather M0") + require.NotNil(t, props) + require.NotNil(t, buildPlatformRelease) + require.NotNil(t, buildPlatformRelease.Platform) + require.Equal(t, buildPlatformRelease.Platform.String(), "adafruit:samd") + }) + + t.Run("BoardAndBuildPropertiesForNonExistentPackage", func(t *testing.T) { + // Test a board referenced from a non-existent package + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_package") + require.Nil(t, err) + require.NotNil(t, fqbn) + pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) + require.NotNil(t, err) + require.Equal(t, pkg, platformRelease.Platform.Package) + require.NotNil(t, platformRelease) + require.NotNil(t, platformRelease.Platform) + require.Equal(t, platformRelease.Platform.String(), "referenced:avr") + require.NotNil(t, board) + require.Equal(t, board.Name(), "Referenced dummy with invalid package") + require.Nil(t, props) + require.Nil(t, buildPlatformRelease) + }) + + t.Run("BoardAndBuildPropertiesForNonExistentArchitecture", func(t *testing.T) { + // Test a board referenced from a non-existent platform/architecture + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_platform") + require.Nil(t, err) + require.NotNil(t, fqbn) + pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) + require.NotNil(t, err) + require.Equal(t, pkg, platformRelease.Platform.Package) + require.NotNil(t, platformRelease) + require.NotNil(t, platformRelease.Platform) + require.Equal(t, platformRelease.Platform.String(), "referenced:avr") + require.NotNil(t, board) + require.Equal(t, board.Name(), "Referenced dummy with invalid platform") + require.Nil(t, props) + require.Nil(t, buildPlatformRelease) + }) + + t.Run("BoardAndBuildPropertiesForNonExistentCore", func(t *testing.T) { + // Test a board referenced from a non-existent core + // Note that ResolveFQBN does not actually check this currently + fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_core") + require.Nil(t, err) + require.NotNil(t, fqbn) + pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) + require.Nil(t, err) + require.Equal(t, pkg, platformRelease.Platform.Package) + require.NotNil(t, platformRelease) + require.NotNil(t, platformRelease.Platform) + require.Equal(t, platformRelease.Platform.String(), "referenced:avr") + require.NotNil(t, board) + require.Equal(t, board.Name(), "Referenced dummy with invalid core") + require.NotNil(t, props) + require.NotNil(t, buildPlatformRelease) + require.NotNil(t, buildPlatformRelease.Platform) + require.Equal(t, buildPlatformRelease.Platform.String(), "arduino:avr") + }) +} + func TestResolveFQBN(t *testing.T) { // Pass nil, since these paths are only used for installing - pmb := NewBuilder(nil, nil, nil, nil, nil, "test", downloader.GetDefaultConfig()) + pmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) // Hardware from main packages directory pmb.LoadHardwareFromDirectory(dataDir1.Join("packages")) // This contains the arduino:avr core pmb.LoadHardwareFromDirectory(customHardware) - // This contains the referenced:avr core - pmb.LoadHardwareFromDirectory(extraHardware) pm := pmb.Build() pme, release := pm.NewExplorer() defer release() @@ -86,8 +189,8 @@ func TestResolveFQBN(t *testing.T) { testNormalization("arduino:avr:mega", "arduino:avr:mega") testNormalization("arduino:avr:mega:cpu=atmega2560", "arduino:avr:mega") testNormalization("arduino:avr:mega:cpu=atmega1280", "arduino:avr:mega:cpu=atmega1280") - testNormalization("esp8266:esp8266:generic:baud=57600,wipe=sdk", "esp8266:esp8266:generic:baud=57600,wipe=sdk") - testNormalization("esp8266:esp8266:generic:baud=115200,wipe=sdk", "esp8266:esp8266:generic:wipe=sdk") + testNormalization("esp8266:esp8266:generic:CpuFrequency=80", "esp8266:esp8266:generic") + testNormalization("esp8266:esp8266:generic:CpuFrequency=160", "esp8266:esp8266:generic:CpuFrequency=160") testNormalization("arduino:avr:mega:cpu=nonexistent", "ERROR") testNormalization("arduino:avr:mega:nonexistent=blah", "ERROR") }) @@ -103,7 +206,7 @@ func TestResolveFQBN(t *testing.T) { require.NotNil(t, platformRelease.Platform) require.Equal(t, platformRelease.Platform.String(), "arduino:avr") require.NotNil(t, board) - require.Equal(t, board.Name(), "Arduino Uno") + require.Equal(t, board.Name(), "Arduino/Genuino Uno") require.NotNil(t, props) require.Equal(t, platformRelease, buildPlatformRelease) @@ -124,7 +227,7 @@ func TestResolveFQBN(t *testing.T) { require.NotNil(t, platformRelease.Platform) require.Equal(t, platformRelease.Platform.String(), "arduino:avr") require.NotNil(t, board) - require.Equal(t, board.Name(), "Arduino Mega or Mega 2560") + require.Equal(t, board.Name(), "Arduino/Genuino Mega or Mega 2560") require.NotNil(t, props) require.Equal(t, platformRelease, buildPlatformRelease) }) @@ -166,25 +269,6 @@ func TestResolveFQBN(t *testing.T) { }) - t.Run("BoardAndBuildPropertiesForReferencedArduinoUno", func(t *testing.T) { - // Test a board referenced from the main AVR arduino platform - fqbn, err := fqbn.Parse("referenced:avr:uno") - require.Nil(t, err) - require.NotNil(t, fqbn) - pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) - require.Nil(t, err) - require.Equal(t, pkg, platformRelease.Platform.Package) - require.NotNil(t, platformRelease) - require.NotNil(t, platformRelease.Platform) - require.Equal(t, platformRelease.Platform.String(), "referenced:avr") - require.NotNil(t, board) - require.Equal(t, board.Name(), "Referenced Uno") - require.NotNil(t, props) - require.NotNil(t, buildPlatformRelease) - require.NotNil(t, buildPlatformRelease.Platform) - require.Equal(t, buildPlatformRelease.Platform.String(), "arduino:avr") - }) - t.Run("BoardAndBuildPropertiesForArduinoDue", func(t *testing.T) { fqbn, err := fqbn.Parse("arduino:sam:arduino_due_x") require.Nil(t, err) @@ -232,80 +316,6 @@ func TestResolveFQBN(t *testing.T) { require.Equal(t, "tiny14", props.Get("build.variant")) }) - t.Run("BoardAndBuildPropertiesForReferencedFeatherM0", func(t *testing.T) { - // Test a board referenced from the Adafruit SAMD core (this tests - // deriving where the package and core name are different) - fqbn, err := fqbn.Parse("referenced:samd:feather_m0") - require.Nil(t, err) - require.NotNil(t, fqbn) - pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) - require.Nil(t, err) - require.Equal(t, pkg, platformRelease.Platform.Package) - require.NotNil(t, platformRelease) - require.NotNil(t, platformRelease.Platform) - require.Equal(t, platformRelease.Platform.String(), "referenced:samd") - require.NotNil(t, board) - require.Equal(t, board.Name(), "Referenced Feather M0") - require.NotNil(t, props) - require.NotNil(t, buildPlatformRelease) - require.NotNil(t, buildPlatformRelease.Platform) - require.Equal(t, buildPlatformRelease.Platform.String(), "adafruit:samd") - }) - - t.Run("BoardAndBuildPropertiesForNonExistentPackage", func(t *testing.T) { - // Test a board referenced from a non-existent package - fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_package") - require.Nil(t, err) - require.NotNil(t, fqbn) - pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) - require.NotNil(t, err) - require.Equal(t, pkg, platformRelease.Platform.Package) - require.NotNil(t, platformRelease) - require.NotNil(t, platformRelease.Platform) - require.Equal(t, platformRelease.Platform.String(), "referenced:avr") - require.NotNil(t, board) - require.Equal(t, board.Name(), "Referenced dummy with invalid package") - require.Nil(t, props) - require.Nil(t, buildPlatformRelease) - }) - - t.Run("BoardAndBuildPropertiesForNonExistentArchitecture", func(t *testing.T) { - // Test a board referenced from a non-existent platform/architecture - fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_platform") - require.Nil(t, err) - require.NotNil(t, fqbn) - pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) - require.NotNil(t, err) - require.Equal(t, pkg, platformRelease.Platform.Package) - require.NotNil(t, platformRelease) - require.NotNil(t, platformRelease.Platform) - require.Equal(t, platformRelease.Platform.String(), "referenced:avr") - require.NotNil(t, board) - require.Equal(t, board.Name(), "Referenced dummy with invalid platform") - require.Nil(t, props) - require.Nil(t, buildPlatformRelease) - }) - - t.Run("BoardAndBuildPropertiesForNonExistentCore", func(t *testing.T) { - // Test a board referenced from a non-existent core - // Note that ResolveFQBN does not actually check this currently - fqbn, err := fqbn.Parse("referenced:avr:dummy_invalid_core") - require.Nil(t, err) - require.NotNil(t, fqbn) - pkg, platformRelease, board, props, buildPlatformRelease, err := pme.ResolveFQBN(fqbn) - require.Nil(t, err) - require.Equal(t, pkg, platformRelease.Platform.Package) - require.NotNil(t, platformRelease) - require.NotNil(t, platformRelease.Platform) - require.Equal(t, platformRelease.Platform.String(), "referenced:avr") - require.NotNil(t, board) - require.Equal(t, board.Name(), "Referenced dummy with invalid core") - require.NotNil(t, props) - require.NotNil(t, buildPlatformRelease) - require.NotNil(t, buildPlatformRelease.Platform) - require.Equal(t, buildPlatformRelease.Platform.String(), "arduino:avr") - }) - t.Run("AddBuildBoardPropertyIfMissing", func(t *testing.T) { fqbn, err := fqbn.Parse("my_avr_platform:avr:mymega") require.Nil(t, err) @@ -342,7 +352,7 @@ func TestResolveFQBN(t *testing.T) { } func TestBoardOptionsFunctions(t *testing.T) { - pmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) + pmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) pm := pmb.Build() pme, release := pm.NewExplorer() @@ -615,7 +625,7 @@ func TestIndexMerger(t *testing.T) { } func TestIdentifyBoard(t *testing.T) { - pmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) + pmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) pm := pmb.Build() pme, release := pm.NewExplorer() @@ -642,12 +652,12 @@ func TestIdentifyBoard(t *testing.T) { func TestPackageManagerClear(t *testing.T) { // Create a PackageManager and load the harware - pmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) + pmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) pm := pmb.Build() // Creates another PackageManager but don't load the hardware - emptyPmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) + emptyPmb := NewBuilder(nil, nil, customHardware, nil, nil, "test", downloader.GetDefaultConfig()) emptyPm := emptyPmb.Build() // Verifies they're not equal From dad506358782e1c200e35eae84f1da2dfdce01a5 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 16 Jan 2025 12:41:40 +0100 Subject: [PATCH 11/11] Fixed integration test --- internal/integrationtest/board/board_test.go | 4 +- .../board/hardware_loading_test.go | 6 +- .../integrationtest/compile_4/compile_test.go | 4 +- internal/integrationtest/core/core_test.go | 108 +++++++----------- .../user_hardware/arduino/avr/.gitkeep | 0 5 files changed, 47 insertions(+), 75 deletions(-) delete mode 100644 internal/integrationtest/testdata/user_hardware/arduino/avr/.gitkeep diff --git a/internal/integrationtest/board/board_test.go b/internal/integrationtest/board/board_test.go index db5a7ff200b..0fd486b09a0 100644 --- a/internal/integrationtest/board/board_test.go +++ b/internal/integrationtest/board/board_test.go @@ -237,10 +237,10 @@ func TestBoardListallWithManuallyInstalledPlatform(t *testing.T) { "platform": { "metadata": { "id": "arduino-beta-development:samd", + "manually_installed": true }, "release": { "installed": true, - "version": "1.8.11", "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" }, } @@ -251,10 +251,10 @@ func TestBoardListallWithManuallyInstalledPlatform(t *testing.T) { "platform": { "metadata": { "id": "arduino-beta-development:samd", + "manually_installed": true }, "release": { "installed": true, - "version": "1.8.11", "name": "Arduino SAMD (32-bits ARM Cortex-M0+) Boards" }, } diff --git a/internal/integrationtest/board/hardware_loading_test.go b/internal/integrationtest/board/hardware_loading_test.go index 758ce6a40d2..231abd73a3e 100644 --- a/internal/integrationtest/board/hardware_loading_test.go +++ b/internal/integrationtest/board/hardware_loading_test.go @@ -182,9 +182,9 @@ func TestHardwareLoading(t *testing.T) { "platforms": [ { "id": "my_avr_platform:avr", - "installed_version": "9.9.9", + "installed_version": "", "releases": { - "9.9.9": { + "": { "name": "My AVR Boards", "boards": [ { @@ -207,7 +207,7 @@ func TestHardwareLoading(t *testing.T) { "id": "my_symlinked_avr_platform:avr", "manually_installed": true, "releases": { - "9.9.9": { + "": { } } } diff --git a/internal/integrationtest/compile_4/compile_test.go b/internal/integrationtest/compile_4/compile_test.go index f0916138246..8cfacd9a0fd 100644 --- a/internal/integrationtest/compile_4/compile_test.go +++ b/internal/integrationtest/compile_4/compile_test.go @@ -828,7 +828,7 @@ type buildOptions struct { Verbose bool } -func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, optionsArg ...*buildOptions) (*builderOutput, error) { +func tryBuild(t *testing.T, _ *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string, optionsArg ...*buildOptions) (*builderOutput, error) { var options *buildOptions if len(optionsArg) == 0 { options = &buildOptions{} @@ -870,7 +870,7 @@ func tryBuild(t *testing.T, env *integrationtest.Environment, cli *integrationte return &out, err } -func tryPreprocess(t *testing.T, env *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string) (*paths.Path, []byte, error) { +func tryPreprocess(t *testing.T, _ *integrationtest.Environment, cli *integrationtest.ArduinoCLI, fqbn string) (*paths.Path, []byte, error) { subTestName := strings.Split(t.Name(), "/")[1] sketchPath, err := paths.New("testdata", subTestName).Abs() require.NoError(t, err) diff --git a/internal/integrationtest/core/core_test.go b/internal/integrationtest/core/core_test.go index ec93ee89a02..70dbf6a321a 100644 --- a/internal/integrationtest/core/core_test.go +++ b/internal/integrationtest/core/core_test.go @@ -19,7 +19,6 @@ import ( "encoding/json" "fmt" "os" - "path/filepath" "runtime" "sort" "strconv" @@ -52,12 +51,16 @@ func TestCorrectHandlingOfPlatformVersionProperty(t *testing.T) { "platforms": [ { "id":"DxCore-dev:megaavr", + "manually_installed": true, "installed_version":"1.4.10", "releases": { - "1.4.10": { + "": { "name":"DxCore" } - } + }, + "installed_version": "", + "latest_version": "", + "has_manually_installed_release": true } ] }`) @@ -512,63 +515,9 @@ func TestCoreListAllManuallyInstalledCore(t *testing.T) { requirejson.Contains(t, stdout, `{"platforms":[ { "id": "arduino-beta-development:avr", - "latest_version": "1.8.3", + "latest_version": "", "releases": { - "1.8.3": { - "name": "Arduino AVR Boards" - } - } - } - ]}`) -} - -func TestCoreListShowsLatestVersionWhenMultipleReleasesOfAManuallyInstalledCoreArePresent(t *testing.T) { - env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) - defer env.CleanUp() - - _, _, err := cli.Run("core", "update-index") - require.NoError(t, err) - - // Verifies only cores in board manager are shown - stdout, _, err := cli.Run("core", "list", "--all", "--json") - require.NoError(t, err) - requirejson.Query(t, stdout, `.platforms | length > 0`, `true`) - length, err := strconv.Atoi(requirejson.Parse(t, stdout).Query(".platforms | length").String()) - require.NoError(t, err) - - // Manually installs a core in sketchbooks hardware folder - gitUrl := "https://github.com/arduino/ArduinoCore-avr.git" - repoDir := cli.SketchbookDir().Join("hardware", "arduino-beta-development", "avr") - _, err = git.PlainClone(filepath.Join(repoDir.String(), "1.8.3"), false, &git.CloneOptions{ - URL: gitUrl, - ReferenceName: plumbing.NewTagReferenceName("1.8.3"), - }) - require.NoError(t, err) - - tmp := paths.New(t.TempDir(), "1.8.4") - _, err = git.PlainClone(tmp.String(), false, &git.CloneOptions{ - URL: gitUrl, - ReferenceName: plumbing.NewTagReferenceName("1.8.4"), - }) - require.NoError(t, err) - - err = tmp.Rename(repoDir.Join("1.8.4")) - require.NoError(t, err) - - // When manually installing 2 releases of the same core, the newest one takes precedence - stdout, _, err = cli.Run("core", "list", "--all", "--json") - require.NoError(t, err) - requirejson.Query(t, stdout, `.platforms | length`, fmt.Sprint(length+1)) - requirejson.Contains(t, stdout, `{"platforms":[ - { - "id": "arduino-beta-development:avr", - "latest_version": "1.8.4", - "installed_version": "1.8.4", - "releases": { - "1.8.3": { - "name": "Arduino AVR Boards" - }, - "1.8.3": { + "": { "name": "Arduino AVR Boards" } } @@ -606,12 +555,15 @@ func TestCoreListUpdatableAllFlags(t *testing.T) { requirejson.Contains(t, stdout, `{"platforms":[ { "id": "arduino-beta-development:avr", - "latest_version": "1.8.3", + "manually_installed": true, + "installed_version": "", + "latest_version": "", "releases": { - "1.8.3": { + "": { "name": "Arduino AVR Boards" } - } + }, + "has_manually_installed_release": true } ]}`) } @@ -1009,7 +961,7 @@ func TestCoreWithMissingCustomBoardOptionsIsLoaded(t *testing.T) { { "id": "arduino-beta-dev:platform_with_missing_custom_board_options", "releases": { - "4.2.0": { + "": { "boards": [ { "fqbn": "arduino-beta-dev:platform_with_missing_custom_board_options:nessuno" @@ -1396,10 +1348,10 @@ func TestCoreOverrideIfInstalledInSketchbook(t *testing.T) { require.NoError(t, err) // Copy it in the sketchbook hardware folder (simulate a user installed core) - // avrCore := cli.DataDir().Join("packages", "arduino", "hardware", "avr", "1.8.5") - // avrCoreCopy := cli.SketchbookDir().Join("hardware", "arduino", "avr") - // require.NoError(t, avrCoreCopy.Parent().MkdirAll()) - // require.NoError(t, avrCore.CopyDirTo(avrCoreCopy)) + avrCore := cli.DataDir().Join("packages", "arduino", "hardware", "avr", "1.8.5") + avrCoreCopy := cli.SketchbookDir().Join("hardware", "arduino", "avr") + require.NoError(t, avrCoreCopy.Parent().MkdirAll()) + require.NoError(t, avrCore.CopyDirTo(avrCoreCopy)) // Install avr@1.8.6 _, _, err = cli.Run("core", "install", "arduino:avr@1.8.6") @@ -1408,5 +1360,25 @@ func TestCoreOverrideIfInstalledInSketchbook(t *testing.T) { // List cores and check that version 1.8.5 is listed stdout, _, err := cli.Run("core", "list", "--json") require.NoError(t, err) - requirejson.Query(t, stdout, `.platforms.[] | select(.id=="arduino:avr") | .installed_version`, `"1.8.5"`) + requirejson.Contains(t, stdout, `{ + "platforms": [ + { + "id": "arduino:avr", + "indexed": true, + "releases" : { + "": { + "name": "Arduino AVR Boards", + "installed": true + }, + "1.8.6": { + "name": "Arduino AVR Boards", + "installed": true + } + }, + "installed_version": "1.8.6", + "latest_version": "1.8.6", + "has_manually_installed_release": true + } + ] + }`) } diff --git a/internal/integrationtest/testdata/user_hardware/arduino/avr/.gitkeep b/internal/integrationtest/testdata/user_hardware/arduino/avr/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000