From a15595c4677c2db6fbdae3e499de5cb020997ab4 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 17:33:48 +0200 Subject: [PATCH 01/12] Changes in errors.MultipleBoardsDetectedError and errors.NoBoardsDetectedError - The message formatting has been fixed - The errors now accepts a *rpc.Port instead of a *discovery.Port - The new error NoBoardsDetectedError has been added --- arduino/errors.go | 24 +++++++++++++++++++++--- commands/upload/upload.go | 2 +- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/arduino/errors.go b/arduino/errors.go index b1de65205dd..35085a9423a 100644 --- a/arduino/errors.go +++ b/arduino/errors.go @@ -19,7 +19,6 @@ import ( "fmt" "strings" - "github.com/arduino/arduino-cli/arduino/discovery" "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "google.golang.org/grpc/codes" @@ -125,16 +124,35 @@ func (e *InvalidVersionError) Unwrap() error { return e.Cause } +// NoBoardsDetectedError is returned when detecting the FQBN of a board +// does not produce any result. +type NoBoardsDetectedError struct { + Port *rpc.Port +} + +func (e *NoBoardsDetectedError) Error() string { + return tr( + "Please specify an FQBN. The board on port %[1]s with protocol %[2]s can't be identified", + e.Port.Address, + e.Port.Protocol, + ) +} + +// ToRPCStatus converts the error into a *status.Status +func (e *NoBoardsDetectedError) ToRPCStatus() *status.Status { + return status.New(codes.InvalidArgument, e.Error()) +} + // MultipleBoardsDetectedError is returned when trying to detect // the FQBN of a board connected to a port fails because that // are multiple possible boards detected. type MultipleBoardsDetectedError struct { - Port *discovery.Port + Port *rpc.Port } func (e *MultipleBoardsDetectedError) Error() string { return tr( - "Please specify an FQBN. Multiple possible ports detected on port %s with protocol %s", + "Please specify an FQBN. Multiple possible boards detected on port %[1]s with protocol %[2]s", e.Port.Address, e.Port.Protocol, ) diff --git a/commands/upload/upload.go b/commands/upload/upload.go index 886621d0bc7..89c92fb3f58 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -144,7 +144,7 @@ func DetectConnectedBoard(pm *packagemanager.PackageManager, address, protocol s } else if l >= 2 { // There are multiple boards detected on this port, // we have no way of knowing which one is the one. - return "", &arduino.MultipleBoardsDetectedError{Port: p} + return "", &arduino.MultipleBoardsDetectedError{Port: p.ToRPC()} } else { // We found a matching port but there's either // no board connected or we can't recognize it. From 20a6f2007b13d6b2e06af184ab4e5ed9903c54ee Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 17:48:06 +0200 Subject: [PATCH 02/12] Renamed some variable in compile/compile.go to improve readability fqbn -> fqbnArg port -> portArgs detectedFqbn -> fqbn discoveryPort -> port --- cli/compile/compile.go | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/cli/compile/compile.go b/cli/compile/compile.go index 867f451482b..e35363e89ae 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -47,7 +47,7 @@ import ( ) var ( - fqbn arguments.Fqbn // Fully Qualified Board Name, e.g.: arduino:avr:uno. + fqbnArg arguments.Fqbn // Fully Qualified Board Name, e.g.: arduino:avr:uno. showProperties bool // Show all build preferences used instead of compiling. preprocess bool // Print preprocessed code to stdout. buildCachePath string // Builds of 'core.a' are saved into this path to be cached and reused. @@ -61,7 +61,7 @@ var ( quiet bool // Suppresses almost every output. vidPid string // VID/PID specific build properties. uploadAfterCompile bool // Upload the binary after the compilation. - port arguments.Port // Upload port, e.g.: COM10 or /dev/ttyACM0. + portArgs arguments.Port // Upload port, e.g.: COM10 or /dev/ttyACM0. verify bool // Upload, verify uploaded binary after the upload. exportDir string // The compiled binary is written to this file optimizeForDebug bool // Optimize compile output for debug, not for release @@ -92,7 +92,7 @@ func NewCommand() *cobra.Command { Run: runCompileCommand, } - fqbn.AddToCommand(compileCommand) + fqbnArg.AddToCommand(compileCommand) compileCommand.Flags().BoolVar(&showProperties, "show-properties", false, tr("Show all build properties used instead of compiling.")) compileCommand.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling.")) compileCommand.Flags().StringVar(&buildCachePath, "build-cache-path", "", tr("Builds of 'core.a' are saved into this path to be cached and reused.")) @@ -114,7 +114,7 @@ func NewCommand() *cobra.Command { compileCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode.")) compileCommand.Flags().BoolVar(&quiet, "quiet", false, tr("Optional, suppresses almost every output.")) compileCommand.Flags().BoolVarP(&uploadAfterCompile, "upload", "u", false, tr("Upload the binary after the compilation.")) - port.AddToCommand(compileCommand) + portArgs.AddToCommand(compileCommand) compileCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload.")) compileCommand.Flags().StringVar(&vidPid, "vid-pid", "", tr("When specified, VID/PID specific build properties are used, if board supports them.")) compileCommand.Flags().StringSliceVar(&library, "library", []string{}, @@ -172,19 +172,19 @@ func runCompileCommand(cmd *cobra.Command, args []string) { overrides = o.Overrides } - detectedFqbn := fqbn.String() + fqbn := fqbnArg.String() var sk *sketch.Sketch - var discoveryPort *discovery.Port + var port *discovery.Port // If the user didn't provide an FQBN it might either mean // that she forgot or that is trying to compile and upload // using board autodetection. - if detectedFqbn == "" && uploadAfterCompile { + if fqbn == "" && uploadAfterCompile { sk = arguments.NewSketch(sketchPath) - discoveryPort = port.GetDiscoveryPort(inst, sk) - rpcPort := discoveryPort.ToRPC() + port = portArgs.GetDiscoveryPort(inst, sk) + rpcPort := port.ToRPC() var err error pm := commands.GetPackageManager(inst.Id) - detectedFqbn, err = upload.DetectConnectedBoard(pm, rpcPort.Address, rpcPort.Protocol) + fqbn, err = upload.DetectConnectedBoard(pm, rpcPort.Address, rpcPort.Protocol) if err != nil { feedback.Errorf(tr("Error during FQBN detection: %v", err)) os.Exit(errorcodes.ErrGeneric) @@ -193,7 +193,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) { compileRequest := &rpc.CompileRequest{ Instance: inst, - Fqbn: detectedFqbn, + Fqbn: fqbn, SketchPath: sketchPath.String(), ShowProperties: showProperties, Preprocess: preprocess, @@ -230,15 +230,15 @@ func runCompileCommand(cmd *cobra.Command, args []string) { if sk == nil { sk = arguments.NewSketch(sketchPath) } - if discoveryPort == nil { - discoveryPort = port.GetDiscoveryPort(inst, sk) + if port == nil { + port = portArgs.GetDiscoveryPort(inst, sk) } userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: inst, - Fqbn: fqbn.String(), - Address: discoveryPort.Address, - Protocol: discoveryPort.Protocol, + Fqbn: fqbnArg.String(), + Address: port.Address, + Protocol: port.Protocol, }) if err != nil { feedback.Errorf(tr("Error during Upload: %v"), err) @@ -247,15 +247,15 @@ func runCompileCommand(cmd *cobra.Command, args []string) { fields := map[string]string{} if len(userFieldRes.UserFields) > 0 { - feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", discoveryPort.Protocol)) + feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol)) fields = arguments.AskForUserFields(userFieldRes.UserFields) } uploadRequest := &rpc.UploadRequest{ Instance: inst, - Fqbn: detectedFqbn, + Fqbn: fqbn, SketchPath: sketchPath.String(), - Port: discoveryPort.ToRPC(), + Port: port.ToRPC(), Verbose: verbose, Verify: verify, ImportDir: buildPath, From 441c63e28a4c7e8afad5916235b0534f02da4de5 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 17:51:21 +0200 Subject: [PATCH 03/12] Renamed some variable in debug/debug.go to improve readability fqbn -> fqbnArg port -> portArgs discoveryPort -> port --- cli/debug/debug.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/debug/debug.go b/cli/debug/debug.go index 465fa0674ce..ed47e5cee5e 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -36,8 +36,8 @@ import ( ) var ( - fqbn arguments.Fqbn - port arguments.Port + fqbnArg arguments.Fqbn + portArgs arguments.Port interpreter string importDir string printInfo bool @@ -56,8 +56,8 @@ func NewCommand() *cobra.Command { Run: runDebugCommand, } - fqbn.AddToCommand(debugCommand) - port.AddToCommand(debugCommand) + fqbnArg.AddToCommand(debugCommand) + portArgs.AddToCommand(debugCommand) programmer.AddToCommand(debugCommand) debugCommand.Flags().StringVar(&interpreter, "interpreter", "console", tr("Debug interpreter e.g.: %s", "console, mi, mi1, mi2, mi3")) debugCommand.Flags().StringVarP(&importDir, "input-dir", "", "", tr("Directory containing binaries for debug.")) @@ -77,13 +77,13 @@ func runDebugCommand(command *cobra.Command, args []string) { sketchPath := arguments.InitSketchPath(path) sk := arguments.NewSketch(sketchPath) - discoveryPort := port.GetDiscoveryPort(instance, sk) + port := portArgs.GetDiscoveryPort(instance, sk) debugConfigRequested := &dbg.DebugConfigRequest{ Instance: instance, - Fqbn: fqbn.String(), + Fqbn: fqbnArg.String(), SketchPath: sketchPath.String(), - Port: discoveryPort.ToRPC(), + Port: port.ToRPC(), Interpreter: interpreter, ImportDir: importDir, Programmer: programmer.String(), From 0443d3226d43930c671b5e742ba0fb46911bcb19 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 17:56:42 +0200 Subject: [PATCH 04/12] Fixed some error formatting --- cli/compile/compile.go | 2 +- cli/debug/debug.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/compile/compile.go b/cli/compile/compile.go index e35363e89ae..c765f31811c 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -241,7 +241,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) { Protocol: port.Protocol, }) if err != nil { - feedback.Errorf(tr("Error during Upload: %v"), err) + feedback.Errorf(tr("Error during Upload: %v", err)) os.Exit(errorcodes.ErrGeneric) } diff --git a/cli/debug/debug.go b/cli/debug/debug.go index ed47e5cee5e..1e76543e222 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -92,7 +92,7 @@ func runDebugCommand(command *cobra.Command, args []string) { if printInfo { if res, err := debug.GetDebugConfig(context.Background(), debugConfigRequested); err != nil { - feedback.Errorf(tr("Error getting Debug info: %v"), err) + feedback.Errorf(tr("Error getting Debug info: %v", err)) os.Exit(errorcodes.ErrBadArgument) } else { feedback.PrintResult(&debugInfoResult{res}) @@ -105,7 +105,7 @@ func runDebugCommand(command *cobra.Command, args []string) { signal.Notify(ctrlc, os.Interrupt) if _, err := debug.Debug(context.Background(), debugConfigRequested, os.Stdin, os.Stdout, ctrlc); err != nil { - feedback.Errorf(tr("Error during Debug: %v"), err) + feedback.Errorf(tr("Error during Debug: %v", err)) os.Exit(errorcodes.ErrGeneric) } From 6f7c9ee964a53711208c7c9916ba0fd735d23f42 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 17:59:55 +0200 Subject: [PATCH 05/12] Renamed some variable in compile/compile.go to improve readability fqbn -> fqbnArg port -> portArgs discoveryPort -> port --- cli/upload/upload.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/upload/upload.go b/cli/upload/upload.go index f0a77a5d4dc..8f9ebd8f7fd 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -39,8 +39,8 @@ import ( ) var ( - fqbn arguments.Fqbn - port arguments.Port + fqbnArg arguments.Fqbn + portArgs arguments.Port verbose bool verify bool importDir string @@ -64,8 +64,8 @@ func NewCommand() *cobra.Command { Run: runUploadCommand, } - fqbn.AddToCommand(uploadCommand) - port.AddToCommand(uploadCommand) + fqbnArg.AddToCommand(uploadCommand) + portArgs.AddToCommand(uploadCommand) uploadCommand.Flags().StringVarP(&importDir, "input-dir", "", "", tr("Directory containing binaries to upload.")) uploadCommand.Flags().StringVarP(&importFile, "input-file", "i", "", tr("Binary file to upload.")) uploadCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload.")) @@ -96,23 +96,23 @@ func runUploadCommand(command *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - discoveryPort, err := port.GetPort(instance, sk) + port, err := portArgs.GetPort(instance, sk) if err != nil { feedback.Errorf(tr("Error during Upload: %v"), err) os.Exit(errorcodes.ErrGeneric) } - if fqbn.String() == "" && sk != nil && sk.Metadata != nil { + if fqbnArg.String() == "" && sk != nil && sk.Metadata != nil { // If the user didn't specify an FQBN and a sketch.json file is present // read it from there. - fqbn.Set(sk.Metadata.CPU.Fqbn) + fqbnArg.Set(sk.Metadata.CPU.Fqbn) } userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: instance, - Fqbn: fqbn.String(), - Address: discoveryPort.Address, - Protocol: discoveryPort.Protocol, + Fqbn: fqbnArg.String(), + Address: port.Address, + Protocol: port.Protocol, }) if err != nil { feedback.Errorf(tr("Error during Upload: %v"), err) @@ -143,7 +143,7 @@ func runUploadCommand(command *cobra.Command, args []string) { fields := map[string]string{} if len(userFieldRes.UserFields) > 0 { - feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", discoveryPort.Protocol)) + feedback.Print(tr("Uploading to specified board using %s protocol requires the following info:", port.Protocol)) fields = arguments.AskForUserFields(userFieldRes.UserFields) } @@ -153,9 +153,9 @@ func runUploadCommand(command *cobra.Command, args []string) { if _, err := upload.Upload(context.Background(), &rpc.UploadRequest{ Instance: instance, - Fqbn: fqbn.String(), + Fqbn: fqbnArg.String(), SketchPath: path, - Port: discoveryPort.ToRPC(), + Port: port.ToRPC(), Verbose: verbose, Verify: verify, ImportFile: importFile, From da903d4f47d697f249a7e135d88e7710f20c6a1b Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 18:08:42 +0200 Subject: [PATCH 06/12] Refactored board autodetection in upload/compile - use `board.List()` instead of implementing a duplicate of it - factored the logic that calculates FQBN, Port and possibly autodetects FQBN, so we have a single implementation for all commands of the cli. --- cli/arguments/fqbn.go | 47 ++++++++++++++++++++ cli/arguments/port.go | 32 +++++++++++--- cli/compile/compile.go | 34 ++------------ cli/debug/debug.go | 7 ++- cli/upload/upload.go | 19 ++------ commands/upload/upload.go | 93 +-------------------------------------- 6 files changed, 86 insertions(+), 146 deletions(-) diff --git a/cli/arguments/fqbn.go b/cli/arguments/fqbn.go index 75862bce001..509a79bb396 100644 --- a/cli/arguments/fqbn.go +++ b/cli/arguments/fqbn.go @@ -16,8 +16,14 @@ package arguments import ( + "os" "strings" + "github.com/arduino/arduino-cli/arduino" + "github.com/arduino/arduino-cli/arduino/sketch" + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" + rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/spf13/cobra" ) @@ -54,3 +60,44 @@ func (f *Fqbn) String() string { func (f *Fqbn) Set(fqbn string) { f.fqbn = fqbn } + +// CalculateFQBNAndPort calculate the FQBN and Port metadata based on +// parameters provided by the user. +// This determine the FQBN based on: +// - the value of the FQBN flag if explicitly specified, otherwise +// - the FQBN value in sketch.json if available, otherwise +// - it tries to autodetect the board connected to the given port flags +// If all above methods fails, it returns the empty string. +// The Port metadata are always returned except if: +// - the port is not found, in this case nil is returned +// - the FQBN autodetection fail, in this case the function prints an error and +// terminates the execution +func CalculateFQBNAndPort(portArgs *Port, fqbnArg *Fqbn, instance *rpc.Instance, sk *sketch.Sketch) (string, *rpc.Port) { + // TODO: REMOVE sketch.Sketch from here + + fqbn := fqbnArg.String() + if fqbn == "" && sk != nil && sk.Metadata != nil { + // If the user didn't specify an FQBN and a sketch.json file is present + // read it from there. + fqbn = sk.Metadata.CPU.Fqbn + } + if fqbn == "" { + if portArgs == nil || portArgs.address == "" { + feedback.Error(&arduino.MissingFQBNError{}) + os.Exit(errorcodes.ErrGeneric) + } + fqbn, port := portArgs.DetectFQBN(instance) + if fqbn == "" { + feedback.Error(&arduino.MissingFQBNError{}) + os.Exit(errorcodes.ErrGeneric) + } + return fqbn, port + } + + port, err := portArgs.GetPort(instance, sk) + if err != nil { + feedback.Errorf(tr("Error getting port metadata: %v", err)) + os.Exit(errorcodes.ErrGeneric) + } + return fqbn, port.ToRPC() +} diff --git a/cli/arguments/port.go b/cli/arguments/port.go index b82db2cd9c2..58b47a6e464 100644 --- a/cli/arguments/port.go +++ b/cli/arguments/port.go @@ -21,11 +21,13 @@ import ( "os" "time" + "github.com/arduino/arduino-cli/arduino" "github.com/arduino/arduino-cli/arduino/discovery" "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/commands/board" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -152,12 +154,32 @@ func (p *Port) GetSearchTimeout() time.Duration { return p.timeout } -// GetDiscoveryPort is a helper function useful to get the port and handle possible errors -func (p *Port) GetDiscoveryPort(instance *rpc.Instance, sk *sketch.Sketch) *discovery.Port { - discoveryPort, err := p.GetPort(instance, sk) +// DetectFQBN tries to identify the board connected to the port and returns the +// discovered Port object together with the FQBN. If the port does not match +// exactly 1 board, +func (p *Port) DetectFQBN(inst *rpc.Instance) (string, *rpc.Port) { + detectedPorts, err := board.List(&rpc.BoardListRequest{Instance: inst}) if err != nil { - feedback.Errorf(tr("Error discovering port: %v"), err) + feedback.Errorf(tr("Error during FQBN detection: %v", err)) os.Exit(errorcodes.ErrGeneric) } - return discoveryPort + for _, detectedPort := range detectedPorts { + port := detectedPort.GetPort() + if p.address != port.GetAddress() { + continue + } + if p.protocol != "" && p.protocol != port.GetProtocol() { + continue + } + if len(detectedPort.MatchingBoards) > 1 { + feedback.Error(&arduino.MultipleBoardsDetectedError{Port: port}) + os.Exit(errorcodes.ErrBadArgument) + } + if len(detectedPort.MatchingBoards) == 0 { + feedback.Error(&arduino.NoBoardsDetectedError{Port: port}) + os.Exit(errorcodes.ErrBadArgument) + } + return detectedPort.MatchingBoards[0].Fqbn, port + } + return "", nil } diff --git a/cli/compile/compile.go b/cli/compile/compile.go index c765f31811c..41fc2e2e272 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -26,8 +26,6 @@ import ( "github.com/arduino/arduino-cli/arduino" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - "github.com/arduino/arduino-cli/arduino/discovery" - "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/globals" @@ -150,6 +148,8 @@ func runCompileCommand(cmd *cobra.Command, args []string) { } sketchPath := arguments.InitSketchPath(path) + sk := arguments.NewSketch(sketchPath) + fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, inst, sk) if keysKeychain != "" || signKey != "" || encryptKey != "" { arguments.CheckFlagsMandatory(cmd, "keys-keychain", "sign-key", "encrypt-key") @@ -172,25 +172,6 @@ func runCompileCommand(cmd *cobra.Command, args []string) { overrides = o.Overrides } - fqbn := fqbnArg.String() - var sk *sketch.Sketch - var port *discovery.Port - // If the user didn't provide an FQBN it might either mean - // that she forgot or that is trying to compile and upload - // using board autodetection. - if fqbn == "" && uploadAfterCompile { - sk = arguments.NewSketch(sketchPath) - port = portArgs.GetDiscoveryPort(inst, sk) - rpcPort := port.ToRPC() - var err error - pm := commands.GetPackageManager(inst.Id) - fqbn, err = upload.DetectConnectedBoard(pm, rpcPort.Address, rpcPort.Protocol) - if err != nil { - feedback.Errorf(tr("Error during FQBN detection: %v", err)) - os.Exit(errorcodes.ErrGeneric) - } - } - compileRequest := &rpc.CompileRequest{ Instance: inst, Fqbn: fqbn, @@ -227,16 +208,9 @@ func runCompileCommand(cmd *cobra.Command, args []string) { } if compileError == nil && uploadAfterCompile { - if sk == nil { - sk = arguments.NewSketch(sketchPath) - } - if port == nil { - port = portArgs.GetDiscoveryPort(inst, sk) - } - userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: inst, - Fqbn: fqbnArg.String(), + Fqbn: fqbn, Address: port.Address, Protocol: port.Protocol, }) @@ -255,7 +229,7 @@ func runCompileCommand(cmd *cobra.Command, args []string) { Instance: inst, Fqbn: fqbn, SketchPath: sketchPath.String(), - Port: port.ToRPC(), + Port: port, Verbose: verbose, Verify: verify, ImportDir: buildPath, diff --git a/cli/debug/debug.go b/cli/debug/debug.go index 1e76543e222..1dd0d56da25 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -77,13 +77,12 @@ func runDebugCommand(command *cobra.Command, args []string) { sketchPath := arguments.InitSketchPath(path) sk := arguments.NewSketch(sketchPath) - port := portArgs.GetDiscoveryPort(instance, sk) - + fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, instance, sk) debugConfigRequested := &dbg.DebugConfigRequest{ Instance: instance, - Fqbn: fqbnArg.String(), + Fqbn: fqbn, SketchPath: sketchPath.String(), - Port: port.ToRPC(), + Port: port, Interpreter: interpreter, ImportDir: importDir, Programmer: programmer.String(), diff --git a/cli/upload/upload.go b/cli/upload/upload.go index 8f9ebd8f7fd..93b962649c8 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -95,22 +95,11 @@ func runUploadCommand(command *cobra.Command, args []string) { feedback.Errorf(tr("Error during Upload: %v"), err) os.Exit(errorcodes.ErrGeneric) } - - port, err := portArgs.GetPort(instance, sk) - if err != nil { - feedback.Errorf(tr("Error during Upload: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } - - if fqbnArg.String() == "" && sk != nil && sk.Metadata != nil { - // If the user didn't specify an FQBN and a sketch.json file is present - // read it from there. - fqbnArg.Set(sk.Metadata.CPU.Fqbn) - } + fqbn, port := arguments.CalculateFQBNAndPort(&portArgs, &fqbnArg, instance, sk) userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: instance, - Fqbn: fqbnArg.String(), + Fqbn: fqbn, Address: port.Address, Protocol: port.Protocol, }) @@ -153,9 +142,9 @@ func runUploadCommand(command *cobra.Command, args []string) { if _, err := upload.Upload(context.Background(), &rpc.UploadRequest{ Instance: instance, - Fqbn: fqbnArg.String(), + Fqbn: fqbn, SketchPath: path, - Port: port.ToRPC(), + Port: port, Verbose: verbose, Verify: verify, ImportFile: importFile, diff --git a/commands/upload/upload.go b/commands/upload/upload.go index 89c92fb3f58..cfd85c406ce 100644 --- a/commands/upload/upload.go +++ b/commands/upload/upload.go @@ -52,16 +52,7 @@ func SupportedUserFields(ctx context.Context, req *rpc.SupportedUserFieldsReques return nil, &arduino.InvalidInstanceError{} } - reqFQBN := req.GetFqbn() - if reqFQBN == "" { - var err error - reqFQBN, err = DetectConnectedBoard(pm, req.Address, req.Protocol) - if err != nil { - return nil, err - } - } - - fqbn, err := cores.ParseFQBN(reqFQBN) + fqbn, err := cores.ParseFQBN(req.GetFqbn()) if err != nil { return nil, &arduino.InvalidFQBNError{Cause: err} } @@ -86,76 +77,6 @@ func SupportedUserFields(ctx context.Context, req *rpc.SupportedUserFieldsReques }, nil } -// DetectConnectedBoard returns the FQBN of the board connected to specified address and protocol. -// In all other cases, like when more than a possible board is detected return an error. -func DetectConnectedBoard(pm *packagemanager.PackageManager, address, protocol string) (string, error) { - if address == "" { - return "", &arduino.MissingPortAddressError{} - } - if protocol == "" { - return "", &arduino.MissingPortProtocolError{} - } - - dm := pm.DiscoveryManager() - - // Run discoveries if they're not already running - if errs := dm.RunAll(); len(errs) > 0 { - // Some discovery managed to not run, just log the errors, - // we'll fail further down the line. - for _, err := range errs { - logrus.Error(err) - } - } - - if errs := dm.StartAll(); len(errs) > 0 { - // Some discovery managed to not start, just log the errors, - // we'll fail further down the line. - for _, err := range errs { - logrus.Error(err) - } - } - - ports, errs := dm.List() - if len(errs) > 0 { - // Errors at this time are not a big issue, we'll - // fail further down the line if we can't find a - // matching board and tell the user to provide - // an FQBN. - for _, err := range errs { - logrus.Error(err) - } - } - - for _, p := range ports { - if p.Address == address && p.Protocol == protocol { - // Found matching port, let's see if we can detect - // which board is connected to it - boards := pm.IdentifyBoard(p.Properties) - if l := len(boards); l == 1 { - // We found only one board connected, that must - // the one the user want to upload to. - board := boards[0] - logrus. - WithField("board", board.String()). - WithField("address", address). - WithField("protocol", protocol). - Trace("Detected board") - return board.FQBN(), nil - } else if l >= 2 { - // There are multiple boards detected on this port, - // we have no way of knowing which one is the one. - return "", &arduino.MultipleBoardsDetectedError{Port: p.ToRPC()} - } else { - // We found a matching port but there's either - // no board connected or we can't recognize it. - // The user must provide an FQBN. - break - } - } - } - return "", &arduino.MissingFQBNError{} -} - // getToolID returns the ID of the tool that supports the action and protocol combination by searching in props. // Returns error if tool cannot be found. func getToolID(props *properties.Map, action, protocol string) (string, error) { @@ -271,18 +192,6 @@ func runProgramAction(pm *packagemanager.PackageManager, logrus.WithField("port", port).Tracef("Upload port") - if fqbnIn == "" && sk != nil && sk.Metadata != nil { - fqbnIn = sk.Metadata.CPU.Fqbn - } - - if fqbnIn == "" { - var err error - fqbnIn, err = DetectConnectedBoard(pm, port.Address, port.Protocol) - if err != nil { - return err - } - } - fqbn, err := cores.ParseFQBN(fqbnIn) if err != nil { return &arduino.InvalidFQBNError{Cause: err} From fd773dc27fc7058c6bf2bfa576a0aa5cf8b98b14 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 18:11:50 +0200 Subject: [PATCH 07/12] Removed SupportedUserFieldsRequest.Address gRPC parameter Because it's no more needed --- cli/compile/compile.go | 1 - cli/upload/upload.go | 1 - rpc/cc/arduino/cli/commands/v1/upload.pb.go | 52 ++++++++------------- rpc/cc/arduino/cli/commands/v1/upload.proto | 3 -- 4 files changed, 20 insertions(+), 37 deletions(-) diff --git a/cli/compile/compile.go b/cli/compile/compile.go index 41fc2e2e272..3104ff2aa71 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -211,7 +211,6 @@ func runCompileCommand(cmd *cobra.Command, args []string) { userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: inst, Fqbn: fqbn, - Address: port.Address, Protocol: port.Protocol, }) if err != nil { diff --git a/cli/upload/upload.go b/cli/upload/upload.go index 93b962649c8..2cec1380641 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -100,7 +100,6 @@ func runUploadCommand(command *cobra.Command, args []string) { userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: instance, Fqbn: fqbn, - Address: port.Address, Protocol: port.Protocol, }) if err != nil { diff --git a/rpc/cc/arduino/cli/commands/v1/upload.pb.go b/rpc/cc/arduino/cli/commands/v1/upload.pb.go index e9544a52876..f151a4288ea 100644 --- a/rpc/cc/arduino/cli/commands/v1/upload.pb.go +++ b/rpc/cc/arduino/cli/commands/v1/upload.pb.go @@ -776,9 +776,6 @@ type SupportedUserFieldsRequest struct { // necessary to pick the right upload tool for the board specified // with the FQBN. Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"` - // If an FQBN is not provided but both protocol and address are - // we can try and detect the FQBN using this information. - Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` } func (x *SupportedUserFieldsRequest) Reset() { @@ -834,13 +831,6 @@ func (x *SupportedUserFieldsRequest) GetProtocol() string { return "" } -func (x *SupportedUserFieldsRequest) GetAddress() string { - if x != nil { - return x.Address - } - return "" -} - type UserField struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1106,7 +1096,7 @@ var file_cc_arduino_cli_commands_v1_upload_proto_rawDesc = []byte{ 0x03, 0x28, 0x0b, 0x32, 0x26, 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, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x52, 0x0b, 0x70, 0x72, 0x6f, - 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x22, 0xa8, 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x70, + 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x1a, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x40, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, @@ -1115,27 +1105,25 @@ var file_cc_arduino_cli_commands_v1_upload_proto_rawDesc = []byte{ 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x62, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x22, 0x66, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, - 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x74, 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x65, 0x0a, 0x1b, 0x53, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x0b, 0x75, 0x73, - 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 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, 0x55, 0x73, 0x65, - 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, - 0x64, 0x73, 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, + 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x66, 0x0a, 0x09, 0x55, 0x73, 0x65, + 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x22, 0x65, 0x0a, 0x1b, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x55, 0x73, + 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x46, 0x0a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 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, 0x55, 0x73, 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x0a, 0x75, 0x73, + 0x65, 0x72, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 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/upload.proto b/rpc/cc/arduino/cli/commands/v1/upload.proto index d7638b26c08..d0aa108c0ef 100644 --- a/rpc/cc/arduino/cli/commands/v1/upload.proto +++ b/rpc/cc/arduino/cli/commands/v1/upload.proto @@ -162,9 +162,6 @@ message SupportedUserFieldsRequest { // necessary to pick the right upload tool for the board specified // with the FQBN. string protocol = 3; - // If an FQBN is not provided but both protocol and address are - // we can try and detect the FQBN using this information. - string address = 4; } message UserField { From 0679228959bba2df231c230ce60d80c2814a45f0 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 20 Apr 2022 18:13:07 +0200 Subject: [PATCH 08/12] Added notes about technical debt --- cli/arguments/port.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cli/arguments/port.go b/cli/arguments/port.go index 58b47a6e464..0de392f990c 100644 --- a/cli/arguments/port.go +++ b/cli/arguments/port.go @@ -74,6 +74,9 @@ func (p *Port) GetPortAddressAndProtocol(instance *rpc.Instance, sk *sketch.Sket // GetPort returns the Port obtained by parsing command line arguments. // The extra metadata for the ports is obtained using the pluggable discoveries. func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Port, error) { + // TODO: REMOVE sketch.Sketch from here + // TODO: REMOVE discvoery from here (use board.List instead) + address := p.address protocol := p.protocol From 8df8033a2bb26fecb03d1b45d3f9c576988372f7 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 21 Apr 2022 15:43:59 +0200 Subject: [PATCH 09/12] Factored --discovery-timeout flag and added timeout to board autodetection --- cli/arguments/discovery_timeout.go | 37 ++++++++++++++++++++++++++++++ cli/arguments/port.go | 13 +++++++---- cli/board/list.go | 12 +++++----- 3 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 cli/arguments/discovery_timeout.go diff --git a/cli/arguments/discovery_timeout.go b/cli/arguments/discovery_timeout.go new file mode 100644 index 00000000000..140c37fcef8 --- /dev/null +++ b/cli/arguments/discovery_timeout.go @@ -0,0 +1,37 @@ +// This file is part of arduino-cli. +// +// Copyright 2022 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package arguments + +import ( + "time" + + "github.com/spf13/cobra" +) + +// DiscoveryTimeout is the timeout given to discoveries to detect ports. +type DiscoveryTimeout struct { + timeout time.Duration +} + +// AddToCommand adds the flags used to set fqbn to the specified Command +func (d *DiscoveryTimeout) AddToCommand(cmd *cobra.Command) { + cmd.Flags().DurationVar(&d.timeout, "discovery-timeout", time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m")) +} + +// Get returns the timeout +func (d *DiscoveryTimeout) Get() time.Duration { + return d.timeout +} diff --git a/cli/arguments/port.go b/cli/arguments/port.go index 0de392f990c..d74ed4d974a 100644 --- a/cli/arguments/port.go +++ b/cli/arguments/port.go @@ -40,7 +40,7 @@ import ( type Port struct { address string protocol string - timeout time.Duration + timeout DiscoveryTimeout } // AddToCommand adds the flags used to set port and protocol to the specified Command @@ -53,7 +53,7 @@ func (p *Port) AddToCommand(cmd *cobra.Command) { cmd.RegisterFlagCompletionFunc("protocol", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return GetInstalledProtocols(), cobra.ShellCompDirectiveDefault }) - cmd.Flags().DurationVar(&p.timeout, "discovery-timeout", 5*time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m")) + p.timeout.AddToCommand(cmd) } // GetPortAddressAndProtocol returns only the port address and the port protocol @@ -127,7 +127,7 @@ func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Po } }() - deadline := time.After(p.timeout) + deadline := time.After(p.timeout.Get()) for { select { case portEvent := <-eventChan: @@ -154,14 +154,17 @@ func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Po // GetSearchTimeout returns the timeout func (p *Port) GetSearchTimeout() time.Duration { - return p.timeout + return p.timeout.Get() } // DetectFQBN tries to identify the board connected to the port and returns the // discovered Port object together with the FQBN. If the port does not match // exactly 1 board, func (p *Port) DetectFQBN(inst *rpc.Instance) (string, *rpc.Port) { - detectedPorts, err := board.List(&rpc.BoardListRequest{Instance: inst}) + detectedPorts, err := board.List(&rpc.BoardListRequest{ + Instance: inst, + Timeout: p.timeout.Get().Milliseconds(), + }) if err != nil { feedback.Errorf(tr("Error during FQBN detection: %v", err)) os.Exit(errorcodes.ErrGeneric) diff --git a/cli/board/list.go b/cli/board/list.go index eeae355ba7a..83f4e4418cd 100644 --- a/cli/board/list.go +++ b/cli/board/list.go @@ -19,9 +19,9 @@ import ( "fmt" "os" "sort" - "time" "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" @@ -33,8 +33,8 @@ import ( ) var ( - timeout time.Duration - watch bool + timeoutArg arguments.DiscoveryTimeout + watch bool ) func initListCommand() *cobra.Command { @@ -42,12 +42,12 @@ func initListCommand() *cobra.Command { Use: "list", Short: tr("List connected boards."), Long: tr("Detects and displays a list of boards connected to the current computer."), - Example: " " + os.Args[0] + " board list --timeout 10s", + Example: " " + os.Args[0] + " board list --discovery-timeout 10s", Args: cobra.NoArgs, Run: runListCommand, } - listCommand.Flags().DurationVar(&timeout, "discovery-timeout", time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m")) + timeoutArg.AddToCommand(listCommand) listCommand.Flags().BoolVarP(&watch, "watch", "w", false, tr("Command keeps running and prints list of connected boards whenever there is a change.")) return listCommand @@ -66,7 +66,7 @@ func runListCommand(cmd *cobra.Command, args []string) { ports, err := board.List(&rpc.BoardListRequest{ Instance: inst, - Timeout: timeout.Milliseconds(), + Timeout: timeoutArg.Get().Milliseconds(), }) if err != nil { feedback.Errorf(tr("Error detecting boards: %v"), err) From 3e0cf80585814c5e1c6b67d7b22ad4ebb074d841 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 21 Apr 2022 15:44:14 +0200 Subject: [PATCH 10/12] Added docs --- docs/UPGRADING.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index bca31e0b706..798006ae9e2 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -4,6 +4,39 @@ Here you can find a list of migration guides to handle breaking changes between ## 0.22.0 +### `github.com/arduino/arduino-cli/arduino.MultipleBoardsDetectedError` field changed type + +Now the `Port` field of the error is a `github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1.Port`, usually +imported as `rpc.Port`. The old `discovery.Port` can be converted to the new one using the `.ToRPC()` method. + +### Function `github.com/arduino/arduino-cli/commands/upload.DetectConnectedBoard(...)` has been removed + +Use `github.com/arduino/arduino-cli/commands/board.List(...)` to detect boards. + +### Function `arguments.GetDiscoveryPort(...)` has been removed + +NOTE: the functions in the `arguments` package doesn't have much use outside of the `arduino-cli` so we are considering +to remove them from the public golang API making them `internal`. + +The old function: + +```go +func (p *Port) GetDiscoveryPort(instance *rpc.Instance, sk *sketch.Sketch) *discovery.Port { } +``` + +is now replaced by the more powerful: + +```go +func (p *Port) DetectFQBN(inst *rpc.Instance) (string, *rpc.Port) { } + +func CalculateFQBNAndPort(portArgs *Port, fqbnArg *Fqbn, instance *rpc.Instance, sk *sketch.Sketch) (string, *rpc.Port) { } +``` + +### gRPC: `address` parameter has been removed from `commands.SupportedUserFieldsRequest` + +The parameter is no more needed. Lagacy code will continue to work without modification (the value of the parameter will +be just ignored). + ### The content of package `github.com/arduino/arduino-cli/httpclient` has been moved to a different path In particular: From d7d5411d919e3c2cb6dee88d0e65465ead623ba1 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 21 Apr 2022 17:00:24 +0200 Subject: [PATCH 11/12] Fixed error message and integration tests --- cli/arguments/sketch.go | 2 +- test/test_compile_part_1.py | 4 ++-- test/test_compile_part_3.py | 12 ++++++------ test/test_compile_part_4.py | 2 +- test/test_upload.py | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/arguments/sketch.go b/cli/arguments/sketch.go index bb14af47ef2..11a93c1963b 100644 --- a/cli/arguments/sketch.go +++ b/cli/arguments/sketch.go @@ -48,7 +48,7 @@ func InitSketchPath(path string) (sketchPath *paths.Path) { func NewSketch(sketchPath *paths.Path) *sketch.Sketch { sketch, err := sketch.New(sketchPath) if err != nil { - feedback.Errorf(tr("Error creating sketch: %v"), err) + feedback.Errorf(tr("Error opening sketch: %v"), err) os.Exit(errorcodes.ErrGeneric) } return sketch diff --git a/test/test_compile_part_1.py b/test/test_compile_part_1.py index 90579a79f20..e53c6360b37 100644 --- a/test/test_compile_part_1.py +++ b/test/test_compile_part_1.py @@ -131,7 +131,7 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): result = run_command(["compile", "-b", fqbn, sketch_path]) # The assertion is a bit relaxed in this case because win behaves differently from macOs and linux # returning a different error detailed message - assert "Error during build: Can't open sketch:" in result.stderr + assert "Error opening sketch:" in result.stderr assert not result.ok sketch_name = "CompileIntegrationTestSymlinkDirLoop" @@ -153,7 +153,7 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir): result = run_command(["compile", "-b", fqbn, sketch_path]) # The assertion is a bit relaxed in this case because win behaves differently from macOs and linux # returning a different error detailed message - assert "Error during build: Can't open sketch:" in result.stderr + assert "Error opening sketch:" in result.stderr assert not result.ok diff --git a/test/test_compile_part_3.py b/test/test_compile_part_3.py index d2385c8b5f6..69b50864542 100644 --- a/test/test_compile_part_3.py +++ b/test/test_compile_part_3.py @@ -91,17 +91,17 @@ def test_compile_sketch_with_multiple_main_files(run_command, data_dir): # Build sketch from folder res = run_command(["compile", "--clean", "-b", fqbn, sketch_path]) assert res.failed - assert "Error during build: Can't open sketch: multiple main sketch files found" in res.stderr + assert "Error opening sketch: multiple main sketch files found" in res.stderr # Build sketch from .ino file res = run_command(["compile", "--clean", "-b", fqbn, sketch_ino_file]) assert res.failed - assert "Error during build: Can't open sketch: multiple main sketch files found" in res.stderr + assert "Error opening sketch: multiple main sketch files found" in res.stderr # Build sketch from .pde file res = run_command(["compile", "--clean", "-b", fqbn, sketch_pde_file]) assert res.failed - assert "Error during build: Can't open sketch: multiple main sketch files found" in res.stderr + assert "Error opening sketch: multiple main sketch files found" in res.stderr def test_compile_sketch_case_mismatch_fails(run_command, data_dir): @@ -124,15 +124,15 @@ def test_compile_sketch_case_mismatch_fails(run_command, data_dir): # * Compiling with sketch path res = run_command(["compile", "--clean", "-b", fqbn, sketch_path]) assert res.failed - assert "Error during build: Can't open sketch: no valid sketch found" in res.stderr + assert "Error opening sketch: no valid sketch found" in res.stderr # * Compiling with sketch main file res = run_command(["compile", "--clean", "-b", fqbn, sketch_main_file]) assert res.failed - assert "Error during build: Can't open sketch: no valid sketch found" in res.stderr + assert "Error opening sketch: no valid sketch found" in res.stderr # * Compiling in sketch path res = run_command(["compile", "--clean", "-b", fqbn], custom_working_dir=sketch_path) assert res.failed - assert "Error during build: Can't open sketch: no valid sketch found" in res.stderr + assert "Error opening sketch: no valid sketch found" in res.stderr def test_compile_with_only_compilation_database_flag(run_command, data_dir): diff --git a/test/test_compile_part_4.py b/test/test_compile_part_4.py index bdc85d8cb9e..2066811a1d1 100644 --- a/test/test_compile_part_4.py +++ b/test/test_compile_part_4.py @@ -377,7 +377,7 @@ def test_compile_without_upload_and_fqbn(run_command, data_dir): res = run_command(["compile", sketch_path]) assert res.failed - assert "Error during build: Missing FQBN (Fully Qualified Board Name)" in res.stderr + assert "Missing FQBN (Fully Qualified Board Name)" in res.stderr def test_compile_non_installed_platform_with_wrong_packager_and_arch(run_command, data_dir): diff --git a/test/test_upload.py b/test/test_upload.py index 3020a50c210..a6eed7f249d 100644 --- a/test/test_upload.py +++ b/test/test_upload.py @@ -364,7 +364,7 @@ def test_compile_and_upload_combo_sketch_with_mismatched_casing(run_command, dat # Try to compile res = run_command(["compile", "--clean", "-b", board.fqbn, "-u", "-p", board.address, sketch_path]) assert res.failed - assert "Error during build: Can't open sketch: no valid sketch found in" in res.stderr + assert "Error opening sketch: no valid sketch found in" in res.stderr def test_upload_sketch_with_mismatched_casing(run_command, data_dir, detected_boards, wait_for_board): From de4c9dc4c9f24d2210c0211d3ee128f26d3d3039 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 2 May 2022 11:47:32 +0200 Subject: [PATCH 12/12] Update cli/arguments/port.go Co-authored-by: Umberto Baldi <34278123+umbynos@users.noreply.github.com> --- cli/arguments/port.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/arguments/port.go b/cli/arguments/port.go index d74ed4d974a..12e7e28f5c7 100644 --- a/cli/arguments/port.go +++ b/cli/arguments/port.go @@ -75,7 +75,7 @@ func (p *Port) GetPortAddressAndProtocol(instance *rpc.Instance, sk *sketch.Sket // The extra metadata for the ports is obtained using the pluggable discoveries. func (p *Port) GetPort(instance *rpc.Instance, sk *sketch.Sketch) (*discovery.Port, error) { // TODO: REMOVE sketch.Sketch from here - // TODO: REMOVE discvoery from here (use board.List instead) + // TODO: REMOVE discovery from here (use board.List instead) address := p.address protocol := p.protocol