diff --git a/cli/arguments/arguments.go b/cli/arguments/arguments.go index 5d0a7c6eff9..92a057986d2 100644 --- a/cli/arguments/arguments.go +++ b/cli/arguments/arguments.go @@ -15,6 +15,25 @@ package arguments -import "github.com/arduino/arduino-cli/i18n" +import ( + "os" + "strings" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/arduino-cli/i18n" + "github.com/spf13/cobra" +) var tr = i18n.Tr + +// CheckFlagsConflicts is a helper function useful to report errors when more than one conflicting flag is used +func CheckFlagsConflicts(command *cobra.Command, flagNames ...string) { + for _, flagName := range flagNames { + if !command.Flag(flagName).Changed { + return + } + } + feedback.Errorf(tr("Can't use %s flags at the same time.", "--"+strings.Join(flagNames, " "+tr("and")+" --"))) + os.Exit(errorcodes.ErrBadArgument) +} diff --git a/cli/arguments/fqbn.go b/cli/arguments/fqbn.go new file mode 100644 index 00000000000..7eae7776126 --- /dev/null +++ b/cli/arguments/fqbn.go @@ -0,0 +1,43 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 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 "github.com/spf13/cobra" + +// Fqbn contains the fqbn flag data. +// This is useful so all flags used by commands that need +// this information are consistent with each other. +type Fqbn struct { + fqbn string +} + +// AddToCommand adds the flags used to set fqbn to the specified Command +func (f *Fqbn) AddToCommand(cmd *cobra.Command) { + cmd.Flags().StringVarP(&f.fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) + cmd.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return GetInstalledBoards(), cobra.ShellCompDirectiveDefault + }) +} + +// String returns the fqbn +func (f *Fqbn) String() string { + return f.fqbn +} + +// Set sets the fqbn +func (f *Fqbn) Set(fqbn string) { + f.fqbn = fqbn +} diff --git a/cli/arguments/port.go b/cli/arguments/port.go index c723335efcd..b82db2cd9c2 100644 --- a/cli/arguments/port.go +++ b/cli/arguments/port.go @@ -18,10 +18,12 @@ package arguments import ( "fmt" "net/url" + "os" "time" "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" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" @@ -144,3 +146,18 @@ 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 +} + +// 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) + if err != nil { + feedback.Errorf(tr("Error discovering port: %v"), err) + os.Exit(errorcodes.ErrGeneric) + } + return discoveryPort +} diff --git a/cli/arguments/post_install.go b/cli/arguments/post_install.go new file mode 100644 index 00000000000..1db4eb85645 --- /dev/null +++ b/cli/arguments/post_install.go @@ -0,0 +1,66 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 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 ( + "github.com/arduino/arduino-cli/configuration" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +// PostInstallFlags contains flags data used by the core install and the upgrade command +// This is useful so all flags used by commands that need +// this information are consistent with each other. +type PostInstallFlags struct { + runPostInstall bool // force the execution of installation scripts + skipPostInstall bool //skip the execution of installation scripts +} + +// AddToCommand adds flags that can be used to force running or skipping +// of post installation scripts +func (p *PostInstallFlags) AddToCommand(cmd *cobra.Command) { + cmd.Flags().BoolVar(&p.runPostInstall, "run-post-install", false, tr("Force run of post-install scripts (if the CLI is not running interactively).")) + cmd.Flags().BoolVar(&p.skipPostInstall, "skip-post-install", false, tr("Force skip of post-install scripts (if the CLI is running interactively).")) +} + +// GetRunPostInstall returns the run-post-install flag value +func (p *PostInstallFlags) GetRunPostInstall() bool { + return p.runPostInstall +} + +// GetSkipPostInstall returns the skip-post-install flag value +func (p *PostInstallFlags) GetSkipPostInstall() bool { + return p.skipPostInstall +} + +// DetectSkipPostInstallValue returns true if a post install script must be run +func (p *PostInstallFlags) DetectSkipPostInstallValue() bool { + if p.GetRunPostInstall() { + logrus.Info("Will run post-install by user request") + return false + } + if p.GetSkipPostInstall() { + logrus.Info("Will skip post-install by user request") + return true + } + + if !configuration.IsInteractive { + logrus.Info("Not running from console, will skip post-install by default") + return true + } + logrus.Info("Running from console, will run post-install by default") + return false +} diff --git a/cli/arguments/programmer.go b/cli/arguments/programmer.go new file mode 100644 index 00000000000..4cb00edd8d9 --- /dev/null +++ b/cli/arguments/programmer.go @@ -0,0 +1,38 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 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 "github.com/spf13/cobra" + +// Programmer contains the programmer flag data. +// This is useful so all flags used by commands that need +// this information are consistent with each other. +type Programmer struct { + programmer string +} + +// AddToCommand adds the flags used to set the programmer to the specified Command +func (p *Programmer) AddToCommand(cmd *cobra.Command) { + cmd.Flags().StringVarP(&p.programmer, "programmer", "P", "", tr("Programmer to use, e.g: atmel_ice")) + cmd.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault + }) +} + +// String returns the programmer +func (p *Programmer) String() string { + return p.programmer +} diff --git a/cli/arguments/sketch.go b/cli/arguments/sketch.go index 5c95cfd7f85..bb14af47ef2 100644 --- a/cli/arguments/sketch.go +++ b/cli/arguments/sketch.go @@ -18,6 +18,7 @@ package arguments import ( "os" + "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/go-paths-helper" @@ -26,16 +27,40 @@ import ( // InitSketchPath returns an instance of paths.Path pointing to sketchPath. // If sketchPath is an empty string returns the current working directory. -func InitSketchPath(sketchPath string) *paths.Path { - if sketchPath != "" { - return paths.New(sketchPath) +// In both cases it warns the user if he's using deprecated files +func InitSketchPath(path string) (sketchPath *paths.Path) { + if path != "" { + sketchPath = paths.New(path) + } else { + wd, err := paths.Getwd() + if err != nil { + feedback.Errorf(tr("Couldn't get current working directory: %v"), err) + os.Exit(errorcodes.ErrGeneric) + } + logrus.Infof("Reading sketch from dir: %s", wd) + sketchPath = wd } + WarnDeprecatedFiles(sketchPath) + return sketchPath +} - wd, err := paths.Getwd() +// NewSketch is a helper function useful to create a sketch instance +func NewSketch(sketchPath *paths.Path) *sketch.Sketch { + sketch, err := sketch.New(sketchPath) if err != nil { - feedback.Errorf(tr("Couldn't get current working directory: %v"), err) + feedback.Errorf(tr("Error creating sketch: %v"), err) os.Exit(errorcodes.ErrGeneric) } - logrus.Infof("Reading sketch from dir: %s", wd) - return wd + return sketch +} + +// WarnDeprecatedFiles warns the user that a type of sketch files are deprecated +func WarnDeprecatedFiles(sketchPath *paths.Path) { + // .pde files are still supported but deprecated, this warning urges the user to rename them + if files := sketch.CheckForPdeFiles(sketchPath); len(files) > 0 { + feedback.Error(tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")) + for _, f := range files { + feedback.Error(f) + } + } } diff --git a/cli/board/attach.go b/cli/board/attach.go index 5c185064b34..cc715e52142 100644 --- a/cli/board/attach.go +++ b/cli/board/attach.go @@ -27,43 +27,56 @@ import ( "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands/board" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) +var ( + port arguments.Port +) + func initAttachCommand() *cobra.Command { attachCommand := &cobra.Command{ - Use: fmt.Sprintf("attach <%s>|<%s> [%s]", tr("port"), tr("FQBN"), tr("sketchPath")), + Use: fmt.Sprintf("attach -p <%s>|-b <%s> [%s]", tr("port"), tr("FQBN"), tr("sketchPath")), Short: tr("Attaches a sketch to a board."), Long: tr("Attaches a sketch to a board."), - Example: " " + os.Args[0] + " board attach serial:///dev/ttyACM0\n" + - " " + os.Args[0] + " board attach serial:///dev/ttyACM0 HelloWorld\n" + - " " + os.Args[0] + " board attach arduino:samd:mkr1000", - Args: cobra.RangeArgs(1, 2), + Example: " " + os.Args[0] + " board attach -p /dev/ttyACM0\n" + + " " + os.Args[0] + " board attach -p /dev/ttyACM0 HelloWorld\n" + + " " + os.Args[0] + " board attach -b arduino:samd:mkr1000", + Args: cobra.MaximumNArgs(1), Run: runAttachCommand, } - attachCommand.Flags().StringVar(&attachFlags.searchTimeout, "timeout", "5s", - tr("The connected devices search timeout, raise it if your board doesn't show up (e.g. to %s).", "10s")) - return attachCommand -} + fqbn.AddToCommand(attachCommand) + port.AddToCommand(attachCommand) -var attachFlags struct { - searchTimeout string // Expressed in a parsable duration, is the timeout for the list and attach commands. + return attachCommand } func runAttachCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli board attach`") + path := "" - if len(args) > 1 { - path = args[1] + if len(args) > 0 { + path = args[0] } sketchPath := arguments.InitSketchPath(path) + // ugly hack to allow user to specify fqbn and port as flags (consistency) + // a more meaningful fix would be to fix board.Attach + var boardURI string + discoveryPort, _ := port.GetPort(instance, nil) + if fqbn.String() != "" { + boardURI = fqbn.String() + } else if discoveryPort != nil { + boardURI = discoveryPort.Address + } if _, err := board.Attach(context.Background(), &rpc.BoardAttachRequest{ Instance: instance, - BoardUri: args[0], + BoardUri: boardURI, SketchPath: sketchPath.String(), - SearchTimeout: attachFlags.searchTimeout, + SearchTimeout: port.GetSearchTimeout().String(), }, output.TaskProgress()); err != nil { feedback.Errorf(tr("Attach board error: %v"), err) os.Exit(errorcodes.ErrGeneric) diff --git a/cli/board/board.go b/cli/board/board.go index d1dbb9add35..8ed5531f150 100644 --- a/cli/board/board.go +++ b/cli/board/board.go @@ -18,9 +18,12 @@ package board import ( "os" + "github.com/arduino/arduino-cli/i18n" "github.com/spf13/cobra" ) +var tr = i18n.Tr + // NewCommand created a new `board` command func NewCommand() *cobra.Command { boardCommand := &cobra.Command{ diff --git a/cli/board/details.go b/cli/board/details.go index abe5234ab3f..a51957ac917 100644 --- a/cli/board/details.go +++ b/cli/board/details.go @@ -25,17 +25,18 @@ import ( "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/commands/board" - "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/table" "github.com/fatih/color" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var tr = i18n.Tr -var showFullDetails bool -var fqbn string -var listProgrammers bool +var ( + showFullDetails bool + listProgrammers bool + fqbn arguments.Fqbn +) func initDetailsCommand() *cobra.Command { var detailsCommand = &cobra.Command{ @@ -43,17 +44,14 @@ func initDetailsCommand() *cobra.Command { Short: tr("Print details about a board."), Long: tr("Show information about a board, in particular if the board has options to be specified in the FQBN."), Example: " " + os.Args[0] + " board details -b arduino:avr:nano", - Args: cobra.MaximumNArgs(1), + Args: cobra.NoArgs, Run: runDetailsCommand, } + fqbn.AddToCommand(detailsCommand) detailsCommand.Flags().BoolVarP(&showFullDetails, "full", "f", false, tr("Show full board details")) - detailsCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - detailsCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) detailsCommand.Flags().BoolVarP(&listProgrammers, "list-programmers", "", false, tr("Show list of available programmers")) - // detailsCommand.MarkFlagRequired("fqbn") // enable once `board details ` is removed + detailsCommand.MarkFlagRequired("fqbn") return detailsCommand } @@ -61,14 +59,11 @@ func initDetailsCommand() *cobra.Command { func runDetailsCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - // remove once `board details ` is removed - if fqbn == "" && len(args) > 0 { - fqbn = args[0] - } + logrus.Info("Executing `arduino-cli board details`") res, err := board.Details(context.Background(), &rpc.BoardDetailsRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: fqbn.String(), }) if err != nil { diff --git a/cli/board/list.go b/cli/board/list.go index 15daebd2d37..a08a7cf4a0c 100644 --- a/cli/board/list.go +++ b/cli/board/list.go @@ -28,9 +28,15 @@ import ( "github.com/arduino/arduino-cli/commands/board" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/table" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) +var ( + timeout time.Duration + watch bool +) + func initListCommand() *cobra.Command { listCommand := &cobra.Command{ Use: "list", @@ -41,31 +47,26 @@ func initListCommand() *cobra.Command { Run: runListCommand, } - listCommand.Flags().DurationVar(&listFlags.timeout, "timeout", time.Second, - tr("The connected devices search timeout, raise it if your board doesn't show up e.g.: 10s")) - listCommand.Flags().BoolVarP(&listFlags.watch, "watch", "w", false, - tr("Command keeps running and prints list of connected boards whenever there is a change.")) + listCommand.Flags().DurationVar(&timeout, "discovery-timeout", time.Second, tr("Max time to wait for port discovery, e.g.: 30s, 1m")) + listCommand.Flags().BoolVarP(&watch, "watch", "w", false, tr("Command keeps running and prints list of connected boards whenever there is a change.")) return listCommand } -var listFlags struct { - timeout time.Duration - watch bool -} - // runListCommand detects and lists the connected arduino boards func runListCommand(cmd *cobra.Command, args []string) { - if listFlags.watch { - inst := instance.CreateAndInit() + inst := instance.CreateAndInit() + + logrus.Info("Executing `arduino-cli board list`") + + if watch { watchList(cmd, inst) os.Exit(0) } - inst := instance.CreateAndInit() ports, err := board.List(&rpc.BoardListRequest{ Instance: inst, - Timeout: listFlags.timeout.Milliseconds(), + Timeout: timeout.Milliseconds(), }) if err != nil { feedback.Errorf(tr("Error detecting boards: %v"), err) diff --git a/cli/board/listall.go b/cli/board/listall.go index 4093abd8642..b4142b935cd 100644 --- a/cli/board/listall.go +++ b/cli/board/listall.go @@ -27,9 +27,12 @@ import ( "github.com/arduino/arduino-cli/commands/board" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/table" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) +var showHiddenBoard bool + func initListAllCommand() *cobra.Command { var listAllCommand = &cobra.Command{ Use: fmt.Sprintf("listall [%s]", tr("boardname")), @@ -46,12 +49,12 @@ for a specific board if you specify the board name`), return listAllCommand } -var showHiddenBoard bool - // runListAllCommand list all installed boards func runListAllCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli board listall`") + list, err := board.ListAll(context.Background(), &rpc.BoardListAllRequest{ Instance: inst, SearchArgs: args, diff --git a/cli/board/search.go b/cli/board/search.go index b6768ab8020..be2e7b97e19 100644 --- a/cli/board/search.go +++ b/cli/board/search.go @@ -28,6 +28,7 @@ import ( "github.com/arduino/arduino-cli/commands/board" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/table" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -43,21 +44,19 @@ for a specific board if you specify the board name`), Args: cobra.ArbitraryArgs, Run: runSearchCommand, } - searchCommand.Flags().BoolVarP(&searchFlags.showHiddenBoard, "show-hidden", "a", false, tr("Show also boards marked as 'hidden' in the platform")) + searchCommand.Flags().BoolVarP(&showHiddenBoard, "show-hidden", "a", false, tr("Show also boards marked as 'hidden' in the platform")) return searchCommand } -var searchFlags struct { - showHiddenBoard bool -} - func runSearchCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli board search`") + res, err := board.Search(context.Background(), &rpc.BoardSearchRequest{ Instance: inst, SearchArgs: strings.Join(args, " "), - IncludeHiddenBoards: searchFlags.showHiddenBoard, + IncludeHiddenBoards: showHiddenBoard, }) if err != nil { feedback.Errorf(tr("Error searching boards: %v"), err) diff --git a/cli/burnbootloader/burnbootloader.go b/cli/burnbootloader/burnbootloader.go index 7a1ea0db27f..f16997086be 100644 --- a/cli/burnbootloader/burnbootloader.go +++ b/cli/burnbootloader/burnbootloader.go @@ -26,15 +26,16 @@ import ( "github.com/arduino/arduino-cli/commands/upload" "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( - fqbn string + fqbn arguments.Fqbn port arguments.Port verbose bool verify bool - programmer string + programmer arguments.Programmer dryRun bool tr = i18n.Tr ) @@ -47,29 +48,25 @@ func NewCommand() *cobra.Command { Long: tr("Upload the bootloader on the board using an external programmer."), Example: " " + os.Args[0] + " burn-bootloader -b arduino:avr:uno -P atmel_ice", Args: cobra.MaximumNArgs(1), - Run: run, + Run: runBootloaderCommand, } - burnBootloaderCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - burnBootloaderCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) + fqbn.AddToCommand(burnBootloaderCommand) port.AddToCommand(burnBootloaderCommand) + programmer.AddToCommand(burnBootloaderCommand) burnBootloaderCommand.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload.")) burnBootloaderCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Turns on verbose mode.")) - burnBootloaderCommand.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Use the specified programmer to upload.")) - burnBootloaderCommand.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault - }) burnBootloaderCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions")) burnBootloaderCommand.Flags().MarkHidden("dry-run") return burnBootloaderCommand } -func run(command *cobra.Command, args []string) { +func runBootloaderCommand(command *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli burn-bootloader`") + // We don't need a Sketch to upload a board's bootloader discoveryPort, err := port.GetPort(instance, nil) if err != nil { @@ -79,11 +76,11 @@ func run(command *cobra.Command, args []string) { if _, err := upload.BurnBootloader(context.Background(), &rpc.BurnBootloaderRequest{ Instance: instance, - Fqbn: fqbn, + Fqbn: fqbn.String(), Port: discoveryPort.ToRPC(), Verbose: verbose, Verify: verify, - Programmer: programmer, + Programmer: programmer.String(), DryRun: dryRun, }, os.Stdout, os.Stderr); err != nil { feedback.Errorf(tr("Error during Upload: %v"), err) diff --git a/cli/cache/clean.go b/cli/cache/clean.go index 774cd6f63c8..9633737591c 100644 --- a/cli/cache/clean.go +++ b/cli/cache/clean.go @@ -38,7 +38,7 @@ func initCleanCommand() *cobra.Command { } func runCleanCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino cache clean`") + logrus.Info("Executing `arduino-cli cache clean`") cachePath := configuration.Settings.GetString("directories.Downloads") err := os.RemoveAll(cachePath) diff --git a/cli/compile/compile.go b/cli/compile/compile.go index 493cd80d39f..0563f8501db 100644 --- a/cli/compile/compile.go +++ b/cli/compile/compile.go @@ -21,13 +21,12 @@ import ( "encoding/json" "os" - "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/output" "github.com/arduino/arduino-cli/configuration" "github.com/arduino/arduino-cli/i18n" + "github.com/sirupsen/logrus" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/instance" @@ -39,25 +38,25 @@ import ( ) var ( - fqbn string // 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. - buildPath string // Path where to save compiled files. - buildProperties []string // List of custom build properties separated by commas. Or can be used multiple times for multiple properties. - warnings string // Used to tell gcc which warning level to use. - verbose bool // Turns on verbose mode. - 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. - 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 - programmer string // Use the specified programmer to upload - clean bool // Cleanup the build folder and do not use any cached build - compilationDatabaseOnly bool // Only create compilation database without actually compiling - sourceOverrides string // Path to a .json file that contains a set of replacements of the sketch source code. + fqbn 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. + buildPath string // Path where to save compiled files. + buildProperties []string // List of custom build properties separated by commas. Or can be used multiple times for multiple properties. + warnings string // Used to tell gcc which warning level to use. + verbose bool // Turns on verbose mode. + 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. + 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 + programmer arguments.Programmer // Use the specified programmer to upload + clean bool // Cleanup the build folder and do not use any cached build + compilationDatabaseOnly bool // Only create compilation database without actually compiling + sourceOverrides string // Path to a .json file that contains a set of replacements of the sketch source code. // library and libraries sound similar but they're actually different. // library expects a path to the root folder of one single library. // libraries expects a path to a directory containing multiple libraries, similarly to the /libraries path. @@ -68,7 +67,7 @@ var ( // NewCommand created a new `compile` command func NewCommand() *cobra.Command { - command := &cobra.Command{ + compileCommand := &cobra.Command{ Use: "compile", Short: tr("Compiles Arduino sketches."), Long: tr("Compiles Arduino sketches."), @@ -78,72 +77,61 @@ func NewCommand() *cobra.Command { " " + os.Args[0] + ` compile -b arduino:avr:uno --build-property "build.extra_flags=-DPIN=2 \"-DMY_DEFINE=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n" + " " + os.Args[0] + ` compile -b arduino:avr:uno --build-property build.extra_flags=-DPIN=2 --build-property "compiler.cpp.extra_flags=\"-DSSID=\"hello world\"\"" /home/user/Arduino/MySketch` + "\n", Args: cobra.MaximumNArgs(1), - Run: run, + Run: runCompileCommand, } - command.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - command.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) - command.Flags().BoolVar(&showProperties, "show-properties", false, tr("Show all build properties used instead of compiling.")) - command.Flags().BoolVar(&preprocess, "preprocess", false, tr("Print preprocessed code to stdout instead of compiling.")) - command.Flags().StringVar(&buildCachePath, "build-cache-path", "", tr("Builds of 'core.a' are saved into this path to be cached and reused.")) - command.Flags().StringVarP(&exportDir, "output-dir", "", "", tr("Save build artifacts in this directory.")) - command.Flags().StringVar(&buildPath, "build-path", "", + fqbn.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.")) + compileCommand.Flags().StringVarP(&exportDir, "output-dir", "", "", tr("Save build artifacts in this directory.")) + compileCommand.Flags().StringVar(&buildPath, "build-path", "", tr("Path where to save compiled files. If omitted, a directory will be created in the default temporary path of your OS.")) - command.Flags().StringSliceVar(&buildProperties, "build-properties", []string{}, + compileCommand.Flags().StringSliceVar(&buildProperties, "build-properties", []string{}, tr("List of custom build properties separated by commas. Or can be used multiple times for multiple properties.")) - command.Flags().StringArrayVar(&buildProperties, "build-property", []string{}, + compileCommand.Flags().StringArrayVar(&buildProperties, "build-property", []string{}, tr("Override a build property with a custom value. Can be used multiple times for multiple properties.")) - command.Flags().StringVar(&warnings, "warnings", "none", + compileCommand.Flags().StringVar(&warnings, "warnings", "none", tr(`Optional, can be: %s. Used to tell gcc which warning level to use (-W flag).`, "none, default, more, all")) - command.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode.")) - command.Flags().BoolVar(&quiet, "quiet", false, tr("Optional, suppresses almost every output.")) - command.Flags().BoolVarP(&uploadAfterCompile, "upload", "u", false, tr("Upload the binary after the compilation.")) - port.AddToCommand(command) - command.Flags().BoolVarP(&verify, "verify", "t", false, tr("Verify uploaded binary after the upload.")) - command.Flags().StringVar(&vidPid, "vid-pid", "", tr("When specified, VID/PID specific build properties are used, if board supports them.")) - command.Flags().StringSliceVar(&library, "library", []string{}, + 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) + 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{}, tr("List of paths to libraries root folders. Libraries set this way have top priority in case of conflicts. Can be used multiple times for different libraries.")) - command.Flags().StringSliceVar(&libraries, "libraries", []string{}, + compileCommand.Flags().StringSliceVar(&libraries, "libraries", []string{}, tr("List of custom libraries dir paths separated by commas. Or can be used multiple times for multiple libraries dir paths.")) - command.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, tr("Optional, optimize compile output for debugging, rather than for release.")) - command.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Optional, use the specified programmer to upload.")) - command.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault - }) - command.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, tr("Just produce the compilation database, without actually compiling. All build commands are skipped except pre* hooks.")) - command.Flags().BoolVar(&clean, "clean", false, tr("Optional, cleanup the build folder and do not use any cached build.")) + compileCommand.Flags().BoolVar(&optimizeForDebug, "optimize-for-debug", false, tr("Optional, optimize compile output for debugging, rather than for release.")) + programmer.AddToCommand(compileCommand) + compileCommand.Flags().BoolVar(&compilationDatabaseOnly, "only-compilation-database", false, tr("Just produce the compilation database, without actually compiling. All build commands are skipped except pre* hooks.")) + compileCommand.Flags().BoolVar(&clean, "clean", false, tr("Optional, cleanup the build folder and do not use any cached build.")) // We must use the following syntax for this flag since it's also bound to settings. // This must be done because the value is set when the binding is accessed from viper. Accessing from cobra would only // read the value if the flag is set explicitly by the user. - command.Flags().BoolP("export-binaries", "e", false, tr("If set built binaries will be exported to the sketch folder.")) - command.Flags().StringVar(&sourceOverrides, "source-override", "", tr("Optional. Path to a .json file that contains a set of replacements of the sketch source code.")) - command.Flag("source-override").Hidden = true + compileCommand.Flags().BoolP("export-binaries", "e", false, tr("If set built binaries will be exported to the sketch folder.")) + compileCommand.Flags().StringVar(&sourceOverrides, "source-override", "", tr("Optional. Path to a .json file that contains a set of replacements of the sketch source code.")) + compileCommand.Flag("source-override").Hidden = true - configuration.Settings.BindPFlag("sketch.always_export_binaries", command.Flags().Lookup("export-binaries")) + configuration.Settings.BindPFlag("sketch.always_export_binaries", compileCommand.Flags().Lookup("export-binaries")) - command.Flags().MarkDeprecated("build-properties", tr("please use --build-property instead.")) + compileCommand.Flags().MarkDeprecated("build-properties", tr("please use --build-property instead.")) - return command + return compileCommand } -func run(cmd *cobra.Command, args []string) { +func runCompileCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli compile`") + path := "" if len(args) > 0 { path = args[0] } - sketchPath := arguments.InitSketchPath(path) - // .pde files are still supported but deprecated, this warning urges the user to rename them - if files := sketch.CheckForPdeFiles(sketchPath); len(files) > 0 { - feedback.Error(tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")) - for _, f := range files { - feedback.Error(f) - } - } + sketchPath := arguments.InitSketchPath(path) var overrides map[string]string if sourceOverrides != "" { @@ -164,7 +152,7 @@ func run(cmd *cobra.Command, args []string) { compileRequest := &rpc.CompileRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: fqbn.String(), SketchPath: sketchPath.String(), ShowProperties: showProperties, Preprocess: preprocess, @@ -195,22 +183,12 @@ func run(cmd *cobra.Command, args []string) { } if compileError == nil && uploadAfterCompile { - var sk *sketch.Sketch - sk, err := sketch.New(sketchPath) - if err != nil { - feedback.Errorf(tr("Error during Upload: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } - var discoveryPort *discovery.Port - discoveryPort, err = port.GetPort(inst, sk) - if err != nil { - feedback.Errorf(tr("Error during Upload: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } + sk := arguments.NewSketch(sketchPath) + discoveryPort := port.GetDiscoveryPort(inst, sk) userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: fqbn.String(), Protocol: discoveryPort.Protocol, }) if err != nil { @@ -226,13 +204,13 @@ func run(cmd *cobra.Command, args []string) { uploadRequest := &rpc.UploadRequest{ Instance: inst, - Fqbn: fqbn, + Fqbn: fqbn.String(), SketchPath: sketchPath.String(), Port: discoveryPort.ToRPC(), Verbose: verbose, Verify: verify, ImportDir: buildPath, - Programmer: programmer, + Programmer: programmer.String(), UserFields: fields, } diff --git a/cli/completion/completion.go b/cli/completion/completion.go index 69d70931c47..d7f822d016e 100644 --- a/cli/completion/completion.go +++ b/cli/completion/completion.go @@ -21,6 +21,7 @@ import ( "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/i18n" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -31,7 +32,7 @@ var ( // NewCommand created a new `completion` command func NewCommand() *cobra.Command { - command := &cobra.Command{ + completionCommand := &cobra.Command{ Use: "completion [bash|zsh|fish|powershell] [--no-descriptions]", ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.ExactArgs(1), @@ -39,14 +40,15 @@ func NewCommand() *cobra.Command { Long: tr("Generates completion scripts for various shells"), Example: " " + os.Args[0] + " completion bash > completion.sh\n" + " " + "source completion.sh", - Run: run, + Run: runCompletionCommand, } - command.Flags().BoolVar(&completionNoDesc, "no-descriptions", false, tr("Disable completion description for shells that support it")) + completionCommand.Flags().BoolVar(&completionNoDesc, "no-descriptions", false, tr("Disable completion description for shells that support it")) - return command + return completionCommand } -func run(cmd *cobra.Command, args []string) { +func runCompletionCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli completion`") if completionNoDesc && (args[0] == "powershell") { feedback.Errorf(tr("Error: command description is not supported by %v"), args[0]) os.Exit(errorcodes.ErrGeneric) @@ -54,19 +56,15 @@ func run(cmd *cobra.Command, args []string) { switch args[0] { case "bash": cmd.Root().GenBashCompletionV2(os.Stdout, !completionNoDesc) - break case "zsh": if completionNoDesc { cmd.Root().GenZshCompletionNoDesc(os.Stdout) } else { cmd.Root().GenZshCompletion(os.Stdout) } - break case "fish": cmd.Root().GenFishCompletion(os.Stdout, !completionNoDesc) - break case "powershell": cmd.Root().GenPowerShellCompletion(os.Stdout) - break } } diff --git a/cli/config/add.go b/cli/config/add.go index 4f7ddbeeedb..b4ec7824483 100644 --- a/cli/config/add.go +++ b/cli/config/add.go @@ -22,6 +22,7 @@ import ( "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/configuration" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -43,12 +44,9 @@ func initAddCommand() *cobra.Command { } func runAddCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config add`") key := args[0] - kind, err := typeOf(key) - if err != nil { - feedback.Error(err) - os.Exit(errorcodes.ErrGeneric) - } + kind := validateKey(key) if kind != reflect.Slice { feedback.Errorf(tr("The key '%[1]v' is not a list of items, can't add to it.\nMaybe use '%[2]s'?"), key, "config set") diff --git a/cli/config/config.go b/cli/config/config.go index 41a03c60028..ee0e8922852 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -36,7 +36,7 @@ func NewCommand() *cobra.Command { configCommand.AddCommand(initAddCommand()) configCommand.AddCommand(initDeleteCommand()) - configCommand.AddCommand(initDumpCmd()) + configCommand.AddCommand(initDumpCommand()) configCommand.AddCommand(initInitCommand()) configCommand.AddCommand(initRemoveCommand()) configCommand.AddCommand(initSetCommand()) diff --git a/cli/config/delete.go b/cli/config/delete.go index 370cd33da9c..58a68b97ba8 100644 --- a/cli/config/delete.go +++ b/cli/config/delete.go @@ -22,12 +22,13 @@ import ( "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/configuration" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) func initDeleteCommand() *cobra.Command { - addCommand := &cobra.Command{ + deleteCommand := &cobra.Command{ Use: "delete", Short: tr("Deletes a settings key and all its sub keys."), Long: tr("Deletes a settings key and all its sub keys."), @@ -40,10 +41,11 @@ func initDeleteCommand() *cobra.Command { return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault }, } - return addCommand + return deleteCommand } func runDeleteCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config delete`") toDelete := args[0] keys := []string{} diff --git a/cli/config/dump.go b/cli/config/dump.go index a81de706bb4..19f7885c8d3 100644 --- a/cli/config/dump.go +++ b/cli/config/dump.go @@ -25,8 +25,8 @@ import ( "gopkg.in/yaml.v2" ) -func initDumpCmd() *cobra.Command { - var dumpCmd = &cobra.Command{ +func initDumpCommand() *cobra.Command { + var dumpCommand = &cobra.Command{ Use: "dump", Short: tr("Prints the current configuration"), Long: tr("Prints the current configuration."), @@ -34,7 +34,12 @@ func initDumpCmd() *cobra.Command { Args: cobra.NoArgs, Run: runDumpCommand, } - return dumpCmd + return dumpCommand +} + +func runDumpCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config dump`") + feedback.PrintResult(dumpResult{configuration.Settings.AllSettings()}) } // output from this command requires special formatting, let's create a dedicated @@ -56,8 +61,3 @@ func (dr dumpResult) String() string { return string(bs) } - -func runDumpCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino config dump`") - feedback.PrintResult(dumpResult{configuration.Settings.AllSettings()}) -} diff --git a/cli/config/init.go b/cli/config/init.go index 77ba5e77bea..59f88d72184 100644 --- a/cli/config/init.go +++ b/cli/config/init.go @@ -18,6 +18,7 @@ package config import ( "os" + "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/configuration" @@ -46,7 +47,10 @@ func initInitCommand() *cobra.Command { " " + os.Args[0] + " config init --dest-dir /home/user/MyDirectory\n" + " " + os.Args[0] + " config init --dest-file /home/user/MyDirectory/my_settings.yaml", Args: cobra.NoArgs, - Run: runInitCommand, + PreRun: func(cmd *cobra.Command, args []string) { + arguments.CheckFlagsConflicts(cmd, "dest-file", "dest-dir") + }, + Run: runInitCommand, } initCommand.Flags().StringVar(&destDir, "dest-dir", "", tr("Sets where to save the configuration file.")) initCommand.Flags().StringVar(&destFile, "dest-file", "", tr("Sets where to save the configuration file.")) @@ -55,10 +59,7 @@ func initInitCommand() *cobra.Command { } func runInitCommand(cmd *cobra.Command, args []string) { - if destFile != "" && destDir != "" { - feedback.Errorf(tr("Can't use both --dest-file and --dest-dir flags at the same time.")) - os.Exit(errorcodes.ErrGeneric) - } + logrus.Info("Executing `arduino-cli config init`") var configFileAbsPath *paths.Path var absPath *paths.Path diff --git a/cli/config/remove.go b/cli/config/remove.go index f7fa1e2bc4e..63b7a071e91 100644 --- a/cli/config/remove.go +++ b/cli/config/remove.go @@ -22,11 +22,12 @@ import ( "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/configuration" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) func initRemoveCommand() *cobra.Command { - addCommand := &cobra.Command{ + removeCommand := &cobra.Command{ Use: "remove", Short: tr("Removes one or more values from a setting."), Long: tr("Removes one or more values from a setting."), @@ -39,16 +40,13 @@ func initRemoveCommand() *cobra.Command { return GetConfigurationKeys(), cobra.ShellCompDirectiveDefault }, } - return addCommand + return removeCommand } func runRemoveCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config remove`") key := args[0] - kind, err := typeOf(key) - if err != nil { - feedback.Error(err) - os.Exit(errorcodes.ErrGeneric) - } + kind := validateKey(key) if kind != reflect.Slice { feedback.Errorf(tr("The key '%[1]v' is not a list of items, can't remove from it.\nMaybe use '%[2]s'?"), key, "config delete") diff --git a/cli/config/set.go b/cli/config/set.go index 7e849f0aabd..b4da0277336 100644 --- a/cli/config/set.go +++ b/cli/config/set.go @@ -23,11 +23,12 @@ import ( "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/configuration" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) func initSetCommand() *cobra.Command { - addCommand := &cobra.Command{ + setCommand := &cobra.Command{ Use: "set", Short: tr("Sets a setting value."), Long: tr("Sets a setting value."), @@ -42,16 +43,13 @@ func initSetCommand() *cobra.Command { return configuration.Settings.AllKeys(), cobra.ShellCompDirectiveDefault }, } - return addCommand + return setCommand } func runSetCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli config set`") key := args[0] - kind, err := typeOf(key) - if err != nil { - feedback.Error(err) - os.Exit(errorcodes.ErrGeneric) - } + kind := validateKey(key) if kind != reflect.Slice && len(args) > 2 { feedback.Errorf(tr("Can't set multiple values in key %v"), key) diff --git a/cli/config/validate.go b/cli/config/validate.go index 88a341228f3..38df07145c3 100644 --- a/cli/config/validate.go +++ b/cli/config/validate.go @@ -17,7 +17,11 @@ package config import ( "fmt" + "os" "reflect" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" ) var validMap = map[string]reflect.Kind{ @@ -46,3 +50,12 @@ func typeOf(key string) (reflect.Kind, error) { } return t, nil } + +func validateKey(key string) reflect.Kind { + kind, err := typeOf(key) + if err != nil { + feedback.Error(err) + os.Exit(errorcodes.ErrGeneric) + } + return kind +} diff --git a/cli/core/download.go b/cli/core/download.go index 30b21110241..d1a396d0dac 100644 --- a/cli/core/download.go +++ b/cli/core/download.go @@ -51,7 +51,7 @@ func initDownloadCommand() *cobra.Command { func runDownloadCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino core download`") + logrus.Info("Executing `arduino-cli core download`") platformsRefs, err := arguments.ParseReferences(args, true) if err != nil { diff --git a/cli/core/install.go b/cli/core/install.go index 44475c93ef9..6b69275aa86 100644 --- a/cli/core/install.go +++ b/cli/core/install.go @@ -26,12 +26,15 @@ import ( "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands/core" - "github.com/arduino/arduino-cli/configuration" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) +var ( + postInstallFlags arguments.PostInstallFlags +) + func initInstallCommand() *cobra.Command { installCommand := &cobra.Command{ Use: fmt.Sprintf("install %s:%s[@%s]...", tr("PACKAGER"), tr("ARCH"), tr("VERSION")), @@ -42,53 +45,21 @@ func initInstallCommand() *cobra.Command { " # " + tr("download a specific version (in this case 1.6.9).") + "\n" + " " + os.Args[0] + " core install arduino:samd@1.6.9", Args: cobra.MinimumNArgs(1), - Run: runInstallCommand, + PreRun: func(cmd *cobra.Command, args []string) { + arguments.CheckFlagsConflicts(cmd, "run-post-install", "skip-post-install") + }, + Run: runInstallCommand, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return arguments.GetInstallableCores(), cobra.ShellCompDirectiveDefault }, } - AddPostInstallFlagsToCommand(installCommand) + postInstallFlags.AddToCommand(installCommand) return installCommand } -var postInstallFlags struct { - runPostInstall bool - skipPostInstall bool -} - -// AddPostInstallFlagsToCommand adds flags that can be used to force running or skipping -// of post installation scripts -func AddPostInstallFlagsToCommand(cmd *cobra.Command) { - cmd.Flags().BoolVar(&postInstallFlags.runPostInstall, "run-post-install", false, tr("Force run of post-install scripts (if the CLI is not running interactively).")) - cmd.Flags().BoolVar(&postInstallFlags.skipPostInstall, "skip-post-install", false, tr("Force skip of post-install scripts (if the CLI is running interactively).")) -} - -// DetectSkipPostInstallValue returns true if a post install script must be run -func DetectSkipPostInstallValue() bool { - if postInstallFlags.runPostInstall && postInstallFlags.skipPostInstall { - feedback.Errorf(tr("The flags --run-post-install and --skip-post-install can't be both set at the same time.")) - os.Exit(errorcodes.ErrBadArgument) - } - if postInstallFlags.runPostInstall { - logrus.Info("Will run post-install by user request") - return false - } - if postInstallFlags.skipPostInstall { - logrus.Info("Will skip post-install by user request") - return true - } - - if !configuration.IsInteractive { - logrus.Info("Not running from console, will skip post-install by default") - return true - } - logrus.Info("Running from console, will run post-install by default") - return false -} - func runInstallCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino core install`") + logrus.Info("Executing `arduino-cli core install`") platformsRefs, err := arguments.ParseReferences(args, true) if err != nil { @@ -102,7 +73,7 @@ func runInstallCommand(cmd *cobra.Command, args []string) { PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, Version: platformRef.Version, - SkipPostInstall: DetectSkipPostInstallValue(), + SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(), } _, err := core.PlatformInstall(context.Background(), platformInstallRequest, output.ProgressBar(), output.TaskProgress()) if err != nil { diff --git a/cli/core/list.go b/cli/core/list.go index 338873d4f5e..fff41af07b0 100644 --- a/cli/core/list.go +++ b/cli/core/list.go @@ -29,6 +29,11 @@ import ( "github.com/spf13/cobra" ) +var ( + updatableOnly bool + all bool +) + func initListCommand() *cobra.Command { listCommand := &cobra.Command{ Use: "list", @@ -38,24 +43,19 @@ func initListCommand() *cobra.Command { Args: cobra.NoArgs, Run: runListCommand, } - listCommand.Flags().BoolVar(&listFlags.updatableOnly, "updatable", false, tr("List updatable platforms.")) - listCommand.Flags().BoolVar(&listFlags.all, "all", false, tr("If set return all installable and installed cores, including manually installed.")) + listCommand.Flags().BoolVar(&updatableOnly, "updatable", false, tr("List updatable platforms.")) + listCommand.Flags().BoolVar(&all, "all", false, tr("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) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino core list`") + logrus.Info("Executing `arduino-cli core list`") platforms, err := core.GetPlatforms(&rpc.PlatformListRequest{ Instance: inst, - UpdatableOnly: listFlags.updatableOnly, - All: listFlags.all, + UpdatableOnly: updatableOnly, + All: all, }) if err != nil { feedback.Errorf(tr("Error listing platforms: %v"), err) diff --git a/cli/core/search.go b/cli/core/search.go index c532aa5d38e..69881d6cdb6 100644 --- a/cli/core/search.go +++ b/cli/core/search.go @@ -82,7 +82,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) { } arguments := strings.ToLower(strings.Join(args, " ")) - logrus.Infof("Executing `arduino core search` with args: '%s'", arguments) + logrus.Infof("Executing `arduino-cli core search` with args: '%s'", arguments) resp, err := core.PlatformSearch(&rpc.PlatformSearchRequest{ Instance: inst, diff --git a/cli/core/uninstall.go b/cli/core/uninstall.go index 86ac1af5c9b..9c80536298a 100644 --- a/cli/core/uninstall.go +++ b/cli/core/uninstall.go @@ -32,7 +32,7 @@ import ( ) func initUninstallCommand() *cobra.Command { - return &cobra.Command{ + uninstallCommand := &cobra.Command{ Use: fmt.Sprintf("uninstall %s:%s ...", tr("PACKAGER"), tr("ARCH")), Short: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."), Long: tr("Uninstalls one or more cores and corresponding tool dependencies if no longer used."), @@ -43,11 +43,12 @@ func initUninstallCommand() *cobra.Command { return arguments.GetUninstallableCores(), cobra.ShellCompDirectiveDefault }, } + return uninstallCommand } func runUninstallCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino core uninstall`") + logrus.Info("Executing `arduino-cli core uninstall`") platformsRefs, err := arguments.ParseReferences(args, true) if err != nil { diff --git a/cli/core/update_index.go b/cli/core/update_index.go index c104523ef77..8e3af9b9cea 100644 --- a/cli/core/update_index.go +++ b/cli/core/update_index.go @@ -42,25 +42,8 @@ func initUpdateIndexCommand() *cobra.Command { } func runUpdateIndexCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino core update-index`") - // We don't initialize any CoreInstance when updating indexes since we don't need to. - // Also meaningless errors might be returned when calling this command with --additional-urls - // since the CLI would be searching for a corresponding file for the additional urls set - // as argument but none would be obviously found. - inst, status := instance.Create() - if status != nil { - feedback.Errorf(tr("Error creating instance: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } - - // In case this is the first time the CLI is run we need to update indexes - // to make it work correctly, we must do this explicitly in this command since - // we must use instance.Create instead of instance.CreateAndInit for the - // reason stated above. - if err := instance.FirstUpdate(inst); err != nil { - feedback.Errorf(tr("Error updating indexes: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } + inst := instance.CreateInstanceAndRunFirstUpdate() + logrus.Info("Executing `arduino-cli core update-index`") _, err := commands.UpdateIndex(context.Background(), &rpc.UpdateIndexRequest{ Instance: inst, diff --git a/cli/core/upgrade.go b/cli/core/upgrade.go index b724a289659..0401849fa9f 100644 --- a/cli/core/upgrade.go +++ b/cli/core/upgrade.go @@ -45,13 +45,13 @@ func initUpgradeCommand() *cobra.Command { " " + os.Args[0] + " core upgrade arduino:samd", Run: runUpgradeCommand, } - AddPostInstallFlagsToCommand(upgradeCommand) + postInstallFlags.AddToCommand(upgradeCommand) return upgradeCommand } func runUpgradeCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino core upgrade`") + logrus.Info("Executing `arduino-cli core upgrade`") // if no platform was passed, upgrade allthethings if len(args) == 0 { @@ -93,7 +93,7 @@ func runUpgradeCommand(cmd *cobra.Command, args []string) { Instance: inst, PlatformPackage: platformRef.PackageName, Architecture: platformRef.Architecture, - SkipPostInstall: DetectSkipPostInstallValue(), + SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(), } if _, err := core.PlatformUpgrade(context.Background(), r, output.ProgressBar(), output.TaskProgress()); err != nil { diff --git a/cli/daemon/daemon.go b/cli/daemon/daemon.go index 489c36d7edf..29de9d2e85c 100644 --- a/cli/daemon/daemon.go +++ b/cli/daemon/daemon.go @@ -41,11 +41,16 @@ import ( "google.golang.org/grpc" ) -var tr = i18n.Tr +var ( + tr = i18n.Tr + daemonize bool + debug bool + debugFilters []string +) // NewCommand created a new `daemon` command func NewCommand() *cobra.Command { - cmd := &cobra.Command{ + daemonCommand := &cobra.Command{ Use: "daemon", Short: tr("Run as a daemon on port: %s", configuration.Settings.GetString("daemon.port")), Long: tr("Running as a daemon the initialization of cores and libraries is done only once."), @@ -53,19 +58,16 @@ func NewCommand() *cobra.Command { Args: cobra.NoArgs, Run: runDaemonCommand, } - cmd.PersistentFlags().String("port", "", tr("The TCP port the daemon will listen to")) - configuration.Settings.BindPFlag("daemon.port", cmd.PersistentFlags().Lookup("port")) - cmd.Flags().BoolVar(&daemonize, "daemonize", false, tr("Do not terminate daemon process if the parent process dies")) - cmd.Flags().BoolVar(&debug, "debug", false, tr("Enable debug logging of gRPC calls")) - cmd.Flags().StringSliceVar(&debugFilters, "debug-filter", []string{}, tr("Display only the provided gRPC calls")) - return cmd + daemonCommand.PersistentFlags().String("port", "", tr("The TCP port the daemon will listen to")) + configuration.Settings.BindPFlag("daemon.port", daemonCommand.PersistentFlags().Lookup("port")) + daemonCommand.Flags().BoolVar(&daemonize, "daemonize", false, tr("Do not terminate daemon process if the parent process dies")) + daemonCommand.Flags().BoolVar(&debug, "debug", false, tr("Enable debug logging of gRPC calls")) + daemonCommand.Flags().StringSliceVar(&debugFilters, "debug-filter", []string{}, tr("Display only the provided gRPC calls")) + return daemonCommand } -var daemonize bool -var debug bool -var debugFilters []string - func runDaemonCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli daemon`") if configuration.Settings.GetBool("metrics.enabled") { metrics.Activate("daemon") diff --git a/cli/debug/debug.go b/cli/debug/debug.go index 0a2afd1c4cc..465fa0674ce 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -21,7 +21,6 @@ import ( "os/signal" "sort" - "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" @@ -32,18 +31,17 @@ import ( "github.com/arduino/arduino-cli/table" "github.com/arduino/go-properties-orderedmap" "github.com/fatih/color" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( - fqbn string + fqbn arguments.Fqbn port arguments.Port - verbose bool - verify bool interpreter string importDir string printInfo bool - programmer string + programmer arguments.Programmer tr = i18n.Tr ) @@ -55,18 +53,12 @@ func NewCommand() *cobra.Command { Long: tr("Debug Arduino sketches. (this command opens an interactive gdb session)"), Example: " " + os.Args[0] + " debug -b arduino:samd:mkr1000 -P atmel_ice /home/user/Arduino/MySketch", Args: cobra.MaximumNArgs(1), - Run: run, + Run: runDebugCommand, } - debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - debugCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) + fqbn.AddToCommand(debugCommand) port.AddToCommand(debugCommand) - debugCommand.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Programmer to use for debugging")) - debugCommand.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault - }) + 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.")) debugCommand.Flags().BoolVarP(&printInfo, "info", "I", false, tr("Show metadata about the debug session instead of starting the debugger.")) @@ -74,32 +66,27 @@ func NewCommand() *cobra.Command { return debugCommand } -func run(command *cobra.Command, args []string) { +func runDebugCommand(command *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli debug`") path := "" if len(args) > 0 { path = args[0] } + sketchPath := arguments.InitSketchPath(path) - sk, err := sketch.New(sketchPath) - if err != nil { - feedback.Errorf(tr("Error during Debug: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } - discoveryPort, err := port.GetPort(instance, sk) - if err != nil { - feedback.Errorf(tr("Error during Debug: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } + sk := arguments.NewSketch(sketchPath) + discoveryPort := port.GetDiscoveryPort(instance, sk) + debugConfigRequested := &dbg.DebugConfigRequest{ Instance: instance, - Fqbn: fqbn, + Fqbn: fqbn.String(), SketchPath: sketchPath.String(), Port: discoveryPort.ToRPC(), Interpreter: interpreter, ImportDir: importDir, - Programmer: programmer, + Programmer: programmer.String(), } if printInfo { diff --git a/cli/generatedocs/generatedocs.go b/cli/generatedocs/generatedocs.go index 41f9852ae6d..99657d6874d 100644 --- a/cli/generatedocs/generatedocs.go +++ b/cli/generatedocs/generatedocs.go @@ -31,9 +31,9 @@ var ( tr = i18n.Tr ) -// NewCommand created a new `generatedocs` command +// NewCommand created a new `generate-docs` command func NewCommand() *cobra.Command { - command := &cobra.Command{ + generateDocsCommand := &cobra.Command{ Use: "generate-docs", Short: tr("Generates bash completion and command manpages."), Long: tr("Generates bash completion and command manpages."), @@ -41,23 +41,24 @@ func NewCommand() *cobra.Command { Hidden: true, } - command.PersistentFlags().StringVarP(&outputDir, "output-dir", "o", "", + generateDocsCommand.PersistentFlags().StringVarP(&outputDir, "output-dir", "o", "", tr("Directory where to save generated files. Default is './docs', the directory must exist.")) - command.AddCommand(&cobra.Command{ + generateDocsCommand.AddCommand(&cobra.Command{ Use: "manpage", Args: cobra.NoArgs, Run: generateManPages, }) - command.AddCommand(&cobra.Command{ + generateDocsCommand.AddCommand(&cobra.Command{ Use: "bash-completions", Args: cobra.NoArgs, Run: generateBashCompletions, }) - return command + return generateDocsCommand } func generateBashCompletions(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli generate-docs`") if outputDir == "" { outputDir = "docs/bash_completions" } diff --git a/cli/instance/instance.go b/cli/instance/instance.go index 7d5bde944d7..a26feceb49a 100644 --- a/cli/instance/instance.go +++ b/cli/instance/instance.go @@ -140,3 +140,27 @@ func FirstUpdate(instance *rpc.Instance) error { return nil } + +// CreateInstanceAndRunFirstUpdate creates an instance and runs `FirstUpdate`. +// It is mandatory for all `update-index` commands to call this +func CreateInstanceAndRunFirstUpdate() *rpc.Instance { + // We don't initialize any CoreInstance when updating indexes since we don't need to. + // Also meaningless errors might be returned when calling this command with --additional-urls + // since the CLI would be searching for a corresponding file for the additional urls set + // as argument but none would be obviously found. + inst, status := Create() + if status != nil { + feedback.Errorf(tr("Error creating instance: %v"), status) + os.Exit(errorcodes.ErrGeneric) + } + + // In case this is the first time the CLI is run we need to update indexes + // to make it work correctly, we must do this explicitly in this command since + // we must use instance.Create instead of instance.CreateAndInit for the + // reason stated above. + if err := FirstUpdate(inst); err != nil { + feedback.Errorf(tr("Error updating indexes: %v"), status) + os.Exit(errorcodes.ErrGeneric) + } + return inst +} diff --git a/cli/lib/check_deps.go b/cli/lib/check_deps.go index 034bd646f48..7a420001f62 100644 --- a/cli/lib/check_deps.go +++ b/cli/lib/check_deps.go @@ -27,6 +27,7 @@ import ( "github.com/arduino/arduino-cli/commands/lib" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/fatih/color" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -49,6 +50,7 @@ func initDepsCommand() *cobra.Command { func runDepsCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli lib deps`") libRef, err := ParseLibraryReferenceArgAndAdjustCase(instance, args[0]) if err != nil { feedback.Errorf(tr("Arguments error: %v"), err) diff --git a/cli/lib/download.go b/cli/lib/download.go index f76e6a77686..c2ad41638f5 100644 --- a/cli/lib/download.go +++ b/cli/lib/download.go @@ -27,6 +27,7 @@ import ( "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands/lib" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -49,6 +50,7 @@ func initDownloadCommand() *cobra.Command { func runDownloadCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli lib download`") refs, err := ParseLibraryReferenceArgsAndAdjustCase(instance, args) if err != nil { feedback.Errorf(tr("Invalid argument passed: %v"), err) diff --git a/cli/lib/examples.go b/cli/lib/examples.go index 482ada066a3..5e60728a825 100644 --- a/cli/lib/examples.go +++ b/cli/lib/examples.go @@ -34,6 +34,10 @@ import ( "github.com/spf13/cobra" ) +var ( + fqbn arguments.Fqbn +) + func initExamplesCommand() *cobra.Command { examplesCommand := &cobra.Command{ Use: fmt.Sprintf("examples [%s]", tr("LIBRARY_NAME")), @@ -46,20 +50,13 @@ func initExamplesCommand() *cobra.Command { return arguments.GetInstalledLibraries(), cobra.ShellCompDirectiveDefault }, } - examplesCommand.Flags().StringVarP(&examplesFlags.fqbn, "fqbn", "b", "", tr("Show libraries for the specified board FQBN.")) - examplesCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) + fqbn.AddToCommand(examplesCommand) return examplesCommand } -var examplesFlags struct { - fqbn string -} - func runExamplesCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() - logrus.Info("Show examples for library") + logrus.Info("Executing `arduino-cli lib examples`") name := "" if len(args) > 0 { @@ -70,7 +67,7 @@ func runExamplesCommand(cmd *cobra.Command, args []string) { Instance: instance, All: true, Name: name, - Fqbn: examplesFlags.fqbn, + Fqbn: fqbn.String(), }) if err != nil { feedback.Errorf(tr("Error getting libraries info: %v"), err) diff --git a/cli/lib/install.go b/cli/lib/install.go index 5f1865bed42..616a00d2751 100644 --- a/cli/lib/install.go +++ b/cli/lib/install.go @@ -31,10 +31,17 @@ import ( "github.com/arduino/arduino-cli/configuration" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/go-paths-helper" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" semver "go.bug.st/relaxed-semver" ) +var ( + noDeps bool + gitURL bool + zipPath bool +) + func initInstallCommand() *cobra.Command { installCommand := &cobra.Command{ Use: fmt.Sprintf("install %s[@%s]...", tr("LIBRARY"), tr("VERSION_NUMBER")), @@ -51,22 +58,17 @@ func initInstallCommand() *cobra.Command { return arguments.GetInstallableLibs(), cobra.ShellCompDirectiveDefault }, } - installCommand.Flags().BoolVar(&installFlags.noDeps, "no-deps", false, tr("Do not install dependencies.")) - installCommand.Flags().BoolVar(&installFlags.gitURL, "git-url", false, tr("Enter git url for libraries hosted on repositories")) - installCommand.Flags().BoolVar(&installFlags.zipPath, "zip-path", false, tr("Enter a path to zip file")) + installCommand.Flags().BoolVar(&noDeps, "no-deps", false, tr("Do not install dependencies.")) + installCommand.Flags().BoolVar(&gitURL, "git-url", false, tr("Enter git url for libraries hosted on repositories")) + installCommand.Flags().BoolVar(&zipPath, "zip-path", false, tr("Enter a path to zip file")) return installCommand } -var installFlags struct { - noDeps bool - gitURL bool - zipPath bool -} - func runInstallCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli lib install`") - if installFlags.zipPath || installFlags.gitURL { + if zipPath || gitURL { if !configuration.Settings.GetBool("library.enable_unsafe_install") { documentationURL := "https://arduino.github.io/arduino-cli/latest/configuration/#configuration-keys" _, err := semver.Parse(globals.VersionInfo.VersionString) @@ -80,7 +82,7 @@ func runInstallCommand(cmd *cobra.Command, args []string) { feedback.Print(tr("--git-url and --zip-path flags allow installing untrusted files, use it at your own risk.")) } - if installFlags.zipPath { + if zipPath { for _, path := range args { err := lib.ZipLibraryInstall(context.Background(), &rpc.ZipLibraryInstallRequest{ Instance: instance, @@ -95,7 +97,7 @@ func runInstallCommand(cmd *cobra.Command, args []string) { return } - if installFlags.gitURL { + if gitURL { for _, url := range args { if url == "." { wd, err := paths.Getwd() @@ -129,7 +131,7 @@ func runInstallCommand(cmd *cobra.Command, args []string) { Instance: instance, Name: libRef.Name, Version: libRef.Version, - NoDeps: installFlags.noDeps, + NoDeps: noDeps, } err := lib.LibraryInstall(context.Background(), libraryInstallRequest, output.ProgressBar(), output.TaskProgress()) if err != nil { diff --git a/cli/lib/list.go b/cli/lib/list.go index eb573acc221..496b948cda7 100644 --- a/cli/lib/list.go +++ b/cli/lib/list.go @@ -32,6 +32,11 @@ import ( "github.com/spf13/cobra" ) +var ( + all bool + updatable bool +) + func initListCommand() *cobra.Command { listCommand := &cobra.Command{ Use: fmt.Sprintf("list [%s]", tr("LIBNAME")), @@ -45,21 +50,15 @@ not listed, they can be listed by adding the --all flag.`), Args: cobra.MaximumNArgs(1), Run: runListCommand, } - listCommand.Flags().BoolVar(&listFlags.all, "all", false, tr("Include built-in libraries (from platforms and IDE) in listing.")) - listCommand.Flags().StringVarP(&listFlags.fqbn, "fqbn", "b", "", tr("Show libraries for the specified board FQBN.")) - listCommand.Flags().BoolVar(&listFlags.updatable, "updatable", false, tr("List updatable libraries.")) + listCommand.Flags().BoolVar(&all, "all", false, tr("Include built-in libraries (from platforms and IDE) in listing.")) + fqbn.AddToCommand(listCommand) + listCommand.Flags().BoolVar(&updatable, "updatable", false, tr("List updatable libraries.")) return listCommand } -var listFlags struct { - all bool - updatable bool - fqbn string -} - func runListCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() - logrus.Info("Listing") + logrus.Info("Executing `arduino-cli lib list`") name := "" if len(args) > 0 { @@ -68,10 +67,10 @@ func runListCommand(cmd *cobra.Command, args []string) { res, err := lib.LibraryList(context.Background(), &rpc.LibraryListRequest{ Instance: instance, - All: listFlags.all, - Updatable: listFlags.updatable, + All: all, + Updatable: updatable, Name: name, - Fqbn: listFlags.fqbn, + Fqbn: fqbn.String(), }) if err != nil { feedback.Errorf(tr("Error listing Libraries: %v"), err) @@ -79,11 +78,11 @@ func runListCommand(cmd *cobra.Command, args []string) { } libs := []*rpc.InstalledLibrary{} - if listFlags.fqbn == "" { + if fqbn.String() == "" { libs = res.GetInstalledLibraries() } else { for _, lib := range res.GetInstalledLibraries() { - if lib.Library.CompatibleWith[listFlags.fqbn] { + if lib.Library.CompatibleWith[fqbn.String()] { libs = append(libs, lib) } } @@ -111,7 +110,7 @@ func (ir installedResult) Data() interface{} { func (ir installedResult) String() string { if ir.installedLibs == nil || len(ir.installedLibs) == 0 { - if listFlags.updatable { + if updatable { return tr("No updates available.") } return tr("No libraries installed.") diff --git a/cli/lib/search.go b/cli/lib/search.go index 5e86e9e9ed9..2abd34906f6 100644 --- a/cli/lib/search.go +++ b/cli/lib/search.go @@ -34,6 +34,10 @@ import ( semver "go.bug.st/relaxed-semver" ) +var ( + namesOnly bool // if true outputs lib names only. +) + func initSearchCommand() *cobra.Command { searchCommand := &cobra.Command{ Use: fmt.Sprintf("search [%s]", tr("LIBRARY_NAME")), @@ -43,16 +47,14 @@ func initSearchCommand() *cobra.Command { Args: cobra.ArbitraryArgs, Run: runSearchCommand, } - searchCommand.Flags().BoolVar(&searchFlags.namesOnly, "names", false, tr("Show library names only.")) + searchCommand.Flags().BoolVar(&namesOnly, "names", false, tr("Show library names only.")) return searchCommand } -var searchFlags struct { - namesOnly bool // if true outputs lib names only. -} - func runSearchCommand(cmd *cobra.Command, args []string) { inst, status := instance.Create() + logrus.Info("Executing `arduino-cli lib search`") + if status != nil { feedback.Errorf(tr("Error creating instance: %v"), status) os.Exit(errorcodes.ErrGeneric) @@ -71,7 +73,6 @@ func runSearchCommand(cmd *cobra.Command, args []string) { feedback.Errorf(tr("Error initializing instance: %v"), err) } - logrus.Info("Executing `arduino lib search`") searchResp, err := lib.LibrarySearch(context.Background(), &rpc.LibrarySearchRequest{ Instance: inst, Query: (strings.Join(args, " ")), @@ -83,7 +84,7 @@ func runSearchCommand(cmd *cobra.Command, args []string) { feedback.PrintResult(result{ results: searchResp, - namesOnly: searchFlags.namesOnly, + namesOnly: namesOnly, }) logrus.Info("Done") diff --git a/cli/lib/uninstall.go b/cli/lib/uninstall.go index a520091f0c1..2f7c20ef3bd 100644 --- a/cli/lib/uninstall.go +++ b/cli/lib/uninstall.go @@ -47,9 +47,9 @@ func initUninstallCommand() *cobra.Command { } func runUninstallCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino lib uninstall`") - instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli lib uninstall`") + refs, err := ParseLibraryReferenceArgsAndAdjustCase(instance, args) if err != nil { feedback.Errorf(tr("Invalid argument passed: %v"), err) diff --git a/cli/lib/update_index.go b/cli/lib/update_index.go index e5df0a3213a..713f8e89010 100644 --- a/cli/lib/update_index.go +++ b/cli/lib/update_index.go @@ -25,43 +25,31 @@ import ( "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) func initUpdateIndexCommand() *cobra.Command { - return &cobra.Command{ + updateIndexCommand := &cobra.Command{ Use: "update-index", Short: tr("Updates the libraries index."), Long: tr("Updates the libraries index to the latest version."), Example: " " + os.Args[0] + " lib update-index", Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, args []string) { - // We don't initialize any CoreInstance when updating indexes since we don't need to. - // Also meaningless errors might be returned when calling this command with --additional-urls - // since the CLI would be searching for a corresponding file for the additional urls set - // as argument but none would be obviously found. - inst, status := instance.Create() - if status != nil { - feedback.Errorf(tr("Error creating instance: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } + Run: runUpdateIndexCommand, + } + return updateIndexCommand +} - // In case this is the first time the CLI is run we need to update indexes - // to make it work correctly, we must do this explicitly in this command since - // we must use instance.Create instead of instance.CreateAndInit for the - // reason stated above. - if err := instance.FirstUpdate(inst); err != nil { - feedback.Errorf(tr("Error updating indexes: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } +func runUpdateIndexCommand(cmd *cobra.Command, args []string) { + inst := instance.CreateInstanceAndRunFirstUpdate() + logrus.Info("Executing `arduino-cli lib update-index`") - err := commands.UpdateLibrariesIndex(context.Background(), &rpc.UpdateLibrariesIndexRequest{ - Instance: inst, - }, output.ProgressBar()) - if err != nil { - feedback.Errorf(tr("Error updating library index: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } - }, + err := commands.UpdateLibrariesIndex(context.Background(), &rpc.UpdateLibrariesIndexRequest{ + Instance: inst, + }, output.ProgressBar()) + if err != nil { + feedback.Errorf(tr("Error updating library index: %v"), err) + os.Exit(errorcodes.ErrGeneric) } } diff --git a/cli/lib/upgrade.go b/cli/lib/upgrade.go index c1f417f62b8..11f071b8550 100644 --- a/cli/lib/upgrade.go +++ b/cli/lib/upgrade.go @@ -28,7 +28,7 @@ import ( ) func initUpgradeCommand() *cobra.Command { - listCommand := &cobra.Command{ + upgradeCommand := &cobra.Command{ Use: "upgrade", Short: tr("Upgrades installed libraries."), Long: tr("This command upgrades an installed library to the latest available version. Multiple libraries can be passed separated by a space. If no arguments are provided, the command will upgrade all the installed libraries where an update is available."), @@ -38,11 +38,12 @@ func initUpgradeCommand() *cobra.Command { Args: cobra.ArbitraryArgs, Run: runUpgradeCommand, } - return listCommand + return upgradeCommand } func runUpgradeCommand(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli lib upgrade`") if len(args) == 0 { err := lib.LibraryUpgradeAll(instance.Id, output.ProgressBar(), output.TaskProgress()) diff --git a/cli/monitor/monitor.go b/cli/monitor/monitor.go index b6639223260..ce0d5937525 100644 --- a/cli/monitor/monitor.go +++ b/cli/monitor/monitor.go @@ -34,20 +34,22 @@ import ( rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" "github.com/arduino/arduino-cli/table" "github.com/fatih/color" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) -var tr = i18n.Tr - -var portArgs arguments.Port -var describe bool -var configs []string -var quiet bool -var fqbn string +var ( + portArgs arguments.Port + describe bool + configs []string + quiet bool + fqbn arguments.Fqbn + tr = i18n.Tr +) // NewCommand created a new `monitor` command func NewCommand() *cobra.Command { - cmd := &cobra.Command{ + monitorCommand := &cobra.Command{ Use: "monitor", Short: tr("Open a communication port with a board."), Long: tr("Open a communication port with a board."), @@ -56,20 +58,18 @@ func NewCommand() *cobra.Command { " " + os.Args[0] + " monitor -p /dev/ttyACM0 --describe", Run: runMonitorCmd, } - portArgs.AddToCommand(cmd) - cmd.Flags().BoolVar(&describe, "describe", false, tr("Show all the settings of the communication port.")) - cmd.Flags().StringSliceVarP(&configs, "config", "c", []string{}, tr("Configuration of the port.")) - cmd.Flags().BoolVarP(&quiet, "quiet", "q", false, tr("Run in silent mode, show only monitor input and output.")) - cmd.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - cmd.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) - cmd.MarkFlagRequired("port") - return cmd + portArgs.AddToCommand(monitorCommand) + monitorCommand.Flags().BoolVar(&describe, "describe", false, tr("Show all the settings of the communication port.")) + monitorCommand.Flags().StringSliceVarP(&configs, "config", "c", []string{}, tr("Configuration of the port.")) + monitorCommand.Flags().BoolVarP(&quiet, "quiet", "q", false, tr("Run in silent mode, show only monitor input and output.")) + fqbn.AddToCommand(monitorCommand) + monitorCommand.MarkFlagRequired("port") + return monitorCommand } func runMonitorCmd(cmd *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli monitor`") if !configuration.HasConsole { quiet = true @@ -84,7 +84,7 @@ func runMonitorCmd(cmd *cobra.Command, args []string) { enumerateResp, err := monitor.EnumerateMonitorPortSettings(context.Background(), &rpc.EnumerateMonitorPortSettingsRequest{ Instance: instance, PortProtocol: portProtocol, - Fqbn: fqbn, + Fqbn: fqbn.String(), }) if err != nil { feedback.Error(tr("Error getting port settings details: %s", err)) @@ -148,7 +148,7 @@ func runMonitorCmd(cmd *cobra.Command, args []string) { portProxy, _, err := monitor.Monitor(context.Background(), &rpc.MonitorRequest{ Instance: instance, Port: &rpc.Port{Address: portAddress, Protocol: portProtocol}, - Fqbn: fqbn, + Fqbn: fqbn.String(), PortConfiguration: configuration, }) if err != nil { diff --git a/cli/outdated/outdated.go b/cli/outdated/outdated.go index b39fb9bdf7b..b53ceea3909 100644 --- a/cli/outdated/outdated.go +++ b/cli/outdated/outdated.go @@ -48,7 +48,7 @@ that can be upgraded. If nothing needs to be updated the output is empty.`), func runOutdatedCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino outdated`") + logrus.Info("Executing `arduino-cli outdated`") outdatedResp, err := commands.Outdated(context.Background(), &rpc.OutdatedRequest{ Instance: inst, diff --git a/cli/sketch/archive.go b/cli/sketch/archive.go index 391cd55abb1..66bd9107275 100644 --- a/cli/sketch/archive.go +++ b/cli/sketch/archive.go @@ -20,7 +20,7 @@ import ( "fmt" "os" - "github.com/arduino/arduino-cli/arduino/sketch" + "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" sk "github.com/arduino/arduino-cli/commands/sketch" @@ -34,7 +34,7 @@ var includeBuildDir bool // initArchiveCommand creates a new `archive` command func initArchiveCommand() *cobra.Command { - command := &cobra.Command{ + archiveCommand := &cobra.Command{ Use: fmt.Sprintf("archive <%s> <%s>", tr("sketchPath"), tr("archivePath")), Short: tr("Creates a zip file containing all sketch files."), Long: tr("Creates a zip file containing all sketch files."), @@ -48,26 +48,20 @@ func initArchiveCommand() *cobra.Command { Run: runArchiveCommand, } - command.Flags().BoolVar(&includeBuildDir, "include-build-dir", false, tr("Includes %s directory in the archive.", "build")) + archiveCommand.Flags().BoolVar(&includeBuildDir, "include-build-dir", false, tr("Includes %s directory in the archive.", "build")) - return command + return archiveCommand } func runArchiveCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino sketch archive`") + logrus.Info("Executing `arduino-cli sketch archive`") sketchPath := paths.New(".") if len(args) >= 1 { sketchPath = paths.New(args[0]) } - // .pde files are still supported but deprecated, this warning urges the user to rename them - if files := sketch.CheckForPdeFiles(sketchPath); len(files) > 0 { - feedback.Error(tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")) - for _, f := range files { - feedback.Error(f) - } - } + arguments.WarnDeprecatedFiles(sketchPath) archivePath := "" if len(args) == 2 { diff --git a/cli/sketch/new.go b/cli/sketch/new.go index 90afe67a206..b3a131acf04 100644 --- a/cli/sketch/new.go +++ b/cli/sketch/new.go @@ -26,6 +26,7 @@ import ( sk "github.com/arduino/arduino-cli/commands/sketch" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" paths "github.com/arduino/go-paths-helper" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -42,6 +43,7 @@ func initNewCommand() *cobra.Command { } func runNewCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli sketch new`") // Trim to avoid issues if user creates a sketch adding the .ino extesion to the name sketchName := args[0] trimmedSketchName := strings.TrimSuffix(sketchName, globals.MainFileValidExtension) diff --git a/cli/sketch/sketch.go b/cli/sketch/sketch.go index 2155ae16af1..fa172d3148e 100644 --- a/cli/sketch/sketch.go +++ b/cli/sketch/sketch.go @@ -26,15 +26,15 @@ var tr = i18n.Tr // NewCommand created a new `sketch` command func NewCommand() *cobra.Command { - cmd := &cobra.Command{ + sketchCommand := &cobra.Command{ Use: "sketch", Short: tr("Arduino CLI sketch commands."), Long: tr("Arduino CLI sketch commands."), Example: " " + os.Args[0] + " sketch new MySketch", } - cmd.AddCommand(initNewCommand()) - cmd.AddCommand(initArchiveCommand()) + sketchCommand.AddCommand(initNewCommand()) + sketchCommand.AddCommand(initArchiveCommand()) - return cmd + return sketchCommand } diff --git a/cli/update/update.go b/cli/update/update.go index ba7e1b876ff..8ce69ae75d7 100644 --- a/cli/update/update.go +++ b/cli/update/update.go @@ -52,25 +52,8 @@ var updateFlags struct { } func runUpdateCommand(cmd *cobra.Command, args []string) { - logrus.Info("Executing `arduino update`") - // We don't initialize any CoreInstance when updating indexes since we don't need to. - // Also meaningless errors might be returned when calling this command with --additional-urls - // since the CLI would be searching for a corresponding file for the additional urls set - // as argument but none would be obviously found. - inst, status := instance.Create() - if status != nil { - feedback.Errorf(tr("Error creating instance: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } - - // In case this is the first time the CLI is run we need to update indexes - // to make it work correctly, we must do this explicitly in this command since - // we must use instance.Create instead of instance.CreateAndInit for the - // reason stated above. - if err := instance.FirstUpdate(inst); err != nil { - feedback.Errorf(tr("Error updating indexes: %v"), status) - os.Exit(errorcodes.ErrGeneric) - } + inst := instance.CreateInstanceAndRunFirstUpdate() + logrus.Info("Executing `arduino-cli update`") err := commands.UpdateCoreLibrariesIndex(context.Background(), &rpc.UpdateCoreLibrariesIndexRequest{ Instance: inst, diff --git a/cli/upgrade/upgrade.go b/cli/upgrade/upgrade.go index b6920169167..5134774dbb4 100644 --- a/cli/upgrade/upgrade.go +++ b/cli/upgrade/upgrade.go @@ -19,7 +19,7 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/cli/core" + "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/cli/output" @@ -30,7 +30,10 @@ import ( "github.com/spf13/cobra" ) -var tr = i18n.Tr +var ( + tr = i18n.Tr + postInstallFlags arguments.PostInstallFlags +) // NewCommand creates a new `upgrade` command func NewCommand() *cobra.Command { @@ -43,17 +46,17 @@ func NewCommand() *cobra.Command { Run: runUpgradeCommand, } - core.AddPostInstallFlagsToCommand(upgradeCommand) + postInstallFlags.AddToCommand(upgradeCommand) return upgradeCommand } func runUpgradeCommand(cmd *cobra.Command, args []string) { inst := instance.CreateAndInit() - logrus.Info("Executing `arduino upgrade`") + logrus.Info("Executing `arduino-cli upgrade`") err := commands.Upgrade(context.Background(), &rpc.UpgradeRequest{ Instance: inst, - SkipPostInstall: core.DetectSkipPostInstallValue(), + SkipPostInstall: postInstallFlags.DetectSkipPostInstallValue(), }, output.NewDownloadProgressBarCB(), output.TaskProgress()) if err != nil { diff --git a/cli/upload/upload.go b/cli/upload/upload.go index 6fe40ab15f3..670f0847a5e 100644 --- a/cli/upload/upload.go +++ b/cli/upload/upload.go @@ -19,7 +19,6 @@ import ( "context" "os" - "github.com/arduino/arduino-cli/arduino/sketch" "github.com/arduino/arduino-cli/cli/arguments" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" @@ -27,17 +26,18 @@ import ( "github.com/arduino/arduino-cli/commands/upload" "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( - fqbn string + fqbn arguments.Fqbn port arguments.Port verbose bool verify bool importDir string importFile string - programmer string + programmer arguments.Programmer dryRun bool tr = i18n.Tr ) @@ -50,73 +50,46 @@ func NewCommand() *cobra.Command { Long: tr("Upload Arduino sketches. This does NOT compile the sketch prior to upload."), Example: " " + os.Args[0] + " upload /home/user/Arduino/MySketch", Args: cobra.MaximumNArgs(1), - PreRun: checkFlagsConflicts, - Run: run, + PreRun: func(cmd *cobra.Command, args []string) { + arguments.CheckFlagsConflicts(cmd, "input-file", "input-dir") + }, + Run: runUploadCommand, } - uploadCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", tr("Fully Qualified Board Name, e.g.: arduino:avr:uno")) - uploadCommand.RegisterFlagCompletionFunc("fqbn", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledBoards(), cobra.ShellCompDirectiveDefault - }) + fqbn.AddToCommand(uploadCommand) port.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.")) uploadCommand.Flags().BoolVarP(&verbose, "verbose", "v", false, tr("Optional, turns on verbose mode.")) - uploadCommand.Flags().StringVarP(&programmer, "programmer", "P", "", tr("Optional, use the specified programmer to upload.")) - uploadCommand.RegisterFlagCompletionFunc("programmer", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return arguments.GetInstalledProgrammers(), cobra.ShellCompDirectiveDefault - }) + programmer.AddToCommand(uploadCommand) uploadCommand.Flags().BoolVar(&dryRun, "dry-run", false, tr("Do not perform the actual upload, just log out actions")) uploadCommand.Flags().MarkHidden("dry-run") return uploadCommand } -func checkFlagsConflicts(command *cobra.Command, args []string) { - if importFile != "" && importDir != "" { - feedback.Errorf(tr("error: %s and %s flags cannot be used together", "--input-file", "--input-dir")) - os.Exit(errorcodes.ErrBadArgument) - } -} - -func run(command *cobra.Command, args []string) { +func runUploadCommand(command *cobra.Command, args []string) { instance := instance.CreateAndInit() + logrus.Info("Executing `arduino-cli upload`") path := "" if len(args) > 0 { path = args[0] } - sketchPath := arguments.InitSketchPath(path) - - // .pde files are still supported but deprecated, this warning urges the user to rename them - if files := sketch.CheckForPdeFiles(sketchPath); len(files) > 0 && importDir == "" && importFile == "" { - feedback.Error(tr("Sketches with .pde extension are deprecated, please rename the following files to .ino:")) - for _, f := range files { - feedback.Error(f) - } - } - sk, err := sketch.New(sketchPath) - if err != nil && importDir == "" && importFile == "" { - feedback.Errorf(tr("Error during Upload: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } - - discoveryPort, err := port.GetPort(instance, sk) - if err != nil { - feedback.Errorf(tr("Error during Upload: %v"), err) - os.Exit(errorcodes.ErrGeneric) - } + sketchPath := arguments.InitSketchPath(path) + sk := arguments.NewSketch(sketchPath) + discoveryPort := port.GetDiscoveryPort(instance, sk) - if fqbn == "" && sk != nil && sk.Metadata != nil { + if fqbn.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 = sk.Metadata.CPU.Fqbn + fqbn.Set(sk.Metadata.CPU.Fqbn) } userFieldRes, err := upload.SupportedUserFields(context.Background(), &rpc.SupportedUserFieldsRequest{ Instance: instance, - Fqbn: fqbn, + Fqbn: fqbn.String(), Protocol: discoveryPort.Protocol, }) if err != nil { @@ -136,14 +109,14 @@ func run(command *cobra.Command, args []string) { if _, err := upload.Upload(context.Background(), &rpc.UploadRequest{ Instance: instance, - Fqbn: fqbn, + Fqbn: fqbn.String(), SketchPath: path, Port: discoveryPort.ToRPC(), Verbose: verbose, Verify: verify, ImportFile: importFile, ImportDir: importDir, - Programmer: programmer, + Programmer: programmer.String(), DryRun: dryRun, UserFields: fields, }, os.Stdout, os.Stderr); err != nil { diff --git a/cli/version/version.go b/cli/version/version.go index 045b2bab325..4114bfff235 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -24,6 +24,7 @@ import ( "github.com/arduino/arduino-cli/cli/globals" "github.com/arduino/arduino-cli/cli/updater" "github.com/arduino/arduino-cli/i18n" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" semver "go.bug.st/relaxed-semver" ) @@ -32,17 +33,19 @@ var tr = i18n.Tr // NewCommand created a new `version` command func NewCommand() *cobra.Command { - return &cobra.Command{ + versionCommand := &cobra.Command{ Use: "version", Short: tr("Shows version number of Arduino CLI."), Long: tr("Shows the version number of Arduino CLI which is installed on your system."), Example: " " + os.Args[0] + " version", Args: cobra.NoArgs, - Run: run, + Run: runVersionCommand, } + return versionCommand } -func run(cmd *cobra.Command, args []string) { +func runVersionCommand(cmd *cobra.Command, args []string) { + logrus.Info("Executing `arduino-cli version`") if strings.Contains(globals.VersionInfo.VersionString, "git-snapshot") || strings.Contains(globals.VersionInfo.VersionString, "nightly") { // We're using a development version, no need to check if there's a // new release available diff --git a/commands/lib/download.go b/commands/lib/download.go index 4d0601d26fb..acbebe55adc 100644 --- a/commands/lib/download.go +++ b/commands/lib/download.go @@ -31,7 +31,7 @@ var tr = i18n.Tr // LibraryDownload FIXMEDOC func LibraryDownload(ctx context.Context, req *rpc.LibraryDownloadRequest, downloadCB commands.DownloadProgressCB) (*rpc.LibraryDownloadResponse, error) { - logrus.Info("Executing `arduino lib download`") + logrus.Info("Executing `arduino-cli lib download`") lm := commands.GetLibraryManager(req.GetInstance().GetId()) if lm == nil { diff --git a/docs/UPGRADING.md b/docs/UPGRADING.md index ba1027b4c30..753ebf6a52c 100644 --- a/docs/UPGRADING.md +++ b/docs/UPGRADING.md @@ -2,6 +2,25 @@ Here you can find a list of migration guides to handle breaking changes between releases of the CLI. +## Unreleased + +### `board details` arguments change + +The `board details` command now accepts only the `--fqbn` or `-b` flags to specify the FQBN. + +The previously deprecated `board details ` syntax is no longer supported. + +### `board attach` arguments change + +The `board attach` command now uses `--port` and `-p` flags to set board port and `--board` and `-b` flags to select its +FQBN. + +The previous syntax `board attach | [sketchPath]` is no longer supported. + +### `--timeout` flag in `board list` command has been replaced by `--discovery-timeout` + +The flag `--timeout` in the `board list` command is no longer supported. + ## 0.19.0 ### `board list` command JSON output change diff --git a/test/test_board.py b/test/test_board.py index b283646eb32..3af37c3aa8a 100644 --- a/test/test_board.py +++ b/test/test_board.py @@ -502,37 +502,13 @@ def test_board_details(run_command): assert result["debugging_supported"] is True -# old `arduino-cli board details` did not need -b flag to work -def test_board_details_old(run_command): - run_command(["core", "update-index"]) - # Download samd core pinned to 1.8.6 - run_command(["core", "install", "arduino:samd@1.8.6"]) - result = run_command(["board", "details", "arduino:samd:nano_33_iot", "--format", "json"]) - assert result.ok - # Sort everything before compare - result = json.loads(result.stdout) - gold_board_details = json.loads(gold_board) - - assert result["fqbn"] == gold_board_details["fqbn"] - assert result["name"] == gold_board_details["name"] - assert result["version"] == gold_board_details["version"] - assert result["properties_id"] == gold_board_details["properties_id"] - assert result["official"] == gold_board_details["official"] - assert result["package"] == gold_board_details["package"] - assert result["platform"] == gold_board_details["platform"] - for usb_id in gold_board_details["identification_properties"]: - assert usb_id in result["identification_properties"] - for programmer in gold_board_details["programmers"]: - assert programmer in result["programmers"] - - def test_board_details_no_flags(run_command): run_command(["core", "update-index"]) # Download samd core pinned to 1.8.6 run_command(["core", "install", "arduino:samd@1.8.6"]) result = run_command(["board", "details"]) assert not result.ok - assert "Error getting board details: Invalid FQBN:" in result.stderr + assert 'Error: required flag(s) "fqbn" not set' in result.stderr assert result.stdout == "" @@ -661,7 +637,7 @@ def test_board_attach_without_sketch_json(run_command, data_dir): # Create a test sketch assert run_command(["sketch", "new", sketch_path]) - assert run_command(["board", "attach", fqbn, sketch_path]) + assert run_command(["board", "attach", "-b", fqbn, sketch_path]) def test_board_search_with_outdated_core(run_command): diff --git a/test/test_config.py b/test/test_config.py index 8d0cb3e2d51..ab49ac5caeb 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -144,7 +144,7 @@ def test_init_dest_flag_with_overwrite_flag(run_command, working_dir): def test_init_dest_and_config_file_flags(run_command, working_dir): result = run_command(["config", "init", "--dest-file", "some_other_path", "--dest-dir", "some_path"]) assert result.failed - assert "Can't use both --dest-file and --dest-dir flags at the same time." in result.stderr + assert "Can't use --dest-file and --dest-dir flags at the same time." in result.stderr def test_init_config_file_flag_absolute_path(run_command, working_dir):