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_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/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/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/cores.go b/internal/arduino/cores/cores.go index 25c73508b76..75f7881dbf4 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:"-"` @@ -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 { @@ -238,10 +243,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 +262,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..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()} @@ -441,7 +424,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 14e1d6df912..ae02d4901fc 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" @@ -63,6 +62,17 @@ 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 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 packagersPaths, err := path.ReadDir() if err != nil { @@ -85,43 +95,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 +147,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 +168,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 +179,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 - - 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)} - } + if managed { + // 1. Inside the Boards Manager .arduino15/packages/PACKAGER/hardware/ARCHITECTURE directory: + // - ARCHITECTURE/VERSION/boards.txt - 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,106 +215,117 @@ 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 + + platform := targetPackage.GetOrCreatePlatform(architecture) + 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) + } + pm.log.WithField("platform", release).Infof("Loaded platform") } return nil } -func (pm *Builder) loadPlatformRelease(platform *cores.PlatformRelease, path *paths.Path) error { - platform.InstallDir = path - +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") - platform.Timestamps.AddFile(installedJSONPath) + 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)) } } - // TODO: why CLONE? - platform.Properties = platform.Properties.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 diff --git a/internal/arduino/cores/packagemanager/package_manager.go b/internal/arduino/cores/packagemanager/package_manager.go index 3281a3ad9e9..ec6fd15724c 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() && release.IsManaged() { + 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 @@ -601,33 +625,24 @@ func (pme *Explorer) GetInstalledPlatformRelease(platform *cores.Platform) *core 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 } 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 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) } 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 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/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 a27b5f6d15a..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" @@ -1383,3 +1335,50 @@ 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.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 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. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy