diff --git a/internal/arduino/cores/packageindex/index.go b/internal/arduino/cores/packageindex/index.go index 18e70ce524b..fcc892497b3 100644 --- a/internal/arduino/cores/packageindex/index.go +++ b/internal/arduino/cores/packageindex/index.go @@ -19,6 +19,7 @@ import ( "encoding/json" "errors" "fmt" + "slices" "github.com/arduino/arduino-cli/internal/arduino/cores" "github.com/arduino/arduino-cli/internal/arduino/resources" @@ -348,15 +349,18 @@ func (inToolRelease indexToolRelease) extractToolIn(outPackage *cores.Package) { outTool := outPackage.GetOrCreateTool(inToolRelease.Name) outToolRelease := outTool.GetOrCreateRelease(inToolRelease.Version) - outToolRelease.Flavors = inToolRelease.extractFlavours() + outToolRelease.Flavors = inToolRelease.extractAndMergeFlavours(outToolRelease.Flavors) } -// extractFlavours extracts a map[OS]Flavor object from an indexToolRelease entry. -func (inToolRelease indexToolRelease) extractFlavours() []*cores.Flavor { - ret := make([]*cores.Flavor, len(inToolRelease.Systems)) - for i, flavour := range inToolRelease.Systems { +// extractAndMergeFlavours extracts flavors objects from an indexToolRelease +// and adds them to the given flavors array if missing. It returns the updated array. +func (inToolRelease indexToolRelease) extractAndMergeFlavours(in []*cores.Flavor) []*cores.Flavor { + for _, flavour := range inToolRelease.Systems { + if slices.ContainsFunc(in, func(f *cores.Flavor) bool { return f.OS == flavour.OS }) { + continue + } size, _ := flavour.Size.Int64() - ret[i] = &cores.Flavor{ + in = append(in, &cores.Flavor{ OS: flavour.OS, Resource: &resources.DownloadResource{ ArchiveFileName: flavour.ArchiveFileName, @@ -365,9 +369,9 @@ func (inToolRelease indexToolRelease) extractFlavours() []*cores.Flavor { URL: flavour.URL, CachePath: "packages", }, - } + }) } - return ret + return in } // LoadIndex reads a package_index.json from a file and returns the corresponding Index structure. diff --git a/internal/arduino/cores/packagemanager/package_manager_test.go b/internal/arduino/cores/packagemanager/package_manager_test.go index 595d08d0c21..4f8598a515a 100644 --- a/internal/arduino/cores/packagemanager/package_manager_test.go +++ b/internal/arduino/cores/packagemanager/package_manager_test.go @@ -567,6 +567,52 @@ func TestFindToolsRequiredForBoard(t *testing.T) { require.Equal(t, bossac18.InstallDir.String(), uploadProperties.Get("runtime.tools.bossac.path")) } +func TestIndexMerger(t *testing.T) { + t.Setenv("ARDUINO_DATA_DIR", dataDir1.String()) + pmb := NewBuilder( + dataDir1, + dataDir1.Join("packages"), + nil, + dataDir1.Join("staging"), + dataDir1, + "test", + downloader.GetDefaultConfig(), + ) + + loadIndex := func(addr string) { + res, err := url.Parse(addr) + require.NoError(t, err) + require.NoError(t, pmb.LoadPackageIndex(res)) + } + loadIndex("https://test.com/package_with_regular_dfu_util_index.json") // this is not downloaded, it just picks the "local cached" file package_test_index.json + loadIndex("https://test.com/package_with_empty_dfu_util_index.json") // this is not downloaded, it just picks the "local cached" file package_test_index.json + + // We ignore the errors returned since they might not be necessarily blocking + // but just warnings for the user, like in the case a board is not loaded + // because of malformed menus + pmb.LoadHardware() + pm := pmb.Build() + pme, release := pm.NewExplorer() + defer release() + + dfu_util := pme.GetTool("arduino:dfu-util") + require.NotNil(t, dfu_util) + dfu_release := dfu_util.GetOrCreateRelease(semver.ParseRelaxed("0.11.0-arduino5")) + require.NotNil(t, dfu_release) + require.Len(t, dfu_release.Flavors, 6) + + test_tool := pme.GetTool("arduino:test-tool") + require.NotNil(t, test_tool) + test_tool_release := test_tool.GetOrCreateRelease(semver.ParseRelaxed("1.0.0")) + require.NotNil(t, test_tool_release) + // Check that the new entry has been added + require.Len(t, test_tool_release.Flavors, 2) + require.Equal(t, test_tool_release.Flavors[1].OS, "arm-linux-gnueabihf") + require.Equal(t, test_tool_release.Flavors[1].Resource.URL, "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_arm.tar.gz") + // Check that the invalid entry did not replace existing one + require.NotEqual(t, test_tool_release.Flavors[0].Resource.URL, "INVALID") +} + func TestIdentifyBoard(t *testing.T) { pmb := NewBuilder(customHardware, customHardware, nil, customHardware, customHardware, "test", downloader.GetDefaultConfig()) pmb.LoadHardwareFromDirectory(customHardware) diff --git a/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_empty_dfu_util_index.json b/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_empty_dfu_util_index.json new file mode 100644 index 00000000000..36a120a3ccd --- /dev/null +++ b/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_empty_dfu_util_index.json @@ -0,0 +1,41 @@ +{ + "packages": [ + { + "name": "arduino", + "maintainer": "Arduino", + "websiteURL": "http://www.arduino.cc/", + "email": "packages@arduino.cc", + "help": { + "online": "http://www.arduino.cc/en/Reference/HomePage" + }, + "platforms": [], + "tools": [ + { + "name": "test-tool", + "version": "1.0.0", + "systems": [ + { + "host": "i386-apple-darwin11", + "url": "INVALID", + "archiveFileName": "INVALID", + "size": "100", + "checksum": "SHA-256:9e576c6e44f54b1e921a43ea77bcc08ec99e0e4e0905f4b9acf9ab2c979f0a22" + }, + { + "host": "arm-linux-gnueabihf", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_arm.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-linux_arm.tar.gz", + "size": "2512819", + "checksum": "SHA-256:acd4bd283fd408515279a44dd830499ad37b0767e8f2fde5c27e878ded909dc3" + } + ] + }, + { + "name": "dfu-util", + "version": "0.11.0-arduino5", + "systems": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_regular_dfu_util_index.json b/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_regular_dfu_util_index.json new file mode 100644 index 00000000000..e0f56808434 --- /dev/null +++ b/internal/arduino/cores/packagemanager/testdata/data_dir_1/package_with_regular_dfu_util_index.json @@ -0,0 +1,77 @@ +{ + "packages": [ + { + "name": "arduino", + "maintainer": "Arduino", + "websiteURL": "http://www.arduino.cc/", + "email": "packages@arduino.cc", + "help": { + "online": "http://www.arduino.cc/en/Reference/HomePage" + }, + "platforms": [], + "tools": [ + { + "name": "test-tool", + "version": "1.0.0", + "systems": [ + { + "host": "i386-apple-darwin11", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-darwin_amd64.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-darwin_amd64.tar.gz", + "size": "72429", + "checksum": "SHA-256:9e576c6e44f54b1e921a43ea77bcc08ec99e0e4e0905f4b9acf9ab2c979f0a22" + } + ] + }, + { + "name": "dfu-util", + "version": "0.11.0-arduino5", + "systems": [ + { + "host": "i386-apple-darwin11", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-darwin_amd64.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-darwin_amd64.tar.gz", + "size": "72429", + "checksum": "SHA-256:9e576c6e44f54b1e921a43ea77bcc08ec99e0e4e0905f4b9acf9ab2c979f0a22" + }, + { + "host": "arm-linux-gnueabihf", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_arm.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-linux_arm.tar.gz", + "size": "2512819", + "checksum": "SHA-256:acd4bd283fd408515279a44dd830499ad37b0767e8f2fde5c27e878ded909dc3" + }, + { + "host": "aarch64-linux-gnu", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_arm64.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-linux_arm64.tar.gz", + "size": "2607592", + "checksum": "SHA-256:b3f46a65da0c2fed2449dc5a3351c3c74953a868aa7f8d99ba2bb8c418344fe9" + }, + { + "host": "x86_64-linux-gnu", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_amd64.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-linux_amd64.tar.gz", + "size": "2283425", + "checksum": "SHA-256:96c64c278561af806b585c123c85748926ad02b1aedc07e5578ca9bee2be0d2a" + }, + { + "host": "i686-linux-gnu", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-linux_386.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-linux_386.tar.gz", + "size": "2524406", + "checksum": "SHA-256:9a707692261e5710ed79a6d8a4031ffd0bfe1e585216569934346e9b2d68d0c2" + }, + { + "host": "i686-mingw32", + "url": "http://downloads.arduino.cc/tools/dfu-util-0.11-arduino5-windows_386.tar.gz", + "archiveFileName": "dfu-util-0.11-arduino5-windows_386.tar.gz", + "size": "571340", + "checksum": "SHA-256:6451e16bf77600fe2436c8708ab4b75077c49997cf8bedf03221d9d6726bb641" + } + ] + } + ] + } + ] +} \ No newline at end of file