diff --git a/commands/board/list.go b/commands/board/list.go index 7eaf45179cc..a804b9908c2 100644 --- a/commands/board/list.go +++ b/commands/board/list.go @@ -21,6 +21,7 @@ import ( "io/ioutil" "net/http" "regexp" + "sort" "sync" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" @@ -117,11 +118,16 @@ func identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*r // first query installed cores through the Package Manager logrus.Debug("Querying installed cores for board identification...") for _, board := range pm.IdentifyBoard(port.IdentificationPrefs) { + // We need the Platform maintaner for sorting so we set it here + platform := &rpc.Platform{ + Maintainer: board.PlatformRelease.Platform.Package.Maintainer, + } boards = append(boards, &rpc.BoardListItem{ - Name: board.Name(), - Fqbn: board.FQBN(), - Vid: port.IdentificationPrefs.Get("vid"), - Pid: port.IdentificationPrefs.Get("pid"), + Name: board.Name(), + Fqbn: board.FQBN(), + Platform: platform, + Vid: port.IdentificationPrefs.Get("vid"), + Pid: port.IdentificationPrefs.Get("pid"), }) } @@ -142,6 +148,25 @@ func identify(pm *packagemanager.PackageManager, port *commands.BoardPort) ([]*r // boards) boards = items } + + // Sort by FQBN alphabetically + sort.Slice(boards, func(i, j int) bool { + return boards[i].Fqbn < boards[j].Fqbn + }) + + // Put Arduino boards before others in case there are non Arduino boards with identical VID:PID combination + sort.SliceStable(boards, func(i, j int) bool { + if boards[i].Platform.Maintainer == "Arduino" && boards[j].Platform.Maintainer != "Arduino" { + return true + } + return false + }) + + // We need the Board's Platform only for sorting but it shouldn't be present in the output + for _, board := range boards { + board.Platform = nil + } + return boards, nil } diff --git a/commands/board/list_test.go b/commands/board/list_test.go index 140cb84bd2e..2cccecbd606 100644 --- a/commands/board/list_test.go +++ b/commands/board/list_test.go @@ -19,12 +19,16 @@ import ( "fmt" "net/http" "net/http/httptest" + "os" "testing" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/configuration" + "github.com/arduino/go-paths-helper" "github.com/arduino/go-properties-orderedmap" "github.com/stretchr/testify/require" + semver "go.bug.st/relaxed-semver" ) func init() { @@ -109,3 +113,53 @@ func TestBoardDetectionViaAPIWithNonUSBPort(t *testing.T) { require.Equal(t, err, ErrNotFound) require.Empty(t, items) } + +func TestBoardIdentifySorting(t *testing.T) { + dataDir := paths.TempDir().Join("test", "data_dir") + os.Setenv("ARDUINO_DATA_DIR", dataDir.String()) + dataDir.MkdirAll() + defer paths.TempDir().Join("test").RemoveAll() + + // We don't really care about the paths in this case + pm := packagemanager.NewPackageManager(dataDir, dataDir, dataDir, dataDir) + + // Create some boards with identical VID:PID combination + pack := pm.Packages.GetOrCreatePackage("packager") + pack.Maintainer = "NotArduino" + platform := pack.GetOrCreatePlatform("platform") + platformRelease := platform.GetOrCreateRelease(semver.MustParse("0.0.0")) + platformRelease.InstallDir = dataDir + board := platformRelease.GetOrCreateBoard("boardA") + board.Properties.Set("vid", "0x0000") + board.Properties.Set("pid", "0x0000") + board = platformRelease.GetOrCreateBoard("boardB") + board.Properties.Set("vid", "0x0000") + board.Properties.Set("pid", "0x0000") + + // Create some Arduino boards with same VID:PID combination as boards created previously + pack = pm.Packages.GetOrCreatePackage("arduino") + pack.Maintainer = "Arduino" + platform = pack.GetOrCreatePlatform("avr") + platformRelease = platform.GetOrCreateRelease(semver.MustParse("0.0.0")) + platformRelease.InstallDir = dataDir + board = platformRelease.GetOrCreateBoard("nessuno") + board.Properties.Set("vid", "0x0000") + board.Properties.Set("pid", "0x0000") + board = platformRelease.GetOrCreateBoard("assurdo") + board.Properties.Set("vid", "0x0000") + board.Properties.Set("pid", "0x0000") + + idPrefs := properties.NewMap() + idPrefs.Set("vid", "0x0000") + idPrefs.Set("pid", "0x0000") + res, err := identify(pm, &commands.BoardPort{IdentificationPrefs: idPrefs}) + require.NoError(t, err) + require.NotNil(t, res) + require.Len(t, res, 4) + + // Verify expected sorting + require.Equal(t, res[0].Fqbn, "arduino:avr:assurdo") + require.Equal(t, res[1].Fqbn, "arduino:avr:nessuno") + require.Equal(t, res[2].Fqbn, "packager:platform:boardA") + require.Equal(t, res[3].Fqbn, "packager:platform:boardB") +}