Skip to content

Commit 12caaa8

Browse files
author
Luca Bianconi
committed
feat: filter boards by fqbn in connected list
1 parent a63aff4 commit 12caaa8

File tree

19 files changed

+187
-99
lines changed

19 files changed

+187
-99
lines changed

Diff for: commands/board/list.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ func List(req *rpc.BoardListRequest) (r []*rpc.DetectedPort, discoveryStartError
205205
}
206206
defer release()
207207

208+
var fqbnFilter *cores.FQBN
209+
if f := req.GetFqbn(); f != "" {
210+
var err error
211+
fqbnFilter, err = cores.ParseFQBN(f)
212+
if err != nil {
213+
return nil, nil, &arduino.InvalidFQBNError{Cause: err}
214+
}
215+
}
216+
208217
dm := pme.DiscoveryManager()
209218
discoveryStartErrors = dm.Start()
210219
time.Sleep(time.Duration(req.GetTimeout()) * time.Millisecond)
@@ -222,11 +231,23 @@ func List(req *rpc.BoardListRequest) (r []*rpc.DetectedPort, discoveryStartError
222231
Port: port.ToRPC(),
223232
MatchingBoards: boards,
224233
}
225-
retVal = append(retVal, b)
234+
235+
if fqbnFilter == nil || hasMatchingBoard(b, fqbnFilter) {
236+
retVal = append(retVal, b)
237+
}
226238
}
227239
return retVal, discoveryStartErrors, nil
228240
}
229241

242+
func hasMatchingBoard(b *rpc.DetectedPort, requestedFqbn *cores.FQBN) bool {
243+
for _, detectedBoard := range b.MatchingBoards {
244+
if detectedBoard.Fqbn == requestedFqbn.String() {
245+
return true
246+
}
247+
}
248+
return false
249+
}
250+
230251
// Watch returns a channel that receives boards connection and disconnection events.
231252
// It also returns a callback function that must be used to stop and dispose the watch.
232253
func Watch(req *rpc.BoardListWatchRequest) (<-chan *rpc.BoardListWatchResponse, func(), error) {

Diff for: internal/cli/arguments/fqbn.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,27 @@ type Fqbn struct {
3333
boardOptions []string // List of boards specific options separated by commas. Or can be used multiple times for multiple options.
3434
}
3535

36-
// AddToCommand adds the flags used to set fqbn to the specified Command
36+
// AddToCommand adds the flags used to set fqbn and the board options to the specified Command
3737
func (f *Fqbn) AddToCommand(cmd *cobra.Command) {
38+
f.addToCommand(cmd, true)
39+
}
40+
41+
// AddToCommand adds the flags used to set fqbn to the specified Command, board options flag is not provided
42+
func (f *Fqbn) AddToCommandWithoutBoardOptions(cmd *cobra.Command) {
43+
f.addToCommand(cmd, false)
44+
}
45+
46+
func (f *Fqbn) addToCommand(cmd *cobra.Command, enableBoardOptions bool) bool {
3847
cmd.Flags().StringVarP(&f.fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno"))
3948
cmd.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
4049
return GetInstalledBoards(), cobra.ShellCompDirectiveDefault
4150
})
42-
cmd.Flags().StringSliceVar(&f.boardOptions, "board-options", []string{},
43-
tr("List of board options separated by commas. Or can be used multiple times for multiple options."))
51+
52+
if enableBoardOptions {
53+
cmd.Flags().StringSliceVar(&f.boardOptions, "board-options", []string{},
54+
tr("List of board options separated by commas. Or can be used multiple times for multiple options."))
55+
}
56+
return false
4457
}
4558

4659
// String returns the fqbn with the board options if there are any

Diff for: internal/cli/board/list.go

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"os"
2121
"sort"
2222

23+
"github.com/arduino/arduino-cli/arduino"
2324
"github.com/arduino/arduino-cli/arduino/cores"
2425
"github.com/arduino/arduino-cli/commands/board"
2526
"github.com/arduino/arduino-cli/internal/cli/arguments"
@@ -47,6 +48,7 @@ func initListCommand() *cobra.Command {
4748
}
4849

4950
timeoutArg.AddToCommand(listCommand)
51+
fqbn.AddToCommandWithoutBoardOptions(listCommand)
5052
listCommand.Flags().BoolVarP(&watch, "watch", "w", false, tr("Command keeps running and prints list of connected boards whenever there is a change."))
5153

5254
return listCommand
@@ -66,8 +68,12 @@ func runListCommand(cmd *cobra.Command, args []string) {
6668
ports, discvoeryErrors, err := board.List(&rpc.BoardListRequest{
6769
Instance: inst,
6870
Timeout: timeoutArg.Get().Milliseconds(),
71+
Fqbn: fqbn.String(),
6972
})
7073
if err != nil {
74+
if _, isFqbnError := err.(*arduino.InvalidFQBNError); isFqbnError {
75+
feedback.Fatal(tr(err.Error()), feedback.ErrBadArgument)
76+
}
7177
feedback.Warning(tr("Error detecting boards: %v", err))
7278
}
7379
for _, err := range discvoeryErrors {

Diff for: internal/integrationtest/board/board_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,39 @@ func TestBoardList(t *testing.T) {
9191
MustBeEmpty()
9292
}
9393

94+
func TestBoardListWithFqbnFilter(t *testing.T) {
95+
if os.Getenv("CI") != "" {
96+
t.Skip("VMs have no serial ports")
97+
}
98+
99+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
100+
defer env.CleanUp()
101+
102+
_, _, err := cli.Run("core", "update-index")
103+
require.NoError(t, err)
104+
stdout, _, err := cli.Run("board", "list", "-b", "arduino:avr:uno", "--format", "json")
105+
require.NoError(t, err)
106+
// this is a bit of a passpartout test, it actually filters the "bluetooth boards" locally
107+
// but it would succeed even if the filtering wasn't working properly
108+
// TODO: find a way to simulate connected boards or create a unit test which
109+
// mocks or initializes multiple components
110+
requirejson.Parse(t, stdout).
111+
MustBeEmpty()
112+
}
113+
114+
func TestBoardListWithFqbnFilterInvalid(t *testing.T) {
115+
if os.Getenv("CI") != "" {
116+
t.Skip("VMs have no serial ports")
117+
}
118+
119+
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
120+
defer env.CleanUp()
121+
122+
_, stderr, err := cli.Run("board", "list", "-b", "yadayada", "--format", "json")
123+
require.Error(t, err)
124+
requirejson.Query(t, stderr, ".error", `"Invalid FQBN: not an FQBN: yadayada"`)
125+
}
126+
94127
func TestBoardListWithInvalidDiscovery(t *testing.T) {
95128
env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t)
96129
defer env.CleanUp()

0 commit comments

Comments
 (0)