From b12567acaed2f84b749563c4f64393bb26d41efb Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Thu, 14 Apr 2022 23:03:13 +0200 Subject: [PATCH] Refactor cli package --- cli/cli.go | 39 ++++++++++++++----------- cli/credentials/find.go | 13 ++++++--- cli/credentials/init.go | 58 ++++++++++++++++++------------------- cli/dashboard/create.go | 35 ++++++++++++---------- cli/dashboard/delete.go | 26 ++++++++++------- cli/dashboard/extract.go | 27 ++++++++++------- cli/dashboard/list.go | 33 ++++++++++++--------- cli/device/create.go | 37 +++++++++++++---------- cli/device/creategeneric.go | 29 +++++++++++-------- cli/device/createlora.go | 41 ++++++++++++++------------ cli/device/delete.go | 32 +++++++++++--------- cli/device/list.go | 24 +++++++++------ cli/device/listfqbn.go | 13 ++++++--- cli/device/listfrequency.go | 17 +++++++---- cli/device/tag/create.go | 33 ++++++++++++--------- cli/device/tag/delete.go | 32 +++++++++++--------- cli/ota/massupload.go | 45 ++++++++++++++-------------- cli/ota/upload.go | 36 +++++++++++++---------- cli/thing/bind.go | 33 ++++++++++++--------- cli/thing/clone.go | 29 +++++++++++-------- cli/thing/create.go | 31 +++++++++++--------- cli/thing/delete.go | 32 +++++++++++--------- cli/thing/extract.go | 27 ++++++++++------- cli/thing/list.go | 55 ++++++++++++++++++++--------------- cli/thing/tag/create.go | 30 +++++++++++-------- cli/thing/tag/delete.go | 32 +++++++++++--------- 26 files changed, 483 insertions(+), 356 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index a4a6ff92..9f1e4899 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -35,18 +35,29 @@ import ( "github.com/spf13/cobra" ) -var cliFlags struct { +type cliFlags struct { verbose bool outputFormat string } func Execute() { + flags := &cliFlags{} cli := &cobra.Command{ - Use: "arduino-cloud-cli", - Short: "Arduino Cloud CLI.", - Long: "Arduino Cloud Command Line Interface (arduino-cloud-cli).", - PersistentPreRun: preRun, + Use: "arduino-cloud-cli", + Short: "Arduino Cloud CLI.", + Long: "Arduino Cloud Command Line Interface (arduino-cloud-cli).", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + if err := preRun(flags); err != nil { + feedback.Error(err) + os.Exit(errorcodes.ErrBadCall) + } + }, } + cli.PersistentFlags().BoolVarP(&flags.verbose, "verbose", "v", false, "Print the logs on the standard output.") + validOutputFormats := []string{"text", "json", "jsonmini", "yaml"} + cli.PersistentFlags().StringVar(&flags.outputFormat, "format", "text", + fmt.Sprintf("The output format, can be: %s", strings.Join(validOutputFormats, ", ")), + ) cli.AddCommand(version.NewCommand()) cli.AddCommand(credentials.NewCommand()) @@ -55,12 +66,6 @@ func Execute() { cli.AddCommand(dashboard.NewCommand()) cli.AddCommand(ota.NewCommand()) - cli.PersistentFlags().BoolVarP(&cliFlags.verbose, "verbose", "v", false, "Print the logs on the standard output.") - validOutputFormats := []string{"text", "json", "jsonmini", "yaml"} - cli.PersistentFlags().StringVar(&cliFlags.outputFormat, "format", "text", - fmt.Sprintf("The output format, can be: %s", strings.Join(validOutputFormats, ", ")), - ) - if err := cli.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) } @@ -77,22 +82,22 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) { return f, found } -func preRun(cmd *cobra.Command, args []string) { +func preRun(flags *cliFlags) error { logrus.SetOutput(ioutil.Discard) // enable log only if verbose flag is passed - if cliFlags.verbose { + if flags.verbose { logrus.SetLevel(logrus.InfoLevel) logrus.SetOutput(os.Stdout) } // normalize the format strings - cliFlags.outputFormat = strings.ToLower(cliFlags.outputFormat) + flags.outputFormat = strings.ToLower(flags.outputFormat) // check the right output format was passed - format, found := parseFormatString(cliFlags.outputFormat) + format, found := parseFormatString(flags.outputFormat) if !found { - feedback.Error("Invalid output format: " + cliFlags.outputFormat) - os.Exit(errorcodes.ErrBadCall) + return fmt.Errorf("invalid output format: %s", flags.outputFormat) } // use the output format to configure the Feedback feedback.SetFormat(format) + return nil } diff --git a/cli/credentials/find.go b/cli/credentials/find.go index a060577c..987a8e75 100644 --- a/cli/credentials/find.go +++ b/cli/credentials/find.go @@ -32,20 +32,25 @@ func initFindCommand() *cobra.Command { Use: "find", Short: "Find the credentials that would be used in your current directory", Long: "Find the credentials to access Arduino IoT Cloud that would be used in your current directory", - Run: runFindCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runFindCommand(); err != nil { + feedback.Errorf("Error during credentials find: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } return findCommand } -func runFindCommand(cmd *cobra.Command, args []string) { +func runFindCommand() error { logrus.Info("Looking for credentials") src, err := config.FindCredentials() if err != nil { - feedback.Errorf("Error during credentials find: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.Printf("Using credentials in: %s", src) + return nil } diff --git a/cli/credentials/init.go b/cli/credentials/init.go index 28ac765b..f4a6adb6 100644 --- a/cli/credentials/init.go +++ b/cli/credentials/init.go @@ -34,77 +34,75 @@ import ( "github.com/spf13/viper" ) -var initFlags struct { +type initFlags struct { destDir string overwrite bool format string } func initInitCommand() *cobra.Command { + flags := &initFlags{} initCommand := &cobra.Command{ Use: "init", Short: "Initialize a credentials file", Long: "Initialize an Arduino IoT Cloud CLI credentials file", - Run: runInitCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runInitCommand(flags); err != nil { + feedback.Errorf("Error during credentials init: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - initCommand.Flags().StringVar(&initFlags.destDir, "dest-dir", "", "Sets where to save the credentials file") - initCommand.Flags().BoolVar(&initFlags.overwrite, "overwrite", false, "Overwrite existing credentials file") - initCommand.Flags().StringVar(&initFlags.format, "file-format", "yaml", "Format of the credentials file, can be {yaml|json}") + initCommand.Flags().StringVar(&flags.destDir, "dest-dir", "", "Sets where to save the credentials file") + initCommand.Flags().BoolVar(&flags.overwrite, "overwrite", false, "Overwrite existing credentials file") + initCommand.Flags().StringVar(&flags.format, "file-format", "yaml", "Format of the credentials file, can be {yaml|json}") return initCommand } -func runInitCommand(cmd *cobra.Command, args []string) { +func runInitCommand(flags *initFlags) error { logrus.Info("Initializing credentials file") // Get default destination directory if it's not passed - if initFlags.destDir == "" { + if flags.destDir == "" { credPath, err := arduino.DataDir() if err != nil { - feedback.Errorf("Error during credentials init: cannot retrieve arduino default directory: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("cannot retrieve arduino default directory: %w", err) } // Create arduino default directory if it does not exist if credPath.NotExist() { if err = credPath.MkdirAll(); err != nil { - feedback.Errorf("Error during credentials init: cannot create arduino default directory %s: %v", credPath, err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("cannot create arduino default directory %s: %w", credPath, err) } } - initFlags.destDir = credPath.String() + flags.destDir = credPath.String() } // Validate format flag - initFlags.format = strings.ToLower(initFlags.format) - if initFlags.format != "json" && initFlags.format != "yaml" { - feedback.Error("Error during credentials init: format is not valid, provide 'json' or 'yaml'") - os.Exit(errorcodes.ErrGeneric) + flags.format = strings.ToLower(flags.format) + if flags.format != "json" && flags.format != "yaml" { + return fmt.Errorf("format is not valid, provide 'json' or 'yaml'") } // Check that the destination directory is valid and build the credentials file path - credPath, err := paths.New(initFlags.destDir).Abs() + credPath, err := paths.New(flags.destDir).Abs() if err != nil { - feedback.Errorf("Error during credentials init: cannot retrieve absolute path of %s: %v", initFlags.destDir, err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("cannot retrieve absolute path of %s: %w", flags.destDir, err) } if !credPath.IsDir() { - feedback.Errorf("Error during credentials init: %s is not a valid directory", credPath) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("%s is not a valid directory", credPath) } - credFile := credPath.Join(config.CredentialsFilename + "." + initFlags.format) - if !initFlags.overwrite && credFile.Exist() { - feedback.Errorf("Error during credentials init: %s already exists, use '--overwrite' to overwrite it", - credFile) - os.Exit(errorcodes.ErrGeneric) + credFile := credPath.Join(config.CredentialsFilename + "." + flags.format) + if !flags.overwrite && credFile.Exist() { + return fmt.Errorf("%s already exists, use '--overwrite' to overwrite it", credFile) } // Take needed credentials starting an interactive mode feedback.Print("To obtain your API credentials visit https://create.arduino.cc/iot/integrations") id, key, err := paramsPrompt() if err != nil { - feedback.Errorf("Error during credentials init: cannot take credentials params: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("cannot take credentials params: %w", err) } // Write the credentials file @@ -113,11 +111,11 @@ func runInitCommand(cmd *cobra.Command, args []string) { newSettings.Set("client", id) newSettings.Set("secret", key) if err := newSettings.WriteConfigAs(credFile.String()); err != nil { - feedback.Errorf("Error during credentials init: cannot write credentials file: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("cannot write credentials file: %w", err) } feedback.Printf("Credentials file successfully initialized at: %s", credFile) + return nil } func paramsPrompt() (id, key string, err error) { diff --git a/cli/dashboard/create.go b/cli/dashboard/create.go index f306e4c0..0ec9d176 100644 --- a/cli/dashboard/create.go +++ b/cli/dashboard/create.go @@ -30,54 +30,59 @@ import ( "github.com/spf13/cobra" ) -var createFlags struct { +type createFlags struct { name string template string override map[string]string } func initCreateCommand() *cobra.Command { + flags := &createFlags{} createCommand := &cobra.Command{ Use: "create", Short: "Create a dashboard from a template", Long: "Create a dashboard from a template for Arduino IoT Cloud", - Run: runCreateCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateCommand(flags); err != nil { + feedback.Errorf("Error during dashboard create: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Dashboard name") - createCommand.Flags().StringVarP(&createFlags.template, "template", "t", "", + createCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Dashboard name") + createCommand.Flags().StringVarP(&flags.template, "template", "t", "", "File containing a dashboard template, JSON and YAML format are supported", ) - createCommand.Flags().StringToStringVarP(&createFlags.override, "override", "o", nil, + createCommand.Flags().StringToStringVarP(&flags.override, "override", "o", nil, "Map stating the items to be overridden. Ex: 'thing-0=xxxxxxxx,thing-1=yyyyyyyy'") createCommand.MarkFlagRequired("template") return createCommand } -func runCreateCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating dashboard from template %s", createFlags.template) +func runCreateCommand(flags *createFlags) error { + logrus.Infof("Creating dashboard from template %s", flags.template) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during dashboard create: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &dashboard.CreateParams{ - Template: createFlags.template, - Override: createFlags.override, + Template: flags.template, + Override: flags.override, } - if createFlags.name != "" { - params.Name = &createFlags.name + if flags.name != "" { + params.Name = &flags.name } dashboard, err := dashboard.Create(params, cred) if err != nil { - feedback.Errorf("Error during dashboard create: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(createResult{dashboard}) + return nil } type createResult struct { diff --git a/cli/dashboard/delete.go b/cli/dashboard/delete.go index 387d7084..24fb2231 100644 --- a/cli/dashboard/delete.go +++ b/cli/dashboard/delete.go @@ -18,6 +18,7 @@ package dashboard import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,37 +29,42 @@ import ( "github.com/spf13/cobra" ) -var deleteFlags struct { +type deleteFlags struct { id string } func initDeleteCommand() *cobra.Command { + flags := &deleteFlags{} deleteCommand := &cobra.Command{ Use: "delete", Short: "Delete a dashboard", Long: "Delete a dashboard from Arduino IoT Cloud", - Run: runDeleteCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runDeleteCommand(flags); err != nil { + feedback.Errorf("Error during dashboard delete: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Dashboard ID") + deleteCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Dashboard ID") deleteCommand.MarkFlagRequired("id") return deleteCommand } -func runDeleteCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Deleting dashboard %s", deleteFlags.id) +func runDeleteCommand(flags *deleteFlags) error { + logrus.Infof("Deleting dashboard %s", flags.id) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during dashboard delete: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } - params := &dashboard.DeleteParams{ID: deleteFlags.id} + params := &dashboard.DeleteParams{ID: flags.id} err = dashboard.Delete(params, cred) if err != nil { - feedback.Errorf("Error during dashboard delete: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Dashboard successfully deleted") + return nil } diff --git a/cli/dashboard/extract.go b/cli/dashboard/extract.go index 0fec589b..5d455d6c 100644 --- a/cli/dashboard/extract.go +++ b/cli/dashboard/extract.go @@ -18,6 +18,7 @@ package dashboard import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -29,43 +30,47 @@ import ( "gopkg.in/yaml.v3" ) -var extractFlags struct { +type extractFlags struct { id string } func initExtractCommand() *cobra.Command { + flags := &extractFlags{} extractCommand := &cobra.Command{ Use: "extract", Short: "Extract a template from a dashboard", Long: "Extract a template from a Arduino IoT Cloud dashboard", - Run: runExtractCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runExtractCommand(flags); err != nil { + feedback.Errorf("Error during dashboard extract: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Dashboard ID") - + extractCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Dashboard ID") extractCommand.MarkFlagRequired("id") return extractCommand } -func runExtractCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Extracting template from dashboard %s", extractFlags.id) +func runExtractCommand(flags *extractFlags) error { + logrus.Infof("Extracting template from dashboard %s", flags.id) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during dashboard extract: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &dashboard.ExtractParams{ - ID: extractFlags.id, + ID: flags.id, } template, err := dashboard.Extract(params, cred) if err != nil { - feedback.Errorf("Error during template extraction: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(extractResult{template}) + return nil } type extractResult struct { diff --git a/cli/dashboard/list.go b/cli/dashboard/list.go index 37516a98..80e61bad 100644 --- a/cli/dashboard/list.go +++ b/cli/dashboard/list.go @@ -18,6 +18,7 @@ package dashboard import ( + "fmt" "math" "os" "strings" @@ -35,42 +36,48 @@ const ( widgetsPerRow = 3 ) -var listFlags struct { +type listFlags struct { showWidgets bool } func initListCommand() *cobra.Command { + flags := &listFlags{} listCommand := &cobra.Command{ Use: "list", Short: "List dashboards", Long: "List dashboards on Arduino IoT Cloud", - Run: runListCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runListCommand(flags); err != nil { + feedback.Errorf("Error during dashboard list: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - listCommand.Flags().BoolVarP(&listFlags.showWidgets, "show-widgets", "s", false, "Show names of dashboard widgets") + listCommand.Flags().BoolVarP(&flags.showWidgets, "show-widgets", "s", false, "Show names of dashboard widgets") return listCommand } -func runListCommand(cmd *cobra.Command, args []string) { +func runListCommand(flags *listFlags) error { logrus.Info("Listing dashboards") cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during dashboard list: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } dash, err := dashboard.List(cred) if err != nil { - feedback.Errorf("Error during dashboard list: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } - feedback.PrintResult(listResult{dash}) + feedback.PrintResult(listResult{dashboards: dash, showWidgets: flags.showWidgets}) + return nil } type listResult struct { - dashboards []dashboard.DashboardInfo + dashboards []dashboard.DashboardInfo + showWidgets bool } func (r listResult) Data() interface{} { @@ -84,7 +91,7 @@ func (r listResult) String() string { t := table.New() head := []interface{}{"Name", "ID", "UpdatedAt"} - if listFlags.showWidgets { + if r.showWidgets { head = append(head, "Widgets") } t.SetHeader(head...) @@ -92,7 +99,7 @@ func (r listResult) String() string { for _, dash := range r.dashboards { row := []interface{}{dash.Name, dash.ID, dash.UpdatedAt} - if listFlags.showWidgets { + if r.showWidgets { // Limit number of widgets per row. if len(dash.Widgets) > widgetsPerRow { row = append(row, strings.Join(dash.Widgets[:widgetsPerRow], ", ")) @@ -105,7 +112,7 @@ func (r listResult) String() string { t.AddRow(row...) // Print remaining widgets in new rows - if listFlags.showWidgets { + if r.showWidgets { for len(dash.Widgets) > 0 { row := []interface{}{"", "", ""} l := int(math.Min(float64(len(dash.Widgets)), widgetsPerRow)) diff --git a/cli/device/create.go b/cli/device/create.go index 38603cb7..048f1f77 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -29,52 +29,57 @@ import ( "github.com/spf13/cobra" ) -var createFlags struct { +type createFlags struct { port string name string fqbn string } func initCreateCommand() *cobra.Command { + flags := &createFlags{} createCommand := &cobra.Command{ Use: "create", Short: "Create a device provisioning the onboard secure element with a valid certificate", Long: "Create a device for Arduino IoT Cloud provisioning the onboard secure element with a valid certificate", - Run: runCreateCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateCommand(flags); err != nil { + feedback.Errorf("Error during device create: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createCommand.Flags().StringVarP(&createFlags.port, "port", "p", "", "Device port") - createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Device name") - createCommand.Flags().StringVarP(&createFlags.fqbn, "fqbn", "b", "", "Device fqbn") + createCommand.Flags().StringVarP(&flags.port, "port", "p", "", "Device port") + createCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Device name") + createCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "", "Device fqbn") createCommand.MarkFlagRequired("name") return createCommand } -func runCreateCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating device with name %s", createFlags.name) +func runCreateCommand(flags *createFlags) error { + logrus.Infof("Creating device with name %s", flags.name) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device create: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &device.CreateParams{ - Name: createFlags.name, + Name: flags.name, } - if createFlags.port != "" { - params.Port = &createFlags.port + if flags.port != "" { + params.Port = &flags.port } - if createFlags.fqbn != "" { - params.FQBN = &createFlags.fqbn + if flags.fqbn != "" { + params.FQBN = &flags.fqbn } dev, err := device.Create(params, cred) if err != nil { - feedback.Errorf("Error during device create: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(createResult{dev}) + return nil } type createResult struct { diff --git a/cli/device/creategeneric.go b/cli/device/creategeneric.go index e930a357..e417cdf3 100644 --- a/cli/device/creategeneric.go +++ b/cli/device/creategeneric.go @@ -29,45 +29,50 @@ import ( "github.com/spf13/cobra" ) -var createGenericFlags struct { +type createGenericFlags struct { name string fqbn string } func initCreateGenericCommand() *cobra.Command { + flags := &createGenericFlags{} createGenericCommand := &cobra.Command{ Use: "create-generic", Short: "Create a generic device with password authentication - without secure element - WARNING: less secure", Long: "Create a generic device with password authentication for Arduino IoT Cloud - without secure element - WARNING: less secure", - Run: runCreateGenericCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateGenericCommand(flags); err != nil { + feedback.Errorf("Error during device create-generic: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createGenericCommand.Flags().StringVarP(&createGenericFlags.name, "name", "n", "", "Device name") - createGenericCommand.Flags().StringVarP(&createGenericFlags.fqbn, "fqbn", "b", "generic:generic:generic", "Device fqbn") + createGenericCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Device name") + createGenericCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "generic:generic:generic", "Device fqbn") createGenericCommand.MarkFlagRequired("name") return createGenericCommand } -func runCreateGenericCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating generic device with name %s", createGenericFlags.name) +func runCreateGenericCommand(flags *createGenericFlags) error { + logrus.Infof("Creating generic device with name %s", flags.name) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device create-generic: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &device.CreateGenericParams{ - Name: createGenericFlags.name, - FQBN: createGenericFlags.fqbn, + Name: flags.name, + FQBN: flags.fqbn, } dev, err := device.CreateGeneric(params, cred) if err != nil { - feedback.Errorf("Error during device create-generic: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(createGenericResult{dev}) + return nil } type createGenericResult struct { diff --git a/cli/device/createlora.go b/cli/device/createlora.go index 30fc7837..d7fd048c 100644 --- a/cli/device/createlora.go +++ b/cli/device/createlora.go @@ -29,7 +29,7 @@ import ( "github.com/spf13/cobra" ) -var createLoraFlags struct { +type createLoraFlags struct { port string name string fqbn string @@ -37,51 +37,56 @@ var createLoraFlags struct { } func initCreateLoraCommand() *cobra.Command { + flags := &createLoraFlags{} createLoraCommand := &cobra.Command{ Use: "create-lora", Short: "Create a LoRa device", Long: "Create a LoRa device for Arduino IoT Cloud", - Run: runCreateLoraCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateLoraCommand(flags); err != nil { + feedback.Errorf("Error during device create-lora: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createLoraCommand.Flags().StringVarP(&createLoraFlags.port, "port", "p", "", "Device port") - createLoraCommand.Flags().StringVarP(&createLoraFlags.name, "name", "n", "", "Device name") - createLoraCommand.Flags().StringVarP(&createLoraFlags.fqbn, "fqbn", "b", "", "Device fqbn") - createLoraCommand.Flags().StringVarP(&createLoraFlags.frequencyPlan, "frequency-plan", "f", "", + createLoraCommand.Flags().StringVarP(&flags.port, "port", "p", "", "Device port") + createLoraCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Device name") + createLoraCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "", "Device fqbn") + createLoraCommand.Flags().StringVarP(&flags.frequencyPlan, "frequency-plan", "f", "", "ID of the LoRa frequency plan to use. Run the 'device list-frequency-plans' command to obtain a list of valid plans.") createLoraCommand.MarkFlagRequired("name") createLoraCommand.MarkFlagRequired("frequency-plan") return createLoraCommand } -func runCreateLoraCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating LoRa device with name %s", createLoraFlags.name) +func runCreateLoraCommand(flags *createLoraFlags) error { + logrus.Infof("Creating LoRa device with name %s", flags.name) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device create-lora: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &device.CreateLoraParams{ CreateParams: device.CreateParams{ - Name: createLoraFlags.name, + Name: flags.name, }, - FrequencyPlan: createLoraFlags.frequencyPlan, + FrequencyPlan: flags.frequencyPlan, } - if createLoraFlags.port != "" { - params.Port = &createLoraFlags.port + if flags.port != "" { + params.Port = &flags.port } - if createLoraFlags.fqbn != "" { - params.FQBN = &createLoraFlags.fqbn + if flags.fqbn != "" { + params.FQBN = &flags.fqbn } dev, err := device.CreateLora(params, cred) if err != nil { - feedback.Errorf("Error during device create-lora: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(createLoraResult{dev}) + return nil } type createLoraResult struct { diff --git a/cli/device/delete.go b/cli/device/delete.go index 2d7d592e..7fe20556 100644 --- a/cli/device/delete.go +++ b/cli/device/delete.go @@ -18,6 +18,7 @@ package device import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,21 +29,27 @@ import ( "github.com/spf13/cobra" ) -var deleteFlags struct { +type deleteFlags struct { id string tags map[string]string } func initDeleteCommand() *cobra.Command { + flags := &deleteFlags{} deleteCommand := &cobra.Command{ Use: "delete", Short: "Delete a device", Long: "Delete a device from Arduino IoT Cloud", - Run: runDeleteCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runDeleteCommand(flags); err != nil { + feedback.Errorf("Error during device delete: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Device ID") + deleteCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Device ID") deleteCommand.Flags().StringToStringVar( - &deleteFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.\n"+ @@ -52,25 +59,24 @@ func initDeleteCommand() *cobra.Command { return deleteCommand } -func runDeleteCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Deleting device %s", deleteFlags.id) +func runDeleteCommand(flags *deleteFlags) error { + logrus.Infof("Deleting device %s", flags.id) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device delete: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } - params := &device.DeleteParams{Tags: deleteFlags.tags} - if deleteFlags.id != "" { - params.ID = &deleteFlags.id + params := &device.DeleteParams{Tags: flags.tags} + if flags.id != "" { + params.ID = &flags.id } err = device.Delete(params, cred) if err != nil { - feedback.Errorf("Error during device delete: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Device successfully deleted") + return nil } diff --git a/cli/device/list.go b/cli/device/list.go index d7644bc2..c6c8d9db 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -18,6 +18,7 @@ package device import ( + "fmt" "os" "strings" @@ -30,19 +31,25 @@ import ( "github.com/spf13/cobra" ) -var listFlags struct { +type listFlags struct { tags map[string]string } func initListCommand() *cobra.Command { + flags := &listFlags{} listCommand := &cobra.Command{ Use: "list", Short: "List devices", Long: "List devices on Arduino IoT Cloud", - Run: runListCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runListCommand(flags); err != nil { + feedback.Errorf("Error during device list: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } listCommand.Flags().StringToStringVar( - &listFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.\n"+ @@ -51,23 +58,22 @@ func initListCommand() *cobra.Command { return listCommand } -func runListCommand(cmd *cobra.Command, args []string) { +func runListCommand(flags *listFlags) error { logrus.Info("Listing devices") cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device list: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } - params := &device.ListParams{Tags: listFlags.tags} + params := &device.ListParams{Tags: flags.tags} devs, err := device.List(params, cred) if err != nil { - feedback.Errorf("Error during device list: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(listResult{devs}) + return nil } type listResult struct { diff --git a/cli/device/listfqbn.go b/cli/device/listfqbn.go index 10622099..d0fe5939 100644 --- a/cli/device/listfqbn.go +++ b/cli/device/listfqbn.go @@ -33,21 +33,26 @@ func initListFQBNCommand() *cobra.Command { Use: "list-fqbn", Short: "List supported FQBN", Long: "List all the FQBN supported by Arduino IoT Cloud", - Run: runListFQBNCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runListFQBNCommand(); err != nil { + feedback.Errorf("Error during device list-fqbn: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } return listFQBNCommand } -func runListFQBNCommand(cmd *cobra.Command, args []string) { +func runListFQBNCommand() error { logrus.Info("Listing supported FQBN") fqbn, err := device.ListFQBN() if err != nil { - feedback.Errorf("Error during device list-fqbn: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(listFQBNResult{fqbn}) + return nil } type listFQBNResult struct { diff --git a/cli/device/listfrequency.go b/cli/device/listfrequency.go index e3afc381..6f31716f 100644 --- a/cli/device/listfrequency.go +++ b/cli/device/listfrequency.go @@ -18,6 +18,7 @@ package device import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -34,27 +35,31 @@ func initListFrequencyPlansCommand() *cobra.Command { Use: "list-frequency-plans", Short: "List LoRa frequency plans", Long: "List all supported LoRa frequency plans", - Run: runListFrequencyPlansCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runListFrequencyPlansCommand(); err != nil { + feedback.Errorf("Error during device list-frequency-plans: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } return listCommand } -func runListFrequencyPlansCommand(cmd *cobra.Command, args []string) { +func runListFrequencyPlansCommand() error { logrus.Info("Listing supported frequency plans") cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device list-frequency-plans: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } freqs, err := device.ListFrequencyPlans(cred) if err != nil { - feedback.Errorf("Error during device list-frequency-plans: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(listFrequencyPlansResult{freqs}) + return nil } type listFrequencyPlansResult struct { diff --git a/cli/device/tag/create.go b/cli/device/tag/create.go index baee7c3b..8236297e 100644 --- a/cli/device/tag/create.go +++ b/cli/device/tag/create.go @@ -18,6 +18,7 @@ package tag import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,21 +29,27 @@ import ( "github.com/spf13/cobra" ) -var createTagsFlags struct { +type createTagsFlags struct { id string tags map[string]string } func InitCreateTagsCommand() *cobra.Command { + flags := &createTagsFlags{} createTagsCommand := &cobra.Command{ Use: "create-tags", Short: "Create or overwrite tags on a device", Long: "Create or overwrite tags on a device of Arduino IoT Cloud", - Run: runCreateTagsCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateTagsCommand(flags); err != nil { + feedback.Errorf("Error during device create-tags: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createTagsCommand.Flags().StringVarP(&createTagsFlags.id, "id", "i", "", "Device ID") + createTagsCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Device ID") createTagsCommand.Flags().StringToStringVar( - &createTagsFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.", @@ -52,26 +59,24 @@ func InitCreateTagsCommand() *cobra.Command { return createTagsCommand } -func runCreateTagsCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating tags on device %s", createTagsFlags.id) +func runCreateTagsCommand(flags *createTagsFlags) error { + logrus.Infof("Creating tags on device %s", flags.id) params := &tag.CreateTagsParams{ - ID: createTagsFlags.id, - Tags: createTagsFlags.tags, + ID: flags.id, + Tags: flags.tags, Resource: tag.Device, } cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device create-tags: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } - err = tag.CreateTags(params, cred) - if err != nil { - feedback.Errorf("Error during device create-tags: %v", err) - os.Exit(errorcodes.ErrGeneric) + if err = tag.CreateTags(params, cred); err != nil { + return err } logrus.Info("Tags successfully created") + return nil } diff --git a/cli/device/tag/delete.go b/cli/device/tag/delete.go index 56c195db..041888e2 100644 --- a/cli/device/tag/delete.go +++ b/cli/device/tag/delete.go @@ -18,6 +18,7 @@ package tag import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,47 +29,50 @@ import ( "github.com/spf13/cobra" ) -var deleteTagsFlags struct { +type deleteTagsFlags struct { id string keys []string } func InitDeleteTagsCommand() *cobra.Command { + flags := &deleteTagsFlags{} deleteTagsCommand := &cobra.Command{ Use: "delete-tags", Short: "Delete tags of a device", Long: "Delete tags of a device of Arduino IoT Cloud", - Run: runDeleteTagsCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runDeleteTagsCommand(flags); err != nil { + feedback.Errorf("Error during device delete-tags: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - - deleteTagsCommand.Flags().StringVarP(&deleteTagsFlags.id, "id", "i", "", "Device ID") - deleteTagsCommand.Flags().StringSliceVarP(&deleteTagsFlags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete") - + deleteTagsCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Device ID") + deleteTagsCommand.Flags().StringSliceVarP(&flags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete") deleteTagsCommand.MarkFlagRequired("id") deleteTagsCommand.MarkFlagRequired("keys") return deleteTagsCommand } -func runDeleteTagsCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Deleting tags with keys %s", deleteTagsFlags.keys) +func runDeleteTagsCommand(flags *deleteTagsFlags) error { + logrus.Infof("Deleting tags with keys %s", flags.keys) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device delete-tags: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &tag.DeleteTagsParams{ - ID: deleteTagsFlags.id, - Keys: deleteTagsFlags.keys, + ID: flags.id, + Keys: flags.keys, Resource: tag.Device, } err = tag.DeleteTags(params, cred) if err != nil { - feedback.Errorf("Error during device delete-tags: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Tags successfully deleted") + return nil } diff --git a/cli/ota/massupload.go b/cli/ota/massupload.go index cb84ab53..eaf81a2b 100644 --- a/cli/ota/massupload.go +++ b/cli/ota/massupload.go @@ -32,7 +32,7 @@ import ( "github.com/spf13/cobra" ) -var massUploadFlags struct { +type massUploadFlags struct { deviceIDs []string tags map[string]string file string @@ -41,50 +41,52 @@ var massUploadFlags struct { } func initMassUploadCommand() *cobra.Command { + flags := &massUploadFlags{} massUploadCommand := &cobra.Command{ Use: "mass-upload", Short: "Mass OTA upload", Long: "Mass OTA upload on devices of Arduino IoT Cloud", - Run: runMassUploadCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runMassUploadCommand(flags); err != nil { + feedback.Errorf("Error during ota mass-upload: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - - massUploadCommand.Flags().StringSliceVarP(&massUploadFlags.deviceIDs, "device-ids", "d", nil, + massUploadCommand.Flags().StringSliceVarP(&flags.deviceIDs, "device-ids", "d", nil, "Comma-separated list of device IDs to update") - massUploadCommand.Flags().StringToStringVar(&massUploadFlags.tags, "device-tags", nil, + massUploadCommand.Flags().StringToStringVar(&flags.tags, "device-tags", nil, "Comma-separated list of tags with format =.\n"+ "Perform an OTA upload on all devices that match the provided tags.\n"+ "Mutually exclusive with '--device-ids'.", ) - massUploadCommand.Flags().StringVarP(&massUploadFlags.file, "file", "", "", "Binary file (.bin) to be uploaded") - massUploadCommand.Flags().BoolVar(&massUploadFlags.deferred, "deferred", false, "Perform a deferred OTA. It can take up to 1 week.") - massUploadCommand.Flags().StringVarP(&massUploadFlags.fqbn, "fqbn", "b", "", "FQBN of the devices to update") - + massUploadCommand.Flags().StringVarP(&flags.file, "file", "", "", "Binary file (.bin) to be uploaded") + massUploadCommand.Flags().BoolVar(&flags.deferred, "deferred", false, "Perform a deferred OTA. It can take up to 1 week.") + massUploadCommand.Flags().StringVarP(&flags.fqbn, "fqbn", "b", "", "FQBN of the devices to update") massUploadCommand.MarkFlagRequired("file") massUploadCommand.MarkFlagRequired("fqbn") return massUploadCommand } -func runMassUploadCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Uploading binary %s", massUploadFlags.file) +func runMassUploadCommand(flags *massUploadFlags) error { + logrus.Infof("Uploading binary %s", flags.file) params := &ota.MassUploadParams{ - DeviceIDs: massUploadFlags.deviceIDs, - Tags: massUploadFlags.tags, - File: massUploadFlags.file, - Deferred: massUploadFlags.deferred, - FQBN: massUploadFlags.fqbn, + DeviceIDs: flags.deviceIDs, + Tags: flags.tags, + File: flags.file, + Deferred: flags.deferred, + FQBN: flags.fqbn, } cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during device list-frequency-plans: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } resp, err := ota.MassUpload(params, cred) if err != nil { - feedback.Errorf("Error during ota upload: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } // Put successful devices ahead @@ -101,7 +103,7 @@ func runMassUploadCommand(cmd *cobra.Command, args []string) { } } if len(failed) == 0 { - return + return nil } failDevs := strings.Join(failed, ",") feedback.Printf( @@ -109,6 +111,7 @@ func runMassUploadCommand(cmd *cobra.Command, args []string) { "$ arduino-cloud-cli ota mass-upload --file %s --fqbn %s -d %s", params.File, params.FQBN, failDevs, ) + return nil } type massUploadResult struct { diff --git a/cli/ota/upload.go b/cli/ota/upload.go index 17547386..9d724a9e 100644 --- a/cli/ota/upload.go +++ b/cli/ota/upload.go @@ -18,6 +18,7 @@ package ota import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,48 +29,51 @@ import ( "github.com/spf13/cobra" ) -var uploadFlags struct { +type uploadFlags struct { deviceID string file string deferred bool } func initUploadCommand() *cobra.Command { + flags := &uploadFlags{} uploadCommand := &cobra.Command{ Use: "upload", Short: "OTA upload", Long: "OTA upload on a device of Arduino IoT Cloud", - Run: runUploadCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runUploadCommand(flags); err != nil { + feedback.Errorf("Error during ota upload: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - - uploadCommand.Flags().StringVarP(&uploadFlags.deviceID, "device-id", "d", "", "Device ID") - uploadCommand.Flags().StringVarP(&uploadFlags.file, "file", "", "", "Binary file (.bin) to be uploaded") - uploadCommand.Flags().BoolVar(&uploadFlags.deferred, "deferred", false, "Perform a deferred OTA. It can take up to 1 week.") - + uploadCommand.Flags().StringVarP(&flags.deviceID, "device-id", "d", "", "Device ID") + uploadCommand.Flags().StringVarP(&flags.file, "file", "", "", "Binary file (.bin) to be uploaded") + uploadCommand.Flags().BoolVar(&flags.deferred, "deferred", false, "Perform a deferred OTA. It can take up to 1 week.") uploadCommand.MarkFlagRequired("device-id") uploadCommand.MarkFlagRequired("file") return uploadCommand } -func runUploadCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Uploading binary %s to device %s", uploadFlags.file, uploadFlags.deviceID) +func runUploadCommand(flags *uploadFlags) error { + logrus.Infof("Uploading binary %s to device %s", flags.file, flags.deviceID) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during ota upload: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &ota.UploadParams{ - DeviceID: uploadFlags.deviceID, - File: uploadFlags.file, - Deferred: uploadFlags.deferred, + DeviceID: flags.deviceID, + File: flags.file, + Deferred: flags.deferred, } err = ota.Upload(params, cred) if err != nil { - feedback.Errorf("Error during ota upload: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Upload successfully started") + return nil } diff --git a/cli/thing/bind.go b/cli/thing/bind.go index 472105d4..d1384f1d 100644 --- a/cli/thing/bind.go +++ b/cli/thing/bind.go @@ -18,6 +18,7 @@ package thing import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,43 +29,47 @@ import ( "github.com/spf13/cobra" ) -var bindFlags struct { +type bindFlags struct { id string deviceID string } func initBindCommand() *cobra.Command { + flags := &bindFlags{} bindCommand := &cobra.Command{ Use: "bind", Short: "Bind a thing to a device", Long: "Bind a thing to a device on Arduino IoT Cloud", - Run: runBindCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runBindCommand(flags); err != nil { + feedback.Errorf("Error during thing bind: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - bindCommand.Flags().StringVarP(&bindFlags.id, "id", "i", "", "Thing ID") - bindCommand.Flags().StringVarP(&bindFlags.deviceID, "device-id", "d", "", "Device ID") + bindCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Thing ID") + bindCommand.Flags().StringVarP(&flags.deviceID, "device-id", "d", "", "Device ID") bindCommand.MarkFlagRequired("id") bindCommand.MarkFlagRequired("device-id") return bindCommand } -func runBindCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Binding thing %s to device %s", bindFlags.id, bindFlags.deviceID) +func runBindCommand(flags *bindFlags) error { + logrus.Infof("Binding thing %s to device %s", flags.id, flags.deviceID) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing bind: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &thing.BindParams{ - ID: bindFlags.id, - DeviceID: bindFlags.deviceID, + ID: flags.id, + DeviceID: flags.deviceID, } - err = thing.Bind(params, cred) - if err != nil { - feedback.Errorf("Error during thing bind: %v", err) - os.Exit(errorcodes.ErrGeneric) + if err = thing.Bind(params, cred); err != nil { + return err } logrus.Info("Thing-Device bound successfully updated") + return nil } diff --git a/cli/thing/clone.go b/cli/thing/clone.go index 0fb8f097..0afcfcb5 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -30,46 +30,51 @@ import ( "github.com/spf13/cobra" ) -var cloneFlags struct { +type cloneFlags struct { name string cloneID string } func initCloneCommand() *cobra.Command { + flags := &cloneFlags{} cloneCommand := &cobra.Command{ Use: "clone", Short: "Clone a thing", Long: "Clone a thing for Arduino IoT Cloud", - Run: runCloneCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCloneCommand(flags); err != nil { + feedback.Errorf("Error during thing clone: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - cloneCommand.Flags().StringVarP(&cloneFlags.name, "name", "n", "", "Thing name") - cloneCommand.Flags().StringVarP(&cloneFlags.cloneID, "clone-id", "c", "", "ID of Thing to be cloned") + cloneCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Thing name") + cloneCommand.Flags().StringVarP(&flags.cloneID, "clone-id", "c", "", "ID of Thing to be cloned") cloneCommand.MarkFlagRequired("name") cloneCommand.MarkFlagRequired("clone-id") return cloneCommand } -func runCloneCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Cloning thing %s into a new thing called %s", cloneFlags.cloneID, cloneFlags.name) +func runCloneCommand(flags *cloneFlags) error { + logrus.Infof("Cloning thing %s into a new thing called %s", flags.cloneID, flags.name) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing clone: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &thing.CloneParams{ - Name: cloneFlags.name, - CloneID: cloneFlags.cloneID, + Name: flags.name, + CloneID: flags.cloneID, } thing, err := thing.Clone(params, cred) if err != nil { - feedback.Errorf("Error during thing clone: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(cloneResult{thing}) + return nil } type cloneResult struct { diff --git a/cli/thing/create.go b/cli/thing/create.go index c9d51117..67f1fa72 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -30,21 +30,27 @@ import ( "github.com/spf13/cobra" ) -var createFlags struct { +type createFlags struct { name string template string } func initCreateCommand() *cobra.Command { + flags := &createFlags{} createCommand := &cobra.Command{ Use: "create", Short: "Create a thing from a template", Long: "Create a thing from a template for Arduino IoT Cloud", - Run: runCreateCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateCommand(flags); err != nil { + feedback.Errorf("Error during thing create: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Thing name") + createCommand.Flags().StringVarP(&flags.name, "name", "n", "", "Thing name") createCommand.Flags().StringVarP( - &createFlags.template, + &flags.template, "template", "t", "", @@ -54,29 +60,28 @@ func initCreateCommand() *cobra.Command { return createCommand } -func runCreateCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating thing from template %s", createFlags.template) +func runCreateCommand(flags *createFlags) error { + logrus.Infof("Creating thing from template %s", flags.template) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing create: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &thing.CreateParams{ - Template: createFlags.template, + Template: flags.template, } - if createFlags.name != "" { - params.Name = &createFlags.name + if flags.name != "" { + params.Name = &flags.name } thing, err := thing.Create(params, cred) if err != nil { - feedback.Errorf("Error during thing create: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(createResult{thing}) + return nil } type createResult struct { diff --git a/cli/thing/delete.go b/cli/thing/delete.go index 7c934243..dcfc4b20 100644 --- a/cli/thing/delete.go +++ b/cli/thing/delete.go @@ -18,6 +18,7 @@ package thing import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,21 +29,27 @@ import ( "github.com/spf13/cobra" ) -var deleteFlags struct { +type deleteFlags struct { id string tags map[string]string } func initDeleteCommand() *cobra.Command { + flags := &deleteFlags{} deleteCommand := &cobra.Command{ Use: "delete", Short: "Delete a thing", Long: "Delete a thing from Arduino IoT Cloud", - Run: runDeleteCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runDeleteCommand(flags); err != nil { + feedback.Errorf("Error during thing delete: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Thing ID") + deleteCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Thing ID") deleteCommand.Flags().StringToStringVar( - &deleteFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.\n"+ @@ -52,25 +59,24 @@ func initDeleteCommand() *cobra.Command { return deleteCommand } -func runDeleteCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Deleting thing %s", deleteFlags.id) +func runDeleteCommand(flags *deleteFlags) error { + logrus.Infof("Deleting thing %s", flags.id) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing delete: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } - params := &thing.DeleteParams{Tags: deleteFlags.tags} - if deleteFlags.id != "" { - params.ID = &deleteFlags.id + params := &thing.DeleteParams{Tags: flags.tags} + if flags.id != "" { + params.ID = &flags.id } err = thing.Delete(params, cred) if err != nil { - feedback.Errorf("Error during thing delete: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Thing successfully deleted") + return nil } diff --git a/cli/thing/extract.go b/cli/thing/extract.go index e51738be..6fb92d89 100644 --- a/cli/thing/extract.go +++ b/cli/thing/extract.go @@ -18,6 +18,7 @@ package thing import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -29,43 +30,47 @@ import ( "gopkg.in/yaml.v3" ) -var extractFlags struct { +type extractFlags struct { id string } func initExtractCommand() *cobra.Command { + flags := &extractFlags{} extractCommand := &cobra.Command{ Use: "extract", Short: "Extract a template from a thing", Long: "Extract a template from a Arduino IoT Cloud thing", - Run: runExtractCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runExtractCommand(flags); err != nil { + feedback.Errorf("Error during thing extract: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID") - + extractCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Thing ID") extractCommand.MarkFlagRequired("id") return extractCommand } -func runExtractCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Extracting template from thing %s", extractFlags.id) +func runExtractCommand(flags *extractFlags) error { + logrus.Infof("Extracting template from thing %s", flags.id) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during template extraction: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &thing.ExtractParams{ - ID: extractFlags.id, + ID: flags.id, } template, err := thing.Extract(params, cred) if err != nil { - feedback.Errorf("Error during template extraction: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } feedback.PrintResult(extractResult{template}) + return nil } type extractResult struct { diff --git a/cli/thing/list.go b/cli/thing/list.go index 9736ce52..f98b8a5e 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -18,6 +18,7 @@ package thing import ( + "fmt" "os" "strings" @@ -30,7 +31,7 @@ import ( "github.com/spf13/cobra" ) -var listFlags struct { +type listFlags struct { ids []string deviceID string variables bool @@ -38,19 +39,25 @@ var listFlags struct { } func initListCommand() *cobra.Command { + flags := &listFlags{} listCommand := &cobra.Command{ Use: "list", Short: "List things", Long: "List things on Arduino IoT Cloud", - Run: runListCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runListCommand(flags); err != nil { + feedback.Errorf("Error during thing list: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } // list only the things corresponding to the passed ids - listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", nil, "List of thing IDs to be retrieved") + listCommand.Flags().StringSliceVarP(&flags.ids, "ids", "i", nil, "List of thing IDs to be retrieved") // list only the thing associated to the passed device id - listCommand.Flags().StringVarP(&listFlags.deviceID, "device-id", "d", "", "ID of Device associated to the thing to be retrieved") - listCommand.Flags().BoolVarP(&listFlags.variables, "show-variables", "s", false, "Show thing variables") + listCommand.Flags().StringVarP(&flags.deviceID, "device-id", "d", "", "ID of Device associated to the thing to be retrieved") + listCommand.Flags().BoolVarP(&flags.variables, "show-variables", "s", false, "Show thing variables") listCommand.Flags().StringToStringVar( - &listFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.\n"+ @@ -59,35 +66,35 @@ func initListCommand() *cobra.Command { return listCommand } -func runListCommand(cmd *cobra.Command, args []string) { +func runListCommand(flags *listFlags) error { logrus.Info("Listing things") cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing list: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &thing.ListParams{ - IDs: listFlags.ids, - Variables: listFlags.variables, - Tags: listFlags.tags, + IDs: flags.ids, + Variables: flags.variables, + Tags: flags.tags, } - if listFlags.deviceID != "" { - params.DeviceID = &listFlags.deviceID + if flags.deviceID != "" { + params.DeviceID = &flags.deviceID } things, err := thing.List(params, cred) if err != nil { - feedback.Errorf("Error during thing list: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } - feedback.PrintResult(result{things}) + feedback.PrintResult(result{things: things, variables: flags.variables}) + return nil } type result struct { - things []thing.ThingInfo + things []thing.ThingInfo + variables bool } func (r result) Data() interface{} { @@ -101,18 +108,18 @@ func (r result) String() string { t := table.New() h := []interface{}{"Name", "ID", "Device", "Tags"} - if listFlags.variables { + if r.variables { h = append(h, "Variables") } t.SetHeader(h...) for _, thing := range r.things { - r := []interface{}{thing.Name, thing.ID, thing.DeviceID} - r = append(r, strings.Join(thing.Tags, ",")) - if listFlags.variables { - r = append(r, strings.Join(thing.Variables, ", ")) + row := []interface{}{thing.Name, thing.ID, thing.DeviceID} + row = append(row, strings.Join(thing.Tags, ",")) + if r.variables { + row = append(row, strings.Join(thing.Variables, ", ")) } - t.AddRow(r...) + t.AddRow(row...) } return t.Render() } diff --git a/cli/thing/tag/create.go b/cli/thing/tag/create.go index 3e69e374..1724b3b8 100644 --- a/cli/thing/tag/create.go +++ b/cli/thing/tag/create.go @@ -18,6 +18,7 @@ package tag import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,21 +29,27 @@ import ( "github.com/spf13/cobra" ) -var createTagsFlags struct { +type createTagsFlags struct { id string tags map[string]string } func InitCreateTagsCommand() *cobra.Command { + flags := &createTagsFlags{} createTagsCommand := &cobra.Command{ Use: "create-tags", Short: "Create or overwrite tags on a thing", Long: "Create or overwrite tags on a thing of Arduino IoT Cloud", - Run: runCreateTagsCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runCreateTagsCommand(flags); err != nil { + feedback.Errorf("Error during thing create-tags: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - createTagsCommand.Flags().StringVarP(&createTagsFlags.id, "id", "i", "", "Thing ID") + createTagsCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Thing ID") createTagsCommand.Flags().StringToStringVar( - &createTagsFlags.tags, + &flags.tags, "tags", nil, "Comma-separated list of tags with format =.", @@ -52,26 +59,25 @@ func InitCreateTagsCommand() *cobra.Command { return createTagsCommand } -func runCreateTagsCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Creating tags on thing %s", createTagsFlags.id) +func runCreateTagsCommand(flags *createTagsFlags) error { + logrus.Infof("Creating tags on thing %s", flags.id) params := &tag.CreateTagsParams{ - ID: createTagsFlags.id, - Tags: createTagsFlags.tags, + ID: flags.id, + Tags: flags.tags, Resource: tag.Thing, } cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing create-tags: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } err = tag.CreateTags(params, cred) if err != nil { - feedback.Errorf("Error during thing create-tags: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Tags successfully created") + return nil } diff --git a/cli/thing/tag/delete.go b/cli/thing/tag/delete.go index 4da76c25..8c73627f 100644 --- a/cli/thing/tag/delete.go +++ b/cli/thing/tag/delete.go @@ -18,6 +18,7 @@ package tag import ( + "fmt" "os" "github.com/arduino/arduino-cli/cli/errorcodes" @@ -28,47 +29,50 @@ import ( "github.com/spf13/cobra" ) -var deleteTagsFlags struct { +type deleteTagsFlags struct { id string keys []string } func InitDeleteTagsCommand() *cobra.Command { + flags := &deleteTagsFlags{} deleteTagsCommand := &cobra.Command{ Use: "delete-tags", Short: "Delete tags of a thing", Long: "Delete tags of a thing of Arduino IoT Cloud", - Run: runDeleteTagsCommand, + Run: func(cmd *cobra.Command, args []string) { + if err := runDeleteTagsCommand(flags); err != nil { + feedback.Errorf("Error during thing delete-tags: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + }, } - - deleteTagsCommand.Flags().StringVarP(&deleteTagsFlags.id, "id", "i", "", "Thing ID") - deleteTagsCommand.Flags().StringSliceVarP(&deleteTagsFlags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete") - + deleteTagsCommand.Flags().StringVarP(&flags.id, "id", "i", "", "Thing ID") + deleteTagsCommand.Flags().StringSliceVarP(&flags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete") deleteTagsCommand.MarkFlagRequired("id") deleteTagsCommand.MarkFlagRequired("keys") return deleteTagsCommand } -func runDeleteTagsCommand(cmd *cobra.Command, args []string) { - logrus.Infof("Deleting tags with keys %s", deleteTagsFlags.keys) +func runDeleteTagsCommand(flags *deleteTagsFlags) error { + logrus.Infof("Deleting tags with keys %s", flags.keys) cred, err := config.RetrieveCredentials() if err != nil { - feedback.Errorf("Error during thing delete-tags: retrieving credentials: %v", err) - os.Exit(errorcodes.ErrGeneric) + return fmt.Errorf("retrieving credentials: %w", err) } params := &tag.DeleteTagsParams{ - ID: deleteTagsFlags.id, - Keys: deleteTagsFlags.keys, + ID: flags.id, + Keys: flags.keys, Resource: tag.Thing, } err = tag.DeleteTags(params, cred) if err != nil { - feedback.Errorf("Error during thing delete-tags: %v", err) - os.Exit(errorcodes.ErrGeneric) + return err } logrus.Info("Tags successfully deleted") + return nil }