From a71b16cb57bc2f680821e37444ec3c2263aff2ad Mon Sep 17 00:00:00 2001 From: Silvano Cerza Date: Wed, 3 Feb 2021 17:25:10 +0100 Subject: [PATCH] Add --all flag to core list command and gRPC interface Setting that flags return all installed and installable platforms, including installed manually by the user in their Sketchbook hardware folder. --- arduino/cores/cores.go | 11 +- arduino/cores/packagemanager/loader.go | 23 ++-- cli/core/list.go | 3 + commands/core.go | 15 +-- commands/core/list.go | 15 +++ commands/core/search.go | 5 +- legacy/builder/test/hardware_loader_test.go | 46 +++---- rpc/commands/core.pb.go | 95 ++++++++------ rpc/commands/core.proto | 7 ++ test/test_compile.py | 129 ++++++++++++++++++++ test/test_core.py | 77 ++++++++++++ test/testdata/boards.local.txt | 26 ++++ 12 files changed, 371 insertions(+), 81 deletions(-) create mode 100644 test/testdata/boards.local.txt diff --git a/arduino/cores/cores.go b/arduino/cores/cores.go index ea229d98244..67f0c60ba3a 100644 --- a/arduino/cores/cores.go +++ b/arduino/cores/cores.go @@ -28,11 +28,12 @@ import ( // Platform represents a platform package. type Platform struct { - Architecture string // The name of the architecture of this package. - Name string - Category string - Releases map[string]*PlatformRelease // The Releases of this platform, labeled by version. - Package *Package `json:"-"` + Architecture string // The name of the architecture of this package. + Name string + Category string + Releases map[string]*PlatformRelease // The Releases of this platform, labeled by version. + Package *Package `json:"-"` + ManuallyInstalled bool // true if the Platform has been installed without the CLI } // PlatformReleaseHelp represents the help URL for this Platform release diff --git a/arduino/cores/packagemanager/loader.go b/arduino/cores/packagemanager/loader.go index 2b4133e7cf5..b7aa88f30e1 100644 --- a/arduino/cores/packagemanager/loader.go +++ b/arduino/cores/packagemanager/loader.go @@ -166,18 +166,15 @@ func (pm *PackageManager) loadPlatforms(targetPackage *cores.Package, packageDir return fmt.Errorf("looking for boards.txt in %s: %s", possibleBoardTxtPath, err) } else if exist { - - // case: ARCHITECTURE/boards.txt - // this is the general case for unversioned Platform - version := semver.MustParse("") - - // FIXME: this check is duplicated, find a better way to handle this - if exist, err := platformPath.Join("boards.txt").ExistCheck(); err != nil { - return fmt.Errorf("opening boards.txt: %s", err) - } else if !exist { - continue + platformTxtPath := platformPath.Join("platform.txt") + platformProperties, err := properties.SafeLoad(platformTxtPath.String()) + if err != nil { + return fmt.Errorf("loading platform.txt: %w", err) } + platformName := platformProperties.Get("name") + version := semver.MustParse(platformProperties.Get("version")) + // check if package_bundled_index.json exists isIDEBundled := false packageBundledIndexPath := packageDir.Parent().Join("package_index_bundled.json") @@ -210,6 +207,12 @@ func (pm *PackageManager) loadPlatforms(targetPackage *cores.Package, packageDir } platform := targetPackage.GetOrCreatePlatform(architecture) + if platform.Name == "" { + platform.Name = platformName + } + if !isIDEBundled { + platform.ManuallyInstalled = true + } release := platform.GetOrCreateRelease(version) release.IsIDEBundled = isIDEBundled if isIDEBundled { diff --git a/cli/core/list.go b/cli/core/list.go index 9f7c87462bb..ddb2e29a838 100644 --- a/cli/core/list.go +++ b/cli/core/list.go @@ -39,11 +39,13 @@ func initListCommand() *cobra.Command { Run: runListCommand, } listCommand.Flags().BoolVar(&listFlags.updatableOnly, "updatable", false, "List updatable platforms.") + listCommand.Flags().BoolVar(&listFlags.all, "all", false, "If set return all installable and installed cores, including manually installed.") return listCommand } var listFlags struct { updatableOnly bool + all bool } func runListCommand(cmd *cobra.Command, args []string) { @@ -58,6 +60,7 @@ func runListCommand(cmd *cobra.Command, args []string) { platforms, err := core.GetPlatforms(&rpc.PlatformListReq{ Instance: inst, UpdatableOnly: listFlags.updatableOnly, + All: listFlags.all, }) if err != nil { feedback.Errorf("Error listing platforms: %v", err) diff --git a/commands/core.go b/commands/core.go index 1467e6453ae..8003ebd1978 100644 --- a/commands/core.go +++ b/commands/core.go @@ -51,13 +51,14 @@ func PlatformReleaseToRPC(platformRelease *cores.PlatformRelease) *rpc.Platform } result := &rpc.Platform{ - ID: platformRelease.Platform.String(), - Name: platformRelease.Platform.Name, - Maintainer: platformRelease.Platform.Package.Maintainer, - Website: platformRelease.Platform.Package.WebsiteURL, - Email: platformRelease.Platform.Package.Email, - Boards: boards, - Latest: platformRelease.Version.String(), + ID: platformRelease.Platform.String(), + Name: platformRelease.Platform.Name, + Maintainer: platformRelease.Platform.Package.Maintainer, + Website: platformRelease.Platform.Package.WebsiteURL, + Email: platformRelease.Platform.Package.Email, + Boards: boards, + Latest: platformRelease.Version.String(), + ManuallyInstalled: platformRelease.Platform.ManuallyInstalled, } return result diff --git a/commands/core/list.go b/commands/core/list.go index ebfec59e2ac..13f9c5eeaa2 100644 --- a/commands/core/list.go +++ b/commands/core/list.go @@ -39,6 +39,21 @@ func GetPlatforms(req *rpc.PlatformListReq) ([]*rpc.Platform, error) { for _, targetPackage := range packageManager.Packages { for _, platform := range targetPackage.Platforms { platformRelease := packageManager.GetInstalledPlatformRelease(platform) + + // If both All and UpdatableOnly are set All takes precedence + if req.All { + installedVersion := "" + if platformRelease == nil { + platformRelease = platform.GetLatestRelease() + } else { + installedVersion = platformRelease.Version.String() + } + rpcPlatform := commands.PlatformReleaseToRPC(platform.GetLatestRelease()) + rpcPlatform.Installed = installedVersion + res = append(res, rpcPlatform) + continue + } + if platformRelease != nil { if req.UpdatableOnly { if latest := platform.GetLatestRelease(); latest == nil || latest == platformRelease { diff --git a/commands/core/search.go b/commands/core/search.go index ad2a6960101..4d3034eacb3 100644 --- a/commands/core/search.go +++ b/commands/core/search.go @@ -50,7 +50,10 @@ func PlatformSearch(req *rpc.PlatformSearchReq) (*rpc.PlatformSearchResp, error) for _, targetPackage := range pm.Packages { for _, platform := range targetPackage.Platforms { // discard invalid platforms - if platform == nil || platform.Name == "" { + // Users can install platforms manually in the Sketchbook hardware folder, + // the core search command must operate only on platforms installed through + // the PlatformManager, thus we skip the manually installed ones. + if platform == nil || platform.Name == "" || platform.ManuallyInstalled { continue } diff --git a/legacy/builder/test/hardware_loader_test.go b/legacy/builder/test/hardware_loader_test.go index 0c1575f91da..74a8bf80f10 100644 --- a/legacy/builder/test/hardware_loader_test.go +++ b/legacy/builder/test/hardware_loader_test.go @@ -49,24 +49,24 @@ func TestLoadHardware(t *testing.T) { require.NotNil(t, packages["arduino"]) require.Equal(t, 2, len(packages["arduino"].Platforms)) - require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases[""].Boards["uno"].BoardID) - require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases[""].Boards["uno"].Properties.Get("_id")) + require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["uno"].BoardID) + require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["uno"].Properties.Get("_id")) - require.Equal(t, "yun", packages["arduino"].Platforms["avr"].Releases[""].Boards["yun"].BoardID) - require.Equal(t, "true", packages["arduino"].Platforms["avr"].Releases[""].Boards["yun"].Properties.Get("upload.wait_for_upload_port")) + require.Equal(t, "yun", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["yun"].BoardID) + require.Equal(t, "true", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["yun"].Properties.Get("upload.wait_for_upload_port")) - require.Equal(t, "{build.usb_flags}", packages["arduino"].Platforms["avr"].Releases[""].Boards["robotMotor"].Properties.Get("build.extra_flags")) + require.Equal(t, "{build.usb_flags}", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["robotMotor"].Properties.Get("build.extra_flags")) - require.Equal(t, "arduino_due_x", packages["arduino"].Platforms["sam"].Releases[""].Boards["arduino_due_x"].BoardID) + require.Equal(t, "arduino_due_x", packages["arduino"].Platforms["sam"].Releases["1.6.7"].Boards["arduino_due_x"].BoardID) - require.Equal(t, "ATmega123", packages["arduino"].Platforms["avr"].Releases[""].Boards["diecimila"].Properties.Get("menu.cpu.atmega123")) + require.Equal(t, "ATmega123", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["diecimila"].Properties.Get("menu.cpu.atmega123")) avrPlatform := packages["arduino"].Platforms["avr"] - require.Equal(t, "Arduino AVR Boards", avrPlatform.Releases[""].Properties.Get("name")) - require.Equal(t, "-v", avrPlatform.Releases[""].Properties.Get("tools.avrdude.bootloader.params.verbose")) - require.Equal(t, "/my/personal/avrdude", avrPlatform.Releases[""].Properties.Get("tools.avrdude.cmd.path")) + require.Equal(t, "Arduino AVR Boards", avrPlatform.Releases["1.6.10"].Properties.Get("name")) + require.Equal(t, "-v", avrPlatform.Releases["1.6.10"].Properties.Get("tools.avrdude.bootloader.params.verbose")) + require.Equal(t, "/my/personal/avrdude", avrPlatform.Releases["1.6.10"].Properties.Get("tools.avrdude.cmd.path")) - require.Equal(t, "AVRISP mkII", avrPlatform.Releases[""].Programmers["avrispmkii"].Name) + require.Equal(t, "AVRISP mkII", avrPlatform.Releases["1.6.10"].Programmers["avrispmkii"].Name) //require.Equal(t, "{runtime.tools.ctags.path}", packages.Properties.Get("tools.ctags.path"]) //require.Equal(t, "\"{cmd.path}\" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives \"{source_file}\"", packages.Properties.Get("tools.ctags.pattern"]) @@ -103,17 +103,17 @@ func TestLoadHardwareMixingUserHardwareFolder(t *testing.T) { require.NotNil(t, packages["arduino"]) require.Equal(t, 2, len(packages["arduino"].Platforms)) - require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases[""].Boards["uno"].BoardID) - require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases[""].Boards["uno"].Properties.Get("_id")) + require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["uno"].BoardID) + require.Equal(t, "uno", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["uno"].Properties.Get("_id")) - require.Equal(t, "yun", packages["arduino"].Platforms["avr"].Releases[""].Boards["yun"].BoardID) - require.Equal(t, "true", packages["arduino"].Platforms["avr"].Releases[""].Boards["yun"].Properties.Get("upload.wait_for_upload_port")) + require.Equal(t, "yun", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["yun"].BoardID) + require.Equal(t, "true", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["yun"].Properties.Get("upload.wait_for_upload_port")) - require.Equal(t, "{build.usb_flags}", packages["arduino"].Platforms["avr"].Releases[""].Boards["robotMotor"].Properties.Get("build.extra_flags")) + require.Equal(t, "{build.usb_flags}", packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards["robotMotor"].Properties.Get("build.extra_flags")) - require.Equal(t, "arduino_due_x", packages["arduino"].Platforms["sam"].Releases[""].Boards["arduino_due_x"].BoardID) + require.Equal(t, "arduino_due_x", packages["arduino"].Platforms["sam"].Releases["1.6.7"].Boards["arduino_due_x"].BoardID) - avrPlatform := packages["arduino"].Platforms["avr"].Releases[""] + avrPlatform := packages["arduino"].Platforms["avr"].Releases["1.6.10"] require.Equal(t, "Arduino AVR Boards", avrPlatform.Properties.Get("name")) require.Equal(t, "-v", avrPlatform.Properties.Get("tools.avrdude.bootloader.params.verbose")) require.Equal(t, "/my/personal/avrdude", avrPlatform.Properties.Get("tools.avrdude.cmd.path")) @@ -128,7 +128,7 @@ func TestLoadHardwareMixingUserHardwareFolder(t *testing.T) { require.NotNil(t, packages["my_avr_platform"]) myAVRPlatform := packages["my_avr_platform"] //require.Equal(t, "hello world", myAVRPlatform.Properties.Get("example")) - myAVRPlatformAvrArch := myAVRPlatform.Platforms["avr"].Releases[""] + myAVRPlatformAvrArch := myAVRPlatform.Platforms["avr"].Releases["9.9.9"] require.Equal(t, "custom_yun", myAVRPlatformAvrArch.Boards["custom_yun"].BoardID) require.False(t, myAVRPlatformAvrArch.Properties.ContainsKey("preproc.includes.flags")) @@ -219,15 +219,15 @@ func TestLoadLotsOfHardware(t *testing.T) { require.NotNil(t, packages["my_avr_platform"]) require.Equal(t, 3, len(packages["arduino"].Platforms)) - require.Equal(t, 20, len(packages["arduino"].Platforms["avr"].Releases[""].Boards)) - require.Equal(t, 2, len(packages["arduino"].Platforms["sam"].Releases[""].Boards)) + require.Equal(t, 20, len(packages["arduino"].Platforms["avr"].Releases["1.6.10"].Boards)) + require.Equal(t, 2, len(packages["arduino"].Platforms["sam"].Releases["1.6.7"].Boards)) require.Equal(t, 3, len(packages["arduino"].Platforms["samd"].Releases["1.6.5"].Boards)) require.Equal(t, 1, len(packages["my_avr_platform"].Platforms)) - require.Equal(t, 2, len(packages["my_avr_platform"].Platforms["avr"].Releases[""].Boards)) + require.Equal(t, 2, len(packages["my_avr_platform"].Platforms["avr"].Releases["9.9.9"].Boards)) if runtime.GOOS != "windows" { require.Equal(t, 1, len(packages["my_symlinked_avr_platform"].Platforms)) - require.Equal(t, 2, len(packages["my_symlinked_avr_platform"].Platforms["avr"].Releases[""].Boards)) + require.Equal(t, 2, len(packages["my_symlinked_avr_platform"].Platforms["avr"].Releases["9.9.9"].Boards)) } } diff --git a/rpc/commands/core.pb.go b/rpc/commands/core.pb.go index b50430ed524..2c26ab04f2e 100644 --- a/rpc/commands/core.pb.go +++ b/rpc/commands/core.pb.go @@ -674,6 +674,10 @@ type PlatformListReq struct { // Set to true to only list platforms which have a newer version available // than the one currently installed. UpdatableOnly bool `protobuf:"varint,2,opt,name=updatable_only,json=updatableOnly,proto3" json:"updatable_only,omitempty"` + // Set to true to list platforms installed manually in the user' sketchbook + // hardware folder, installed with the PlatformManager through the CLI or IDE + // and that are available to install + All bool `protobuf:"varint,3,opt,name=all,proto3" json:"all,omitempty"` } func (x *PlatformListReq) Reset() { @@ -722,6 +726,13 @@ func (x *PlatformListReq) GetUpdatableOnly() bool { return false } +func (x *PlatformListReq) GetAll() bool { + if x != nil { + return x.All + } + return false +} + type PlatformListResp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -795,6 +806,9 @@ type Platform struct { // not installed, this is an arbitrary list of board names provided by the // platform author for display and may not match boards.txt. Boards []*Board `protobuf:"bytes,8,rep,name=Boards,proto3" json:"Boards,omitempty"` + // If true this Platform has been installed manually in the user' sketchbook + // hardware folder + ManuallyInstalled bool `protobuf:"varint,9,opt,name=ManuallyInstalled,proto3" json:"ManuallyInstalled,omitempty"` } func (x *Platform) Reset() { @@ -885,6 +899,13 @@ func (x *Platform) GetBoards() []*Board { return nil } +func (x *Platform) GetManuallyInstalled() bool { + if x != nil { + return x.ManuallyInstalled + } + return false +} + type Board struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1049,42 +1070,46 @@ var file_commands_core_proto_rawDesc = []byte{ 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, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x0c, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x77, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, 0x3d, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, - 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 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, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x64, - 0x0a, 0x10, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x50, 0x0a, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, - 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 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, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x52, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x61, 0x74, - 0x66, 0x6f, 0x72, 0x6d, 0x22, 0xec, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, - 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, - 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x06, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x4d, - 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x57, - 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x57, 0x65, - 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x36, 0x0a, 0x06, 0x42, - 0x6f, 0x61, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x63, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x89, 0x01, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, 0x3d, 0x0a, 0x08, 0x69, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 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, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, 0x42, 0x6f, 0x61, - 0x72, 0x64, 0x73, 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, 0x42, 0x2d, 0x5a, 0x2b, 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, 0x6f, 0x6d, 0x6d, 0x61, - 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x08, + 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4f, 0x6e, 0x6c, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x6c, + 0x6c, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x50, 0x0a, 0x12, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x65, 0x64, 0x5f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 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, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x50, + 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x9a, 0x02, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, + 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x4d, 0x61, 0x69, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x36, + 0x0a, 0x06, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, + 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, 0x42, 0x6f, 0x61, 0x72, 0x64, 0x52, 0x06, + 0x42, 0x6f, 0x61, 0x72, 0x64, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, + 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x11, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6c, 0x6c, 0x65, 0x64, 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, 0x42, 0x2d, 0x5a, 0x2b, 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, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/rpc/commands/core.proto b/rpc/commands/core.proto index 030e38be92b..92259368d09 100644 --- a/rpc/commands/core.proto +++ b/rpc/commands/core.proto @@ -109,6 +109,10 @@ message PlatformListReq { // Set to true to only list platforms which have a newer version available // than the one currently installed. bool updatable_only = 2; + // Set to true to list platforms installed manually in the user' sketchbook + // hardware folder, installed with the PlatformManager through the CLI or IDE + // and that are available to install + bool all = 3; } message PlatformListResp { @@ -137,6 +141,9 @@ message Platform { // not installed, this is an arbitrary list of board names provided by the // platform author for display and may not match boards.txt. repeated Board Boards = 8; + // If true this Platform has been installed manually in the user' sketchbook + // hardware folder + bool ManuallyInstalled = 9; } message Board { diff --git a/test/test_compile.py b/test/test_compile.py index fa9d2fd42f0..1def2d31606 100644 --- a/test/test_compile.py +++ b/test/test_compile.py @@ -17,6 +17,7 @@ import tempfile import hashlib import shutil +from git import Repo from pathlib import Path import simplejson as json @@ -758,3 +759,131 @@ def test_compile_with_only_compilation_database_flag(run_command, data_dir): # Verifies no binaries are exported assert not build_path.exists() + + +def test_compile_using_platform_local_txt(run_command, data_dir): + assert run_command("update") + + assert run_command("core install arduino:avr@1.8.3") + + sketch_name = "CompileSketchUsingPlatformLocalTxt" + sketch_path = Path(data_dir, sketch_name) + fqbn = "arduino:avr:uno" + + assert run_command(f"sketch new {sketch_path}") + + # Verifies compilation works without issues + assert run_command(f"compile --clean -b {fqbn} {sketch_path}") + + # Overrides default platform compiler with an unexisting one + platform_local_txt = Path(data_dir, "packages", "arduino", "hardware", "avr", "1.8.3", "platform.local.txt") + platform_local_txt.write_text("compiler.c.cmd=my-compiler-that-does-not-exist") + + # Verifies compilation now fails because compiler is not found + res = run_command(f"compile --clean -b {fqbn} {sketch_path}") + assert res.failed + assert "my-compiler-that-does-not-exist" in res.stderr + + +def test_compile_using_boards_local_txt(run_command, data_dir): + assert run_command("update") + + assert run_command("core install arduino:avr@1.8.3") + + sketch_name = "CompileSketchUsingBoardsLocalTxt" + sketch_path = Path(data_dir, sketch_name) + # Use a made up board + fqbn = "arduino:avr:nessuno" + + assert run_command(f"sketch new {sketch_path}") + + # Verifies compilation fails because board doesn't exist + res = run_command(f"compile --clean -b {fqbn} {sketch_path}") + assert res.failed + assert "Error during build: Error resolving FQBN: board arduino:avr@1.8.3:nessuno not found" in res.stderr + + # Use custom boards.local.txt with made arduino:avr:nessuno board + boards_local_txt = Path(data_dir, "packages", "arduino", "hardware", "avr", "1.8.3", "boards.local.txt") + shutil.copyfile(Path(__file__).parent / "testdata" / "boards.local.txt", boards_local_txt) + + assert run_command(f"compile --clean -b {fqbn} {sketch_path}") + + +def test_compile_manually_installed_platform(run_command, data_dir): + assert run_command("update") + + sketch_name = "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" + sketch_path = Path(data_dir, sketch_name) + fqbn = "arduino-beta-development:avr:uno" + assert run_command(f"sketch new {sketch_path}") + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Installs also the same core via CLI so all the necessary tools are installed + assert run_command("core install arduino:avr@1.8.3") + + # Verifies compilation works without issues + assert run_command(f"compile --clean -b {fqbn} {sketch_path}") + + +def test_compile_manually_installed_platform_using_platform_local_txt(run_command, data_dir): + assert run_command("update") + + sketch_name = "CompileSketchManuallyInstalledPlatformUsingPlatformLocalTxt" + sketch_path = Path(data_dir, sketch_name) + fqbn = "arduino-beta-development:avr:uno" + assert run_command(f"sketch new {sketch_path}") + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Installs also the same core via CLI so all the necessary tools are installed + assert run_command("core install arduino:avr@1.8.3") + + # Verifies compilation works without issues + assert run_command(f"compile --clean -b {fqbn} {sketch_path}") + + # Overrides default platform compiler with an unexisting one + platform_local_txt = Path(repo_dir, "platform.local.txt") + platform_local_txt.write_text("compiler.c.cmd=my-compiler-that-does-not-exist") + + # Verifies compilation now fails because compiler is not found + res = run_command(f"compile --clean -b {fqbn} {sketch_path}") + assert res.failed + assert "my-compiler-that-does-not-exist" in res.stderr + + +def test_compile_manually_installed_platform_using_boards_local_txt(run_command, data_dir): + assert run_command("update") + + sketch_name = "CompileSketchManuallyInstalledPlatformUsingBoardsLocalTxt" + sketch_path = Path(data_dir, sketch_name) + fqbn = "arduino-beta-development:avr:nessuno" + assert run_command(f"sketch new {sketch_path}") + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Installs also the same core via CLI so all the necessary tools are installed + assert run_command("core install arduino:avr@1.8.3") + + # Verifies compilation fails because board doesn't exist + res = run_command(f"compile --clean -b {fqbn} {sketch_path}") + assert res.failed + assert ( + "Error during build: Error resolving FQBN: board arduino-beta-development:avr@1.8.3:nessuno not found" + in res.stderr + ) + + # Use custom boards.local.txt with made arduino:avr:nessuno board + boards_local_txt = Path(repo_dir, "boards.local.txt") + shutil.copyfile(Path(__file__).parent / "testdata" / "boards.local.txt", boards_local_txt) + + assert run_command(f"compile --clean -b {fqbn} {sketch_path}") diff --git a/test/test_core.py b/test/test_core.py index e2813ddad62..1f2c0c9326c 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -18,6 +18,7 @@ import simplejson as json import tempfile import hashlib +from git import Repo from pathlib import Path @@ -363,3 +364,79 @@ def test_core_update_with_local_url(run_command): res = run_command(f'core update-index --additional-urls="file://{test_index}"') assert res.ok assert "Updating index: test_index.json downloaded" in res.stdout + + +def test_core_search_manually_installed_cores_not_printed(run_command, data_dir): + assert run_command("core update-index") + + # Verifies only cores in board manager are shown + res = run_command("core search --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 17 + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Verifies manually installed core is not shown + res = run_command("core search --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 17 + mapped = {core["ID"]: core for core in cores} + core_id = "arduino-beta-development:avr" + assert core_id not in mapped + + +def test_core_list_all_manually_installed_core(run_command, data_dir): + assert run_command("core update-index") + + # Verifies only cores in board manager are shown + res = run_command("core list --all --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 17 + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Verifies manually installed core is shown + res = run_command("core list --all --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 18 + mapped = {core["ID"]: core for core in cores} + expected_core_id = "arduino-beta-development:avr" + assert expected_core_id in mapped + assert "Arduino AVR Boards" == mapped[expected_core_id]["Name"] + assert "1.8.3" == mapped[expected_core_id]["Latest"] + + +def test_core_list_updatable_all_flags(run_command, data_dir): + assert run_command("core update-index") + + # Verifies only cores in board manager are shown + res = run_command("core list --all --updatable --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 17 + + # Manually installs a core in sketchbooks hardware folder + git_url = "https://github.com/arduino/ArduinoCore-avr.git" + repo_dir = Path(data_dir, "hardware", "arduino-beta-development", "avr") + assert Repo.clone_from(git_url, repo_dir, multi_options=["-b 1.8.3"]) + + # Verifies using both --updatable and --all flags --all takes precedence + res = run_command("core list --all --updatable --format json") + assert res.ok + cores = json.loads(res.stdout) + assert len(cores) == 18 + mapped = {core["ID"]: core for core in cores} + expected_core_id = "arduino-beta-development:avr" + assert expected_core_id in mapped + assert "Arduino AVR Boards" == mapped[expected_core_id]["Name"] + assert "1.8.3" == mapped[expected_core_id]["Latest"] diff --git a/test/testdata/boards.local.txt b/test/testdata/boards.local.txt new file mode 100644 index 00000000000..ac8dc604b06 --- /dev/null +++ b/test/testdata/boards.local.txt @@ -0,0 +1,26 @@ +nessuno.name=Arduino Nessuno +nessuno.vid.0=0x2341 +nessuno.pid.0=0x0043 +nessuno.vid.1=0x2341 +nessuno.pid.1=0x0001 +nessuno.vid.2=0x2A03 +nessuno.pid.2=0x0043 +nessuno.vid.3=0x2341 +nessuno.pid.3=0x0243 +nessuno.upload.tool=avrdude +nessuno.upload.protocol=arduino +nessuno.upload.maximum_size=32256 +nessuno.upload.maximum_data_size=2048 +nessuno.upload.speed=115200 +nessuno.bootloader.tool=avrdude +nessuno.bootloader.low_fuses=0xFF +nessuno.bootloader.high_fuses=0xDE +nessuno.bootloader.extended_fuses=0xFD +nessuno.bootloader.unlock_bits=0x3F +nessuno.bootloader.lock_bits=0x0F +nessuno.bootloader.file=optiboot/optiboot_atmega328.hex +nessuno.build.mcu=atmega328p +nessuno.build.f_cpu=16000000L +nessuno.build.board=AVR_NESSUNO +nessuno.build.core=arduino +nessuno.build.variant=standard \ No newline at end of file