From f7a9d77a631dade525069581523da8d6ab5d9cde Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 14:35:43 +0200 Subject: [PATCH 01/17] Replace fmt print into log info --- cli/cli.go | 83 +++++++++++++++++++++++++++++++++++++ cli/config/config.go | 3 +- cli/device/create.go | 7 ++-- cli/device/delete.go | 7 ++-- cli/device/list.go | 5 +-- cli/root.go | 22 ---------- cli/thing/bind.go | 7 ++-- cli/thing/clone.go | 7 ++-- cli/thing/create.go | 7 ++-- cli/thing/delete.go | 7 ++-- cli/thing/extract.go | 7 ++-- cli/thing/list.go | 4 +- command/device/create.go | 3 +- command/device/provision.go | 35 ++++++++-------- 14 files changed, 130 insertions(+), 74 deletions(-) create mode 100644 cli/cli.go delete mode 100644 cli/root.go diff --git a/cli/cli.go b/cli/cli.go new file mode 100644 index 00000000..91d64e61 --- /dev/null +++ b/cli/cli.go @@ -0,0 +1,83 @@ +package cli + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" + "github.com/arduino/iot-cloud-cli/cli/config" + "github.com/arduino/iot-cloud-cli/cli/device" + "github.com/arduino/iot-cloud-cli/cli/thing" + "github.com/mattn/go-colorable" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +var cliFlags struct { + verbose bool + outputFormat string +} + +func Execute() { + cli := &cobra.Command{ + Use: "arduino-cloud-cli", + Short: "Arduino Cloud CLI.", + Long: "Arduino Cloud Command Line Interface (arduino-cloud-cli).", + PersistentPreRun: preRun, + } + + cli.AddCommand(config.NewCommand()) + cli.AddCommand(device.NewCommand()) + cli.AddCommand(thing.NewCommand()) + + cli.PersistentFlags().BoolVarP(&cliFlags.verbose, "verbose", "v", false, "Print the logs on the standard output.") + cli.PersistentFlags().StringVar(&cliFlags.outputFormat, "format", "text", "The output format, can be {text|json}.") + + if err := cli.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + } +} + +func parseFormatString(arg string) (feedback.OutputFormat, bool) { + f, found := map[string]feedback.OutputFormat{ + "json": feedback.JSON, + "text": feedback.Text, + }[arg] + + return f, found +} + +func preRun(cmd *cobra.Command, args []string) { + // decide whether we should log to stdout + if cliFlags.verbose { + // if we print on stdout, do it in full colors + logrus.SetOutput(colorable.NewColorableStdout()) + logrus.SetFormatter(&logrus.TextFormatter{ + ForceColors: true, + }) + } else { + logrus.SetOutput(ioutil.Discard) + } + + // normalize the format strings + cliFlags.outputFormat = strings.ToLower(cliFlags.outputFormat) + // check the right output format was passed + format, found := parseFormatString(cliFlags.outputFormat) + if !found { + feedback.Error("Invalid output format: " + cliFlags.outputFormat) + os.Exit(errorcodes.ErrBadCall) + } + // use the output format to configure the Feedback + feedback.SetFormat(format) + + if cliFlags.outputFormat != "text" { + cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { + logrus.Warn("Calling help on JSON format") + feedback.Error("Invalid Call : should show Help, but it is available only in TEXT mode.") + os.Exit(errorcodes.ErrBadCall) + }) + } +} diff --git a/cli/config/config.go b/cli/config/config.go index ddd856f0..3e9b92b7 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -7,6 +7,7 @@ import ( "github.com/arduino/arduino-cli/cli/feedback" paths "github.com/arduino/go-paths-helper" "github.com/arduino/iot-cloud-cli/command/config" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -60,6 +61,6 @@ func runConfigCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Println("Configuration file updated") + logrus.Info("Configuration file updated") return nil } diff --git a/cli/device/create.go b/cli/device/create.go index 49c2302e..f7b5f021 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -1,9 +1,8 @@ package device import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/device" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -28,7 +27,7 @@ func initCreateCommand() *cobra.Command { } func runCreateCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Creating device with name %s\n", createFlags.name) + logrus.Infof("Creating device with name %s\n", createFlags.name) params := &device.CreateParams{ Name: createFlags.name, @@ -45,6 +44,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Printf("IoT Cloud device created with ID: %s\n", devID) + logrus.Infof("IoT Cloud device created with ID: %s\n", devID) return nil } diff --git a/cli/device/delete.go b/cli/device/delete.go index f71f8e8e..41eddb93 100644 --- a/cli/device/delete.go +++ b/cli/device/delete.go @@ -1,9 +1,8 @@ package device import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/device" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -24,7 +23,7 @@ func initDeleteCommand() *cobra.Command { } func runDeleteCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Deleting device %s\n", deleteFlags.id) + logrus.Infof("Deleting device %s\n", deleteFlags.id) params := &device.DeleteParams{ID: deleteFlags.id} err := device.Delete(params) @@ -32,6 +31,6 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Println("Device successfully deleted") + logrus.Info("Device successfully deleted") return nil } diff --git a/cli/device/list.go b/cli/device/list.go index e7f86540..6d758d27 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -1,11 +1,10 @@ package device import ( - "fmt" - "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/table" "github.com/arduino/iot-cloud-cli/command/device" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -20,7 +19,7 @@ func initListCommand() *cobra.Command { } func runListCommand(cmd *cobra.Command, args []string) error { - fmt.Println("Listing devices") + logrus.Info("Listing devices") devs, err := device.List() if err != nil { diff --git a/cli/root.go b/cli/root.go deleted file mode 100644 index ccc75821..00000000 --- a/cli/root.go +++ /dev/null @@ -1,22 +0,0 @@ -package cli - -import ( - "fmt" - "os" - - "github.com/arduino/iot-cloud-cli/cli/config" - "github.com/arduino/iot-cloud-cli/cli/device" - "github.com/arduino/iot-cloud-cli/cli/thing" - "github.com/spf13/cobra" -) - -func Execute() { - rootCmd := &cobra.Command{} - rootCmd.AddCommand(config.NewCommand()) - rootCmd.AddCommand(device.NewCommand()) - rootCmd.AddCommand(thing.NewCommand()) - - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - } -} diff --git a/cli/thing/bind.go b/cli/thing/bind.go index 5f940655..3e000de8 100644 --- a/cli/thing/bind.go +++ b/cli/thing/bind.go @@ -1,9 +1,8 @@ package thing import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -27,7 +26,7 @@ func initBindCommand() *cobra.Command { } func runBindCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Binding thing %s to device%s\n", bindFlags.id, bindFlags.deviceID) + logrus.Infof("Binding thing %s to device %s\n", bindFlags.id, bindFlags.deviceID) params := &thing.BindParams{ ID: bindFlags.id, @@ -38,6 +37,6 @@ func runBindCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Println("Thing-Device bound successfully updated") + logrus.Info("Thing-Device bound successfully updated") return nil } diff --git a/cli/thing/clone.go b/cli/thing/clone.go index c976f69b..bca8e2e6 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -1,9 +1,8 @@ package thing import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -27,7 +26,7 @@ func initCloneCommand() *cobra.Command { } func runCloneCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Cloning thing %s into a new thing called %s\n", cloneFlags.cloneID, cloneFlags.name) + logrus.Infof("Cloning thing %s into a new thing called %s\n", cloneFlags.cloneID, cloneFlags.name) params := &thing.CloneParams{ Name: cloneFlags.name, @@ -39,6 +38,6 @@ func runCloneCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Printf("IoT Cloud thing created with ID: %s\n", thingID) + logrus.Infof("IoT Cloud thing created with ID: %s\n", thingID) return nil } diff --git a/cli/thing/create.go b/cli/thing/create.go index fd3545da..1ea3537d 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -1,9 +1,8 @@ package thing import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -32,7 +31,7 @@ func initCreateCommand() *cobra.Command { } func runCreateCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Creating thing from template %s\n", createFlags.template) + logrus.Infof("Creating thing from template %s\n", createFlags.template) params := &thing.CreateParams{ Template: createFlags.template, @@ -46,6 +45,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Printf("IoT Cloud thing created with ID: %s\n", thingID) + logrus.Infof("IoT Cloud thing created with ID: %s\n", thingID) return nil } diff --git a/cli/thing/delete.go b/cli/thing/delete.go index ef922edc..d02b94af 100644 --- a/cli/thing/delete.go +++ b/cli/thing/delete.go @@ -1,9 +1,8 @@ package thing import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -24,7 +23,7 @@ func initDeleteCommand() *cobra.Command { } func runDeleteCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Deleting thing %s\n", deleteFlags.id) + logrus.Infof("Deleting thing %s\n", deleteFlags.id) params := &thing.DeleteParams{ID: deleteFlags.id} err := thing.Delete(params) @@ -32,6 +31,6 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Println("Thing successfully deleted") + logrus.Infof("Thing successfully deleted") return nil } diff --git a/cli/thing/extract.go b/cli/thing/extract.go index ba99971a..a5d3ceb2 100644 --- a/cli/thing/extract.go +++ b/cli/thing/extract.go @@ -1,9 +1,8 @@ package thing import ( - "fmt" - "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -34,7 +33,7 @@ func initExtractCommand() *cobra.Command { } func runExtractCommand(cmd *cobra.Command, args []string) error { - fmt.Printf("Extracting template from thing %s\n", extractFlags.id) + logrus.Infof("Extracting template from thing %s\n", extractFlags.id) params := &thing.ExtractParams{ ID: extractFlags.id, @@ -49,6 +48,6 @@ func runExtractCommand(cmd *cobra.Command, args []string) error { return err } - fmt.Println("Template successfully extracted") + logrus.Infof("Template successfully extracted") return nil } diff --git a/cli/thing/list.go b/cli/thing/list.go index 961e1168..ad5774b3 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -1,12 +1,12 @@ package thing import ( - "fmt" "strings" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/table" "github.com/arduino/iot-cloud-cli/command/thing" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -32,7 +32,7 @@ func initListCommand() *cobra.Command { } func runListCommand(cmd *cobra.Command, args []string) error { - fmt.Println("Listing things") + logrus.Info("Listing things") params := &thing.ListParams{ IDs: listFlags.ids, diff --git a/command/device/create.go b/command/device/create.go index 7b3e5673..04c45404 100644 --- a/command/device/create.go +++ b/command/device/create.go @@ -9,6 +9,7 @@ import ( "github.com/arduino/iot-cloud-cli/arduino/cli" "github.com/arduino/iot-cloud-cli/internal/config" "github.com/arduino/iot-cloud-cli/internal/iot" + "github.com/sirupsen/logrus" ) // CreateParams contains the parameters needed @@ -56,7 +57,7 @@ func Create(params *CreateParams) (string, error) { return "", err } - fmt.Println("Creating a new device on the cloud") + logrus.Info("Creating a new device on the cloud") devID, err := iotClient.DeviceCreate(dev.fqbn, params.Name, dev.serial, dev.dType) if err != nil { return "", err diff --git a/command/device/provision.go b/command/device/provision.go index c8fb3213..3d561145 100644 --- a/command/device/provision.go +++ b/command/device/provision.go @@ -12,6 +12,7 @@ import ( "github.com/arduino/iot-cloud-cli/arduino" "github.com/arduino/iot-cloud-cli/internal/iot" "github.com/arduino/iot-cloud-cli/internal/serial" + "github.com/sirupsen/logrus" ) type provision struct { @@ -36,7 +37,7 @@ func (p provision) run() error { return err } - fmt.Printf("\n%s\n", "Uploading provisioning sketch on the device") + logrus.Infof("\n%s\n", "Uploading provisioning sketch on the device") time.Sleep(500 * time.Millisecond) // Try to upload the provisioning sketch errMsg := "Error while uploading the provisioning sketch: " @@ -48,7 +49,7 @@ func (p provision) run() error { return err } - fmt.Printf("\n%s\n", "Connecting to the device through serial port") + logrus.Infof("\n%s\n", "Connecting to the device through serial port") // Try to connect to device through the serial port time.Sleep(1500 * time.Millisecond) p.ser = serial.NewSerial() @@ -60,7 +61,7 @@ func (p provision) run() error { return err } defer p.ser.Close() - fmt.Printf("%s\n\n", "Connected to device") + logrus.Infof("%s\n\n", "Connected to device") // Send configuration commands to the device err = p.configDev() @@ -68,12 +69,12 @@ func (p provision) run() error { return err } - fmt.Printf("%s\n\n", "Device provisioning successful") + logrus.Infof("%s\n\n", "Device provisioning successful") return nil } func (p provision) configDev() error { - fmt.Println("Receiving the certificate") + logrus.Infof("Receiving the certificate") csr, err := p.ser.SendReceive(serial.CSR, []byte(p.id)) if err != nil { return err @@ -83,48 +84,48 @@ func (p provision) configDev() error { return err } - fmt.Println("Requesting begin storage") + logrus.Infof("Requesting begin storage") err = p.ser.Send(serial.BeginStorage, nil) if err != nil { return err } s := strconv.Itoa(cert.NotBefore.Year()) - fmt.Println("Sending year: ", s) + logrus.Infof("Sending year: ", s) err = p.ser.Send(serial.SetYear, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", int(cert.NotBefore.Month())) - fmt.Println("Sending month: ", s) + logrus.Infof("Sending month: ", s) err = p.ser.Send(serial.SetMonth, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", cert.NotBefore.Day()) - fmt.Println("Sending day: ", s) + logrus.Infof("Sending day: ", s) err = p.ser.Send(serial.SetDay, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", cert.NotBefore.Hour()) - fmt.Println("Sending hour: ", s) + logrus.Infof("Sending hour: ", s) err = p.ser.Send(serial.SetHour, []byte(s)) if err != nil { return err } s = strconv.Itoa(31) - fmt.Println("Sending validity: ", s) + logrus.Infof("Sending validity: ", s) err = p.ser.Send(serial.SetValidity, []byte(s)) if err != nil { return err } - fmt.Println("Sending certificate serial") + logrus.Infof("Sending certificate serial") b, err := hex.DecodeString(cert.Serial) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate serial", err) @@ -135,7 +136,7 @@ func (p provision) configDev() error { return err } - fmt.Println("Sending certificate authority key") + logrus.Infof("Sending certificate authority key") b, err = hex.DecodeString(cert.AuthorityKeyIdentifier) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate authority key id", err) @@ -146,7 +147,7 @@ func (p provision) configDev() error { return err } - fmt.Println("Sending certificate signature") + logrus.Infof("Sending certificate signature") b, err = hex.DecodeString(cert.SignatureAsn1X + cert.SignatureAsn1Y) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate signature", err) @@ -158,14 +159,14 @@ func (p provision) configDev() error { } time.Sleep(time.Second) - fmt.Println("Requesting end storage") + logrus.Infof("Requesting end storage") err = p.ser.Send(serial.EndStorage, nil) if err != nil { return err } time.Sleep(2 * time.Second) - fmt.Println("Requesting certificate reconstruction") + logrus.Infof("Requesting certificate reconstruction") err = p.ser.Send(serial.ReconstructCert, nil) if err != nil { return err @@ -254,7 +255,7 @@ func retry(tries int, sleep time.Duration, errMsg string, fun func() error) erro if err == nil { break } - fmt.Println(errMsg, err.Error(), "\nTrying again...") + logrus.Warningf(errMsg, err.Error(), "\nTrying again...") time.Sleep(sleep) } return err From fb1d71640c5d21b47203e173acad4762e7d36131 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 15:03:20 +0200 Subject: [PATCH 02/17] Distinguish board from device --- command/device/create.go | 28 ++++++++++++++-------------- command/device/create_test.go | 22 +++++++++++----------- command/device/provision.go | 28 ++++++++++++++-------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/command/device/create.go b/command/device/create.go index 04c45404..ae76e29d 100644 --- a/command/device/create.go +++ b/command/device/create.go @@ -23,7 +23,7 @@ type CreateParams struct { Fqbn *string } -type device struct { +type board struct { fqbn string serial string dType string @@ -42,9 +42,9 @@ func Create(params *CreateParams) (string, error) { if err != nil { return "", err } - dev := deviceFromPorts(ports, params) - if dev == nil { - err = errors.New("no device found") + board := boardFromPorts(ports, params) + if board == nil { + err = errors.New("no board found") return "", err } @@ -58,7 +58,7 @@ func Create(params *CreateParams) (string, error) { } logrus.Info("Creating a new device on the cloud") - devID, err := iotClient.DeviceCreate(dev.fqbn, params.Name, dev.serial, dev.dType) + devID, err := iotClient.DeviceCreate(board.fqbn, params.Name, board.serial, board.dType) if err != nil { return "", err } @@ -66,7 +66,7 @@ func Create(params *CreateParams) (string, error) { prov := &provision{ Commander: comm, Client: iotClient, - dev: dev, + board: board, id: devID} err = prov.run() if err != nil { @@ -80,18 +80,18 @@ func Create(params *CreateParams) (string, error) { return devID, nil } -// deviceFromPorts returns a board that matches all the criteria -// passed in. If no criteria are passed, it returns the first device found. -func deviceFromPorts(ports []*rpc.DetectedPort, params *CreateParams) *device { +// boardFromPorts returns a board that matches all the criteria +// passed in. If no criteria are passed, it returns the first board found. +func boardFromPorts(ports []*rpc.DetectedPort, params *CreateParams) *board { for _, port := range ports { if portFilter(port, params) { continue } - board := boardFilter(port.Boards, params) - if board != nil { - t := strings.Split(board.Fqbn, ":")[2] - dev := &device{board.Fqbn, port.SerialNumber, t, port.Address} - return dev + boardFound := boardFilter(port.Boards, params) + if boardFound != nil { + t := strings.Split(boardFound.Fqbn, ":")[2] + b := &board{boardFound.Fqbn, port.SerialNumber, t, port.Address} + return b } } diff --git a/command/device/create_test.go b/command/device/create_test.go index 4f6f5ae0..a52d61eb 100644 --- a/command/device/create_test.go +++ b/command/device/create_test.go @@ -39,26 +39,26 @@ func stringPointer(s string) *string { return &s } -func TestDeviceFromPorts(t *testing.T) { +func TestBoardFromPorts(t *testing.T) { tests := []struct { name string filter *CreateParams ports []*rpc.DetectedPort - want *device + want *board }{ { name: "port-filter", filter: &CreateParams{Fqbn: nil, Port: stringPointer("ACM1")}, ports: portsTwoBoards, - want: &device{fqbn: "arduino:avr:uno", port: "ACM1"}, + want: &board{fqbn: "arduino:avr:uno", port: "ACM1"}, }, { name: "fqbn-filter", filter: &CreateParams{Fqbn: stringPointer("arduino:avr:uno"), Port: nil}, ports: portsTwoBoards, - want: &device{fqbn: "arduino:avr:uno", port: "ACM1"}, + want: &board{fqbn: "arduino:avr:uno", port: "ACM1"}, }, { @@ -72,8 +72,8 @@ func TestDeviceFromPorts(t *testing.T) { name: "no-filter", filter: &CreateParams{Fqbn: nil, Port: nil}, ports: portsTwoBoards, - // first device found is selected - want: &device{fqbn: "arduino:samd:nano_33_iot", port: "ACM0"}, + // first board found is selected + want: &board{fqbn: "arduino:samd:nano_33_iot", port: "ACM0"}, }, { @@ -87,7 +87,7 @@ func TestDeviceFromPorts(t *testing.T) { name: "both-filter-found", filter: &CreateParams{Fqbn: stringPointer("arduino:avr:uno"), Port: stringPointer("ACM1")}, ports: portsTwoBoards, - want: &device{fqbn: "arduino:avr:uno", port: "ACM1"}, + want: &board{fqbn: "arduino:avr:uno", port: "ACM1"}, }, { @@ -100,19 +100,19 @@ func TestDeviceFromPorts(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := deviceFromPorts(tt.ports, tt.filter) + got := boardFromPorts(tt.ports, tt.filter) if got == nil && tt.want == nil { return } else if got != nil && tt.want == nil { - t.Errorf("Expected nil device, received not nil device with port %s and fqbn %s", got.port, got.fqbn) + t.Errorf("Expected nil board, received not nil board with port %s and fqbn %s", got.port, got.fqbn) } else if got == nil && tt.want != nil { - t.Errorf("Expected not nil device with port %s and fqbn %s, received a nil device", tt.want.port, tt.want.fqbn) + t.Errorf("Expected not nil board with port %s and fqbn %s, received a nil board", tt.want.port, tt.want.fqbn) } else if got.port != tt.want.port || got.fqbn != tt.want.fqbn { - t.Errorf("Expected device with port %s and fqbn %s, received device with port %s and fqbn %s", + t.Errorf("Expected board with port %s and fqbn %s, received board with port %s and fqbn %s", tt.want.port, tt.want.fqbn, got.port, got.fqbn) } }) diff --git a/command/device/provision.go b/command/device/provision.go index 3d561145..abf8e2e3 100644 --- a/command/device/provision.go +++ b/command/device/provision.go @@ -18,9 +18,9 @@ import ( type provision struct { arduino.Commander iot.Client - ser *serial.Serial - dev *device - id string + ser *serial.Serial + board *board + id string } type binFile struct { @@ -32,39 +32,39 @@ type binFile struct { } func (p provision) run() error { - bin, err := downloadProvisioningFile(p.dev.fqbn) + bin, err := downloadProvisioningFile(p.board.fqbn) if err != nil { return err } - logrus.Infof("\n%s\n", "Uploading provisioning sketch on the device") + logrus.Infof("\n%s\n", "Uploading provisioning sketch on the board") time.Sleep(500 * time.Millisecond) // Try to upload the provisioning sketch errMsg := "Error while uploading the provisioning sketch: " err = retry(5, time.Millisecond*1000, errMsg, func() error { //serialutils.Reset(dev.port, true, nil) - return p.UploadBin(p.dev.fqbn, bin, p.dev.port) + return p.UploadBin(p.board.fqbn, bin, p.board.port) }) if err != nil { return err } - logrus.Infof("\n%s\n", "Connecting to the device through serial port") - // Try to connect to device through the serial port + logrus.Infof("\n%s\n", "Connecting to the board through serial port") + // Try to connect to board through the serial port time.Sleep(1500 * time.Millisecond) p.ser = serial.NewSerial() - errMsg = "Error while connecting to the device: " + errMsg = "Error while connecting to the board: " err = retry(5, time.Millisecond*1000, errMsg, func() error { - return p.ser.Connect(p.dev.port) + return p.ser.Connect(p.board.port) }) if err != nil { return err } defer p.ser.Close() - logrus.Infof("%s\n\n", "Connected to device") + logrus.Infof("%s\n\n", "Connected to board") - // Send configuration commands to the device - err = p.configDev() + // Send configuration commands to the board + err = p.configBoard() if err != nil { return err } @@ -73,7 +73,7 @@ func (p provision) run() error { return nil } -func (p provision) configDev() error { +func (p provision) configBoard() error { logrus.Infof("Receiving the certificate") csr, err := p.ser.SendReceive(serial.CSR, []byte(p.id)) if err != nil { From 7801fce3fa62d5de960d774322d26aa80686cdc7 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 15:19:33 +0200 Subject: [PATCH 03/17] Improve device format output --- cli/device/create.go | 21 +++++++++++++++++++-- cli/device/list.go | 8 ++++---- command/device/create.go | 35 +++++++++++++++++++++-------------- internal/iot/client.go | 8 ++++---- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/cli/device/create.go b/cli/device/create.go index f7b5f021..f5a33000 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -1,6 +1,9 @@ package device import ( + "fmt" + + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/device" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -39,11 +42,25 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { params.Fqbn = &createFlags.fqbn } - devID, err := device.Create(params) + dev, err := device.Create(params) if err != nil { return err } - logrus.Infof("IoT Cloud device created with ID: %s\n", devID) + logrus.Infof("IoT Cloud device created with ID: %s\n", dev.ID) + feedback.PrintResult(createResult{dev}) + return nil } + +type createResult struct { + device *device.DeviceInfo +} + +func (r createResult) Data() interface{} { + return r.device +} + +func (r createResult) String() string { + return fmt.Sprintf("IoT Cloud device created with ID: %s\n", r.device.ID) +} diff --git a/cli/device/list.go b/cli/device/list.go index 6d758d27..fabf9aab 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -26,20 +26,20 @@ func runListCommand(cmd *cobra.Command, args []string) error { return err } - feedback.PrintResult(result{devs}) + feedback.PrintResult(listResult{devs}) return nil } -type result struct { +type listResult struct { devices []device.DeviceInfo } -func (r result) Data() interface{} { +func (r listResult) Data() interface{} { return r.devices } -func (r result) String() string { +func (r listResult) String() string { if len(r.devices) == 0 { return "No devices found." } diff --git a/command/device/create.go b/command/device/create.go index ae76e29d..0a6dce21 100644 --- a/command/device/create.go +++ b/command/device/create.go @@ -32,52 +32,59 @@ type board struct { // Create command is used to provision a new arduino device // and to add it to Arduino IoT Cloud. -func Create(params *CreateParams) (string, error) { +func Create(params *CreateParams) (*DeviceInfo, error) { comm, err := cli.NewCommander() if err != nil { - return "", err + return nil, err } ports, err := comm.BoardList() if err != nil { - return "", err + return nil, err } board := boardFromPorts(ports, params) if board == nil { err = errors.New("no board found") - return "", err + return nil, err } conf, err := config.Retrieve() if err != nil { - return "", err + return nil, err } iotClient, err := iot.NewClient(conf.Client, conf.Secret) if err != nil { - return "", err + return nil, err } logrus.Info("Creating a new device on the cloud") - devID, err := iotClient.DeviceCreate(board.fqbn, params.Name, board.serial, board.dType) + dev, err := iotClient.DeviceCreate(board.fqbn, params.Name, board.serial, board.dType) if err != nil { - return "", err + return nil, err } prov := &provision{ Commander: comm, Client: iotClient, board: board, - id: devID} - err = prov.run() - if err != nil { + id: dev.Id, + } + if err = prov.run(); err != nil { // TODO: retry to delete the device if it returns an error. // In alternative: encapsulate also this error. - iotClient.DeviceDelete(devID) + iotClient.DeviceDelete(dev.Id) err = fmt.Errorf("%s: %w", "cannot provision device", err) - return "", err + return nil, err } - return devID, nil + devInfo := &DeviceInfo{ + Name: dev.Name, + ID: dev.Id, + Board: dev.Type, + Serial: dev.Serial, + FQBN: dev.Fqbn, + } + return devInfo, nil } // boardFromPorts returns a board that matches all the criteria diff --git a/internal/iot/client.go b/internal/iot/client.go index 5560ca6a..f0332581 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -10,7 +10,7 @@ import ( // Client can be used to perform actions on Arduino IoT Cloud. type Client interface { - DeviceCreate(fqbn, name, serial, devType string) (string, error) + DeviceCreate(fqbn, name, serial, devType string) (*iotclient.ArduinoDevicev2, error) DeviceDelete(id string) error DeviceList() ([]iotclient.ArduinoDevicev2, error) DeviceShow(id string) (*iotclient.ArduinoDevicev2, error) @@ -41,7 +41,7 @@ func NewClient(clientID, secretID string) (Client, error) { // DeviceCreate allows to create a new device on Arduino IoT Cloud. // It returns the ID associated to the new device, and an error. -func (cl *client) DeviceCreate(fqbn, name, serial, dType string) (string, error) { +func (cl *client) DeviceCreate(fqbn, name, serial, dType string) (*iotclient.ArduinoDevicev2, error) { payload := iotclient.CreateDevicesV2Payload{ Fqbn: fqbn, Name: name, @@ -51,9 +51,9 @@ func (cl *client) DeviceCreate(fqbn, name, serial, dType string) (string, error) dev, _, err := cl.api.DevicesV2Api.DevicesV2Create(cl.ctx, payload) if err != nil { err = fmt.Errorf("creating device, %w", errorDetail(err)) - return "", err + return nil, err } - return dev.Id, nil + return &dev, nil } // DeviceDelete deletes the device corresponding to the passed ID From 7293f81112eeb42f36695364454a4566065f2cc9 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 15:22:00 +0200 Subject: [PATCH 04/17] Fix log infof --- cli/thing/delete.go | 2 +- cli/thing/extract.go | 2 +- command/device/provision.go | 24 ++++++++++++------------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cli/thing/delete.go b/cli/thing/delete.go index d02b94af..182cfa06 100644 --- a/cli/thing/delete.go +++ b/cli/thing/delete.go @@ -31,6 +31,6 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { return err } - logrus.Infof("Thing successfully deleted") + logrus.Info("Thing successfully deleted") return nil } diff --git a/cli/thing/extract.go b/cli/thing/extract.go index a5d3ceb2..1e442c6d 100644 --- a/cli/thing/extract.go +++ b/cli/thing/extract.go @@ -48,6 +48,6 @@ func runExtractCommand(cmd *cobra.Command, args []string) error { return err } - logrus.Infof("Template successfully extracted") + logrus.Info("Template successfully extracted") return nil } diff --git a/command/device/provision.go b/command/device/provision.go index abf8e2e3..90d7bfea 100644 --- a/command/device/provision.go +++ b/command/device/provision.go @@ -74,7 +74,7 @@ func (p provision) run() error { } func (p provision) configBoard() error { - logrus.Infof("Receiving the certificate") + logrus.Info("Receiving the certificate") csr, err := p.ser.SendReceive(serial.CSR, []byte(p.id)) if err != nil { return err @@ -84,48 +84,48 @@ func (p provision) configBoard() error { return err } - logrus.Infof("Requesting begin storage") + logrus.Info("Requesting begin storage") err = p.ser.Send(serial.BeginStorage, nil) if err != nil { return err } s := strconv.Itoa(cert.NotBefore.Year()) - logrus.Infof("Sending year: ", s) + logrus.Info("Sending year: ", s) err = p.ser.Send(serial.SetYear, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", int(cert.NotBefore.Month())) - logrus.Infof("Sending month: ", s) + logrus.Info("Sending month: ", s) err = p.ser.Send(serial.SetMonth, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", cert.NotBefore.Day()) - logrus.Infof("Sending day: ", s) + logrus.Info("Sending day: ", s) err = p.ser.Send(serial.SetDay, []byte(s)) if err != nil { return err } s = fmt.Sprintf("%02d", cert.NotBefore.Hour()) - logrus.Infof("Sending hour: ", s) + logrus.Info("Sending hour: ", s) err = p.ser.Send(serial.SetHour, []byte(s)) if err != nil { return err } s = strconv.Itoa(31) - logrus.Infof("Sending validity: ", s) + logrus.Info("Sending validity: ", s) err = p.ser.Send(serial.SetValidity, []byte(s)) if err != nil { return err } - logrus.Infof("Sending certificate serial") + logrus.Info("Sending certificate serial") b, err := hex.DecodeString(cert.Serial) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate serial", err) @@ -136,7 +136,7 @@ func (p provision) configBoard() error { return err } - logrus.Infof("Sending certificate authority key") + logrus.Info("Sending certificate authority key") b, err = hex.DecodeString(cert.AuthorityKeyIdentifier) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate authority key id", err) @@ -147,7 +147,7 @@ func (p provision) configBoard() error { return err } - logrus.Infof("Sending certificate signature") + logrus.Info("Sending certificate signature") b, err = hex.DecodeString(cert.SignatureAsn1X + cert.SignatureAsn1Y) if err != nil { err = fmt.Errorf("%s: %w", "decoding certificate signature", err) @@ -159,14 +159,14 @@ func (p provision) configBoard() error { } time.Sleep(time.Second) - logrus.Infof("Requesting end storage") + logrus.Info("Requesting end storage") err = p.ser.Send(serial.EndStorage, nil) if err != nil { return err } time.Sleep(2 * time.Second) - logrus.Infof("Requesting certificate reconstruction") + logrus.Info("Requesting certificate reconstruction") err = p.ser.Send(serial.ReconstructCert, nil) if err != nil { return err From 179f886a4eff6539448c8230f9c9ced9123323aa Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 16:54:40 +0200 Subject: [PATCH 05/17] Improve logs of arduino-cli This commit has two effects: - arduino-cli init command logs are masked out. - arduino-cli upload logs are logged only if logrus was already enabled. --- arduino/cli/commander.go | 11 ++++++----- cli/cli.go | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/arduino/cli/commander.go b/arduino/cli/commander.go index bd772535..c9af3542 100644 --- a/arduino/cli/commander.go +++ b/arduino/cli/commander.go @@ -3,7 +3,6 @@ package cli import ( "context" "fmt" - "io/ioutil" "os" "path/filepath" @@ -24,8 +23,8 @@ type commander struct { // programmatically call arduino-cli commands. // It directly imports the golang packages of the arduino-cli. func NewCommander() (arduino.Commander, error) { - // Discard arduino-cli log messages - logrus.SetOutput(ioutil.Discard) + // Discard arduino-cli log info messages + logrus.SetLevel(logrus.PanicLevel) // Initialize arduino-cli configuration configuration.Settings = configuration.Init(configuration.FindConfigFileInArgsOrWorkingDirectory(os.Args)) // Create arduino-cli instance, needed to execute arduino-cli commands @@ -35,6 +34,8 @@ func NewCommander() (arduino.Commander, error) { return nil, err } + // Re-enable info level log + logrus.SetLevel(logrus.InfoLevel) cmd := &commander{inst} return cmd, nil } @@ -62,10 +63,10 @@ func (c *commander) UploadBin(fqbn, bin, port string) error { Verbose: false, } - if _, err := upload.Upload(context.Background(), req, os.Stdout, os.Stderr); err != nil { + l := logrus.StandardLogger().Writer() + if _, err := upload.Upload(context.Background(), req, l, l); err != nil { err = fmt.Errorf("%s: %w", "uploading binary", err) return err } - return nil } diff --git a/cli/cli.go b/cli/cli.go index 91d64e61..5ef06303 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -11,7 +11,6 @@ import ( "github.com/arduino/iot-cloud-cli/cli/config" "github.com/arduino/iot-cloud-cli/cli/device" "github.com/arduino/iot-cloud-cli/cli/thing" - "github.com/mattn/go-colorable" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -51,16 +50,17 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) { } func preRun(cmd *cobra.Command, args []string) { - // decide whether we should log to stdout + // enable log if verbose flag is passed if cliFlags.verbose { - // if we print on stdout, do it in full colors - logrus.SetOutput(colorable.NewColorableStdout()) + logrus.SetLevel(logrus.InfoLevel) + logrus.SetOutput(os.Stdout) logrus.SetFormatter(&logrus.TextFormatter{ - ForceColors: true, + ForceColors: false, }) } else { logrus.SetOutput(ioutil.Discard) } + // logrus. // normalize the format strings cliFlags.outputFormat = strings.ToLower(cliFlags.outputFormat) From 9c719b1febfe006fa80b7b3e7ac510f6864b9e1a Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 16:56:13 +0200 Subject: [PATCH 06/17] Fix log msg --- command/device/provision.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/command/device/provision.go b/command/device/provision.go index 90d7bfea..017b2d29 100644 --- a/command/device/provision.go +++ b/command/device/provision.go @@ -37,10 +37,10 @@ func (p provision) run() error { return err } - logrus.Infof("\n%s\n", "Uploading provisioning sketch on the board") + logrus.Infof("%s\n", "Uploading provisioning sketch on the board") time.Sleep(500 * time.Millisecond) // Try to upload the provisioning sketch - errMsg := "Error while uploading the provisioning sketch: " + errMsg := "Error while uploading the provisioning sketch" err = retry(5, time.Millisecond*1000, errMsg, func() error { //serialutils.Reset(dev.port, true, nil) return p.UploadBin(p.board.fqbn, bin, p.board.port) @@ -49,11 +49,11 @@ func (p provision) run() error { return err } - logrus.Infof("\n%s\n", "Connecting to the board through serial port") + logrus.Infof("%s\n", "Connecting to the board through serial port") // Try to connect to board through the serial port time.Sleep(1500 * time.Millisecond) p.ser = serial.NewSerial() - errMsg = "Error while connecting to the board: " + errMsg = "Error while connecting to the board" err = retry(5, time.Millisecond*1000, errMsg, func() error { return p.ser.Connect(p.board.port) }) @@ -255,7 +255,7 @@ func retry(tries int, sleep time.Duration, errMsg string, fun func() error) erro if err == nil { break } - logrus.Warningf(errMsg, err.Error(), "\nTrying again...") + logrus.Warningf("%s: %s: %s", errMsg, err.Error(), "\nTrying again...") time.Sleep(sleep) } return err From 66903069161c91691eb06a55185e0eb99cdebf35 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 16:58:06 +0200 Subject: [PATCH 07/17] Update go mod --- go.mod | 2 +- go.sum | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 18c9a4c6..d272dbff 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/arduino/go-paths-helper v1.6.0 github.com/arduino/iot-client-go v1.3.4-0.20210902151346-1cd63fb0c784 github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 - github.com/sirupsen/logrus v1.4.2 + github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.1.3 github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum index 76cd352d..ad9e7e37 100644 --- a/go.sum +++ b/go.sum @@ -255,7 +255,6 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -345,8 +344,9 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -531,6 +531,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From 69d71b0378124f6ffd74dfbd9e875bb53c87dffa Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 17:33:59 +0200 Subject: [PATCH 08/17] Improve thing output format --- cli/thing/clone.go | 20 ++++++++++++++++++-- cli/thing/create.go | 20 ++++++++++++++++++-- command/thing/clone.go | 18 ++++++++++++------ command/thing/create.go | 20 +++++++++++++------- 4 files changed, 61 insertions(+), 17 deletions(-) diff --git a/cli/thing/clone.go b/cli/thing/clone.go index bca8e2e6..c18b43c9 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -1,6 +1,9 @@ package thing import ( + "fmt" + + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -33,11 +36,24 @@ func runCloneCommand(cmd *cobra.Command, args []string) error { CloneID: cloneFlags.cloneID, } - thingID, err := thing.Clone(params) + thing, err := thing.Clone(params) if err != nil { return err } - logrus.Infof("IoT Cloud thing created with ID: %s\n", thingID) + logrus.Infof("IoT Cloud thing created with ID: %s", thing.ID) + feedback.PrintResult(cloneResult{thing}) return nil } + +type cloneResult struct { + thing *thing.ThingInfo +} + +func (r cloneResult) Data() interface{} { + return r.thing +} + +func (r cloneResult) String() string { + return fmt.Sprintf("IoT Cloud thing created with ID: %s", r.thing.ID) +} diff --git a/cli/thing/create.go b/cli/thing/create.go index 1ea3537d..710dfbc1 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -1,6 +1,9 @@ package thing import ( + "fmt" + + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -40,11 +43,24 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { params.Name = &createFlags.name } - thingID, err := thing.Create(params) + thing, err := thing.Create(params) if err != nil { return err } - logrus.Infof("IoT Cloud thing created with ID: %s\n", thingID) + logrus.Infof("IoT Cloud thing created with ID: %s\n", thing.ID) + feedback.PrintResult(createResult{thing}) return nil } + +type createResult struct { + thing *thing.ThingInfo +} + +func (r createResult) Data() interface{} { + return r.thing +} + +func (r createResult) String() string { + return fmt.Sprintf("IoT Cloud thing created with ID: %s", r.thing.ID) +} diff --git a/command/thing/clone.go b/command/thing/clone.go index cbf239f5..23f6714b 100644 --- a/command/thing/clone.go +++ b/command/thing/clone.go @@ -17,29 +17,35 @@ type CloneParams struct { } // Clone allows to create a new thing from an already existing one -func Clone(params *CloneParams) (string, error) { +func Clone(params *CloneParams) (*ThingInfo, error) { conf, err := config.Retrieve() if err != nil { - return "", err + return nil, err } iotClient, err := iot.NewClient(conf.Client, conf.Secret) if err != nil { - return "", err + return nil, err } thing, err := retrieve(iotClient, params.CloneID) if err != nil { - return "", err + return nil, err } thing.Name = params.Name force := true thingID, err := iotClient.ThingCreate(thing, force) if err != nil { - return "", err + return nil, err } - return thingID, nil + thingInfo := &ThingInfo{ + Name: thing.Name, + ID: thingID, + DeviceID: thing.DeviceId, + Variables: nil, + } + return thingInfo, nil } func retrieve(client iot.Client, thingID string) (*iotclient.Thing, error) { diff --git a/command/thing/create.go b/command/thing/create.go index 22feb62c..6dee6313 100644 --- a/command/thing/create.go +++ b/command/thing/create.go @@ -22,19 +22,19 @@ type CreateParams struct { } // Create allows to create a new thing -func Create(params *CreateParams) (string, error) { +func Create(params *CreateParams) (*ThingInfo, error) { conf, err := config.Retrieve() if err != nil { - return "", err + return nil, err } iotClient, err := iot.NewClient(conf.Client, conf.Secret) if err != nil { - return "", err + return nil, err } thing, err := loadTemplate(params.Template) if err != nil { - return "", err + return nil, err } // Name passed as parameter has priority over name from template @@ -43,16 +43,22 @@ func Create(params *CreateParams) (string, error) { } // If name is not specified in the template, it should be passed as parameter if thing.Name == "" { - return "", errors.New("thing name not specified") + return nil, errors.New("thing name not specified") } force := true thingID, err := iotClient.ThingCreate(thing, force) if err != nil { - return "", err + return nil, err } - return thingID, nil + thingInfo := &ThingInfo{ + Name: thing.Name, + ID: thingID, + DeviceID: thing.DeviceId, + Variables: nil, + } + return thingInfo, nil } func loadTemplate(file string) (*iotclient.Thing, error) { From 493689c378e222c36973c6f86d046254314592fc Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 18:02:36 +0200 Subject: [PATCH 09/17] Refactor thing output format --- command/thing/clone.go | 10 ++-------- command/thing/create.go | 10 ++-------- command/thing/list.go | 22 ++-------------------- command/thing/thing.go | 26 ++++++++++++++++++++++++++ internal/iot/client.go | 8 ++++---- 5 files changed, 36 insertions(+), 40 deletions(-) create mode 100644 command/thing/thing.go diff --git a/command/thing/clone.go b/command/thing/clone.go index 23f6714b..abac6046 100644 --- a/command/thing/clone.go +++ b/command/thing/clone.go @@ -34,18 +34,12 @@ func Clone(params *CloneParams) (*ThingInfo, error) { thing.Name = params.Name force := true - thingID, err := iotClient.ThingCreate(thing, force) + newThing, err := iotClient.ThingCreate(thing, force) if err != nil { return nil, err } - thingInfo := &ThingInfo{ - Name: thing.Name, - ID: thingID, - DeviceID: thing.DeviceId, - Variables: nil, - } - return thingInfo, nil + return getThingInfo(newThing), nil } func retrieve(client iot.Client, thingID string) (*iotclient.Thing, error) { diff --git a/command/thing/create.go b/command/thing/create.go index 6dee6313..abd9335a 100644 --- a/command/thing/create.go +++ b/command/thing/create.go @@ -47,18 +47,12 @@ func Create(params *CreateParams) (*ThingInfo, error) { } force := true - thingID, err := iotClient.ThingCreate(thing, force) + newThing, err := iotClient.ThingCreate(thing, force) if err != nil { return nil, err } - thingInfo := &ThingInfo{ - Name: thing.Name, - ID: thingID, - DeviceID: thing.DeviceId, - Variables: nil, - } - return thingInfo, nil + return getThingInfo(newThing), nil } func loadTemplate(file string) (*iotclient.Thing, error) { diff --git a/command/thing/list.go b/command/thing/list.go index 2de5a255..c89639be 100644 --- a/command/thing/list.go +++ b/command/thing/list.go @@ -5,15 +5,6 @@ import ( "github.com/arduino/iot-cloud-cli/internal/iot" ) -// ThingInfo contains the main parameters of -// an Arduino IoT Cloud thing. -type ThingInfo struct { - Name string - ID string - DeviceID string - Variables []string -} - // ListParams contains the optional parameters needed // to filter the things to be listed. // If IDs is valid, only things belonging to that list are listed. @@ -44,17 +35,8 @@ func List(params *ListParams) ([]ThingInfo, error) { var things []ThingInfo for _, foundThing := range foundThings { - var vars []string - for _, p := range foundThing.Properties { - vars = append(vars, p.Name) - } - th := ThingInfo{ - Name: foundThing.Name, - ID: foundThing.Id, - DeviceID: foundThing.DeviceId, - Variables: vars, - } - things = append(things, th) + info := getThingInfo(&foundThing) + things = append(things, *info) } return things, nil diff --git a/command/thing/thing.go b/command/thing/thing.go new file mode 100644 index 00000000..076570d1 --- /dev/null +++ b/command/thing/thing.go @@ -0,0 +1,26 @@ +package thing + +import iotclient "github.com/arduino/iot-client-go" + +// ThingInfo contains the main parameters of +// an Arduino IoT Cloud thing. +type ThingInfo struct { + Name string + ID string + DeviceID string + Variables []string +} + +func getThingInfo(thing *iotclient.ArduinoThing) *ThingInfo { + var vars []string + for _, p := range thing.Properties { + vars = append(vars, p.Name) + } + info := &ThingInfo{ + Name: thing.Name, + ID: thing.Id, + DeviceID: thing.DeviceId, + Variables: vars, + } + return info +} diff --git a/internal/iot/client.go b/internal/iot/client.go index f0332581..5b6fe2b0 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -15,7 +15,7 @@ type Client interface { DeviceList() ([]iotclient.ArduinoDevicev2, error) DeviceShow(id string) (*iotclient.ArduinoDevicev2, error) CertificateCreate(id, csr string) (*iotclient.ArduinoCompressedv2, error) - ThingCreate(thing *iotclient.Thing, force bool) (string, error) + ThingCreate(thing *iotclient.Thing, force bool) (*iotclient.ArduinoThing, error) ThingUpdate(id string, thing *iotclient.Thing, force bool) error ThingDelete(id string) error ThingShow(id string) (*iotclient.ArduinoThing, error) @@ -108,13 +108,13 @@ func (cl *client) CertificateCreate(id, csr string) (*iotclient.ArduinoCompresse } // ThingCreate adds a new thing on Arduino IoT Cloud. -func (cl *client) ThingCreate(thing *iotclient.Thing, force bool) (string, error) { +func (cl *client) ThingCreate(thing *iotclient.Thing, force bool) (*iotclient.ArduinoThing, error) { opt := &iotclient.ThingsV2CreateOpts{Force: optional.NewBool(force)} newThing, _, err := cl.api.ThingsV2Api.ThingsV2Create(cl.ctx, *thing, opt) if err != nil { - return "", fmt.Errorf("%s: %w", "adding new thing", errorDetail(err)) + return nil, fmt.Errorf("%s: %w", "adding new thing", errorDetail(err)) } - return newThing.Id, nil + return &newThing, nil } // ThingUpdate updates a thing on Arduino IoT Cloud. From 29b415de70f274aed50502bbf4744522eeb85ec5 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Wed, 8 Sep 2021 18:03:17 +0200 Subject: [PATCH 10/17] Fix device iot client --- internal/iot/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/iot/client.go b/internal/iot/client.go index 5b6fe2b0..8f52f07c 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -40,7 +40,7 @@ func NewClient(clientID, secretID string) (Client, error) { } // DeviceCreate allows to create a new device on Arduino IoT Cloud. -// It returns the ID associated to the new device, and an error. +// It returns the newly created device, and an error. func (cl *client) DeviceCreate(fqbn, name, serial, dType string) (*iotclient.ArduinoDevicev2, error) { payload := iotclient.CreateDevicesV2Payload{ Fqbn: fqbn, From 370916c94b612175efec7d9edd3faa4f91419714 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 10:59:37 +0200 Subject: [PATCH 11/17] Improve errors: use stderr and error codes --- cli/config/config.go | 14 ++++++++------ cli/device/create.go | 5 ++++- cli/device/delete.go | 7 ++++++- cli/device/list.go | 6 +++++- cli/thing/bind.go | 7 ++++++- cli/thing/clone.go | 5 ++++- cli/thing/create.go | 5 ++++- cli/thing/delete.go | 7 ++++++- cli/thing/extract.go | 7 ++++++- cli/thing/list.go | 5 ++++- 10 files changed, 53 insertions(+), 15 deletions(-) diff --git a/cli/config/config.go b/cli/config/config.go index 3e9b92b7..a1556068 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -1,9 +1,10 @@ package config import ( - "fmt" + "os" "strings" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" paths "github.com/arduino/go-paths-helper" "github.com/arduino/iot-cloud-cli/command/config" @@ -33,7 +34,8 @@ func NewCommand() *cobra.Command { func runConfigCommand(cmd *cobra.Command, args []string) error { if configFlags.file == "" && (configFlags.client == "" || configFlags.secret == "") { - return fmt.Errorf("%s", "Provide either a yaml file or credentials\n") + feedback.Error("Error during config: provide either a yaml file or credentials") + os.Exit(errorcodes.ErrGeneric) } conf := viper.New() @@ -46,8 +48,8 @@ func runConfigCommand(cmd *cobra.Command, args []string) error { conf.AddConfigPath(".") err := conf.ReadInConfig() if err != nil { - feedback.Errorf("Fatal error config file: %v", err) - return err + feedback.Errorf("Error during config: fatal error config file: %v", err) + os.Exit(errorcodes.ErrGeneric) } } else { @@ -57,8 +59,8 @@ func runConfigCommand(cmd *cobra.Command, args []string) error { err := config.Config(conf) if err != nil { - feedback.Errorf("Storing config file: %v", err) - return err + feedback.Errorf("Error during config: storing config file: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Info("Configuration file updated") diff --git a/cli/device/create.go b/cli/device/create.go index f5a33000..25343361 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -2,7 +2,9 @@ package device import ( "fmt" + "os" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/device" "github.com/sirupsen/logrus" @@ -44,7 +46,8 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { dev, err := device.Create(params) if err != nil { - return err + feedback.Errorf("Error during device create: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Infof("IoT Cloud device created with ID: %s\n", dev.ID) diff --git a/cli/device/delete.go b/cli/device/delete.go index 41eddb93..beaec5e3 100644 --- a/cli/device/delete.go +++ b/cli/device/delete.go @@ -1,6 +1,10 @@ package device import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/device" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -28,7 +32,8 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { params := &device.DeleteParams{ID: deleteFlags.id} err := device.Delete(params) if err != nil { - return err + feedback.Errorf("Error during device delete: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Info("Device successfully deleted") diff --git a/cli/device/list.go b/cli/device/list.go index fabf9aab..acc1c6fe 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -1,6 +1,9 @@ package device import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/table" "github.com/arduino/iot-cloud-cli/command/device" @@ -23,7 +26,8 @@ func runListCommand(cmd *cobra.Command, args []string) error { devs, err := device.List() if err != nil { - return err + feedback.Errorf("Error during device list: %v", err) + os.Exit(errorcodes.ErrGeneric) } feedback.PrintResult(listResult{devs}) diff --git a/cli/thing/bind.go b/cli/thing/bind.go index 3e000de8..88277864 100644 --- a/cli/thing/bind.go +++ b/cli/thing/bind.go @@ -1,6 +1,10 @@ package thing import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -34,7 +38,8 @@ func runBindCommand(cmd *cobra.Command, args []string) error { } err := thing.Bind(params) if err != nil { - return err + feedback.Errorf("Error during thing bind: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Info("Thing-Device bound successfully updated") diff --git a/cli/thing/clone.go b/cli/thing/clone.go index c18b43c9..611b4d83 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -2,7 +2,9 @@ package thing import ( "fmt" + "os" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" @@ -38,7 +40,8 @@ func runCloneCommand(cmd *cobra.Command, args []string) error { thing, err := thing.Clone(params) if err != nil { - return err + feedback.Errorf("Error during thing clone: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Infof("IoT Cloud thing created with ID: %s", thing.ID) diff --git a/cli/thing/create.go b/cli/thing/create.go index 710dfbc1..048f464d 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -2,7 +2,9 @@ package thing import ( "fmt" + "os" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" @@ -45,7 +47,8 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { thing, err := thing.Create(params) if err != nil { - return err + feedback.Errorf("Error during thing create: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Infof("IoT Cloud thing created with ID: %s\n", thing.ID) diff --git a/cli/thing/delete.go b/cli/thing/delete.go index 182cfa06..c57fac84 100644 --- a/cli/thing/delete.go +++ b/cli/thing/delete.go @@ -1,6 +1,10 @@ package thing import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -28,7 +32,8 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { params := &thing.DeleteParams{ID: deleteFlags.id} err := thing.Delete(params) if err != nil { - return err + feedback.Errorf("Error during thing delete: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Info("Thing successfully deleted") diff --git a/cli/thing/extract.go b/cli/thing/extract.go index 1e442c6d..66bbf115 100644 --- a/cli/thing/extract.go +++ b/cli/thing/extract.go @@ -1,6 +1,10 @@ package thing import ( + "os" + + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/iot-cloud-cli/command/thing" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -45,7 +49,8 @@ func runExtractCommand(cmd *cobra.Command, args []string) error { err := thing.Extract(params) if err != nil { - return err + feedback.Errorf("Error during template extraction: %v", err) + os.Exit(errorcodes.ErrGeneric) } logrus.Info("Template successfully extracted") diff --git a/cli/thing/list.go b/cli/thing/list.go index ad5774b3..5a2fae04 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -1,8 +1,10 @@ package thing import ( + "os" "strings" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/table" "github.com/arduino/iot-cloud-cli/command/thing" @@ -44,7 +46,8 @@ func runListCommand(cmd *cobra.Command, args []string) error { things, err := thing.List(params) if err != nil { - return err + feedback.Errorf("Error during thing list: %v", err) + os.Exit(errorcodes.ErrGeneric) } feedback.PrintResult(result{things}) From c318bbcf76f1f624d96262179a5080ee1f768d37 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 11:05:22 +0200 Subject: [PATCH 12/17] cli package: don't return error --- cli/config/config.go | 5 ++--- cli/device/create.go | 6 ++---- cli/device/delete.go | 5 ++--- cli/device/list.go | 6 ++---- cli/thing/bind.go | 5 ++--- cli/thing/clone.go | 5 ++--- cli/thing/create.go | 5 ++--- cli/thing/delete.go | 5 ++--- cli/thing/extract.go | 5 ++--- cli/thing/list.go | 5 ++--- 10 files changed, 20 insertions(+), 32 deletions(-) diff --git a/cli/config/config.go b/cli/config/config.go index a1556068..f2de8b18 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -24,7 +24,7 @@ func NewCommand() *cobra.Command { Use: "config", Short: "Set the configuration file", Long: "Set the configuration file to access Arduino IoT Cloud", - RunE: runConfigCommand, + Run: runConfigCommand, } configCommand.Flags().StringVarP(&configFlags.file, "file", "f", "", "Existing configuration yaml file") configCommand.Flags().StringVarP(&configFlags.client, "client", "c", "", "Client ID") @@ -32,7 +32,7 @@ func NewCommand() *cobra.Command { return configCommand } -func runConfigCommand(cmd *cobra.Command, args []string) error { +func runConfigCommand(cmd *cobra.Command, args []string) { if configFlags.file == "" && (configFlags.client == "" || configFlags.secret == "") { feedback.Error("Error during config: provide either a yaml file or credentials") os.Exit(errorcodes.ErrGeneric) @@ -64,5 +64,4 @@ func runConfigCommand(cmd *cobra.Command, args []string) error { } logrus.Info("Configuration file updated") - return nil } diff --git a/cli/device/create.go b/cli/device/create.go index 25343361..f0f9c5ca 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -22,7 +22,7 @@ func initCreateCommand() *cobra.Command { Use: "create", Short: "Create a device", Long: "Create a device for Arduino IoT Cloud", - RunE: runCreateCommand, + Run: runCreateCommand, } createCommand.Flags().StringVarP(&createFlags.port, "port", "p", "", "Device port") createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Device name") @@ -31,7 +31,7 @@ func initCreateCommand() *cobra.Command { return createCommand } -func runCreateCommand(cmd *cobra.Command, args []string) error { +func runCreateCommand(cmd *cobra.Command, args []string) { logrus.Infof("Creating device with name %s\n", createFlags.name) params := &device.CreateParams{ @@ -52,8 +52,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { logrus.Infof("IoT Cloud device created with ID: %s\n", dev.ID) feedback.PrintResult(createResult{dev}) - - return nil } type createResult struct { diff --git a/cli/device/delete.go b/cli/device/delete.go index beaec5e3..96711106 100644 --- a/cli/device/delete.go +++ b/cli/device/delete.go @@ -19,14 +19,14 @@ func initDeleteCommand() *cobra.Command { Use: "delete", Short: "Delete a device", Long: "Delete a device from Arduino IoT Cloud", - RunE: runDeleteCommand, + Run: runDeleteCommand, } deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Device ID") deleteCommand.MarkFlagRequired("id") return deleteCommand } -func runDeleteCommand(cmd *cobra.Command, args []string) error { +func runDeleteCommand(cmd *cobra.Command, args []string) { logrus.Infof("Deleting device %s\n", deleteFlags.id) params := &device.DeleteParams{ID: deleteFlags.id} @@ -37,5 +37,4 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { } logrus.Info("Device successfully deleted") - return nil } diff --git a/cli/device/list.go b/cli/device/list.go index acc1c6fe..6e959410 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -16,12 +16,12 @@ func initListCommand() *cobra.Command { Use: "list", Short: "List devices", Long: "List devices on Arduino IoT Cloud", - RunE: runListCommand, + Run: runListCommand, } return listCommand } -func runListCommand(cmd *cobra.Command, args []string) error { +func runListCommand(cmd *cobra.Command, args []string) { logrus.Info("Listing devices") devs, err := device.List() @@ -31,8 +31,6 @@ func runListCommand(cmd *cobra.Command, args []string) error { } feedback.PrintResult(listResult{devs}) - - return nil } type listResult struct { diff --git a/cli/thing/bind.go b/cli/thing/bind.go index 88277864..e3198329 100644 --- a/cli/thing/bind.go +++ b/cli/thing/bind.go @@ -20,7 +20,7 @@ func initBindCommand() *cobra.Command { Use: "bind", Short: "Bind a thing to a device", Long: "Bind a thing to a device on Arduino IoT Cloud", - RunE: runBindCommand, + Run: runBindCommand, } bindCommand.Flags().StringVarP(&bindFlags.id, "id", "i", "", "Thing ID") bindCommand.Flags().StringVarP(&bindFlags.deviceID, "device-id", "d", "", "Device ID") @@ -29,7 +29,7 @@ func initBindCommand() *cobra.Command { return bindCommand } -func runBindCommand(cmd *cobra.Command, args []string) error { +func runBindCommand(cmd *cobra.Command, args []string) { logrus.Infof("Binding thing %s to device %s\n", bindFlags.id, bindFlags.deviceID) params := &thing.BindParams{ @@ -43,5 +43,4 @@ func runBindCommand(cmd *cobra.Command, args []string) error { } logrus.Info("Thing-Device bound successfully updated") - return nil } diff --git a/cli/thing/clone.go b/cli/thing/clone.go index 611b4d83..5646e428 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -21,7 +21,7 @@ func initCloneCommand() *cobra.Command { Use: "clone", Short: "Clone a thing", Long: "Clone a thing for Arduino IoT Cloud", - RunE: runCloneCommand, + Run: runCloneCommand, } cloneCommand.Flags().StringVarP(&cloneFlags.name, "name", "n", "", "Thing name") cloneCommand.Flags().StringVarP(&cloneFlags.cloneID, "clone-id", "c", "", "ID of Thing to be cloned") @@ -30,7 +30,7 @@ func initCloneCommand() *cobra.Command { return cloneCommand } -func runCloneCommand(cmd *cobra.Command, args []string) error { +func runCloneCommand(cmd *cobra.Command, args []string) { logrus.Infof("Cloning thing %s into a new thing called %s\n", cloneFlags.cloneID, cloneFlags.name) params := &thing.CloneParams{ @@ -46,7 +46,6 @@ func runCloneCommand(cmd *cobra.Command, args []string) error { logrus.Infof("IoT Cloud thing created with ID: %s", thing.ID) feedback.PrintResult(cloneResult{thing}) - return nil } type cloneResult struct { diff --git a/cli/thing/create.go b/cli/thing/create.go index 048f464d..c7d4b03d 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -21,7 +21,7 @@ func initCreateCommand() *cobra.Command { Use: "create", Short: "Create a thing from a template", Long: "Create a thing from a template for Arduino IoT Cloud", - RunE: runCreateCommand, + Run: runCreateCommand, } createCommand.Flags().StringVarP(&createFlags.name, "name", "n", "", "Thing name") createCommand.Flags().StringVarP( @@ -35,7 +35,7 @@ func initCreateCommand() *cobra.Command { return createCommand } -func runCreateCommand(cmd *cobra.Command, args []string) error { +func runCreateCommand(cmd *cobra.Command, args []string) { logrus.Infof("Creating thing from template %s\n", createFlags.template) params := &thing.CreateParams{ @@ -53,7 +53,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) error { logrus.Infof("IoT Cloud thing created with ID: %s\n", thing.ID) feedback.PrintResult(createResult{thing}) - return nil } type createResult struct { diff --git a/cli/thing/delete.go b/cli/thing/delete.go index c57fac84..e6cdecf7 100644 --- a/cli/thing/delete.go +++ b/cli/thing/delete.go @@ -19,14 +19,14 @@ func initDeleteCommand() *cobra.Command { Use: "delete", Short: "Delete a thing", Long: "Delete a thing from Arduino IoT Cloud", - RunE: runDeleteCommand, + Run: runDeleteCommand, } deleteCommand.Flags().StringVarP(&deleteFlags.id, "id", "i", "", "Thing ID") deleteCommand.MarkFlagRequired("id") return deleteCommand } -func runDeleteCommand(cmd *cobra.Command, args []string) error { +func runDeleteCommand(cmd *cobra.Command, args []string) { logrus.Infof("Deleting thing %s\n", deleteFlags.id) params := &thing.DeleteParams{ID: deleteFlags.id} @@ -37,5 +37,4 @@ func runDeleteCommand(cmd *cobra.Command, args []string) error { } logrus.Info("Thing successfully deleted") - return nil } diff --git a/cli/thing/extract.go b/cli/thing/extract.go index 66bbf115..2dc0cf29 100644 --- a/cli/thing/extract.go +++ b/cli/thing/extract.go @@ -21,7 +21,7 @@ func initExtractCommand() *cobra.Command { Use: "extract", Short: "Extract a template from a thing", Long: "Extract a template from a Arduino IoT Cloud thing and save it in a file", - RunE: runExtractCommand, + Run: runExtractCommand, } extractCommand.Flags().StringVarP(&extractFlags.id, "id", "i", "", "Thing ID") extractCommand.Flags().StringVarP(&extractFlags.outfile, "outfile", "o", "", "Template file destination path") @@ -36,7 +36,7 @@ func initExtractCommand() *cobra.Command { return extractCommand } -func runExtractCommand(cmd *cobra.Command, args []string) error { +func runExtractCommand(cmd *cobra.Command, args []string) { logrus.Infof("Extracting template from thing %s\n", extractFlags.id) params := &thing.ExtractParams{ @@ -54,5 +54,4 @@ func runExtractCommand(cmd *cobra.Command, args []string) error { } logrus.Info("Template successfully extracted") - return nil } diff --git a/cli/thing/list.go b/cli/thing/list.go index 5a2fae04..ee9a2137 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -23,7 +23,7 @@ func initListCommand() *cobra.Command { Use: "list", Short: "List things", Long: "List things on Arduino IoT Cloud", - RunE: runListCommand, + Run: runListCommand, } // list only the things corresponding to the passed ids listCommand.Flags().StringSliceVarP(&listFlags.ids, "ids", "i", []string{}, "List of thing IDs to be retrieved") @@ -33,7 +33,7 @@ func initListCommand() *cobra.Command { return listCommand } -func runListCommand(cmd *cobra.Command, args []string) error { +func runListCommand(cmd *cobra.Command, args []string) { logrus.Info("Listing things") params := &thing.ListParams{ @@ -51,7 +51,6 @@ func runListCommand(cmd *cobra.Command, args []string) error { } feedback.PrintResult(result{things}) - return nil } type result struct { From 37bd229a3eaa7687ecb4ac485a010a34d73fd857 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 18:50:06 +0200 Subject: [PATCH 13/17] Remove unreachable code --- cli/cli.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 5ef06303..7f8619ae 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -72,12 +72,4 @@ func preRun(cmd *cobra.Command, args []string) { } // use the output format to configure the Feedback feedback.SetFormat(format) - - if cliFlags.outputFormat != "text" { - cmd.SetHelpFunc(func(cmd *cobra.Command, args []string) { - logrus.Warn("Calling help on JSON format") - feedback.Error("Invalid Call : should show Help, but it is available only in TEXT mode.") - os.Exit(errorcodes.ErrBadCall) - }) - } } From 887249d6a4fac54e23caead6e7e03dd0762df53b Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 18:52:47 +0200 Subject: [PATCH 14/17] Improve log initialization --- cli/cli.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 7f8619ae..afb1ddf5 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -50,17 +50,12 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) { } func preRun(cmd *cobra.Command, args []string) { - // enable log if verbose flag is passed + logrus.SetOutput(ioutil.Discard) + // enable log only if verbose flag is passed if cliFlags.verbose { logrus.SetLevel(logrus.InfoLevel) logrus.SetOutput(os.Stdout) - logrus.SetFormatter(&logrus.TextFormatter{ - ForceColors: false, - }) - } else { - logrus.SetOutput(ioutil.Discard) } - // logrus. // normalize the format strings cliFlags.outputFormat = strings.ToLower(cliFlags.outputFormat) From 01c92f0cf4c026b04dccf58edf71a80e33e96495 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 18:57:23 +0200 Subject: [PATCH 15/17] Remove duplication of info messages --- cli/device/create.go | 3 +-- cli/thing/clone.go | 1 - cli/thing/create.go | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/cli/device/create.go b/cli/device/create.go index f0f9c5ca..7fe8ae18 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -50,7 +50,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - logrus.Infof("IoT Cloud device created with ID: %s\n", dev.ID) feedback.PrintResult(createResult{dev}) } @@ -63,5 +62,5 @@ func (r createResult) Data() interface{} { } func (r createResult) String() string { - return fmt.Sprintf("IoT Cloud device created with ID: %s\n", r.device.ID) + return fmt.Sprintf("IoT Cloud device created with ID: %s", r.device.ID) } diff --git a/cli/thing/clone.go b/cli/thing/clone.go index 5646e428..f6f59ce9 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -44,7 +44,6 @@ func runCloneCommand(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - logrus.Infof("IoT Cloud thing created with ID: %s", thing.ID) feedback.PrintResult(cloneResult{thing}) } diff --git a/cli/thing/create.go b/cli/thing/create.go index c7d4b03d..8d4e4134 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -51,7 +51,6 @@ func runCreateCommand(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrGeneric) } - logrus.Infof("IoT Cloud thing created with ID: %s\n", thing.ID) feedback.PrintResult(createResult{thing}) } From 1787c4fdc106e38bda8f7f11462243c7608a930d Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 18:59:59 +0200 Subject: [PATCH 16/17] Add arduino-cli source to upload logs --- arduino/cli/commander.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arduino/cli/commander.go b/arduino/cli/commander.go index c9af3542..f7590ef5 100644 --- a/arduino/cli/commander.go +++ b/arduino/cli/commander.go @@ -63,7 +63,7 @@ func (c *commander) UploadBin(fqbn, bin, port string) error { Verbose: false, } - l := logrus.StandardLogger().Writer() + l := logrus.StandardLogger().WithField("source", "arduino-cli").Writer() if _, err := upload.Upload(context.Background(), req, l, l); err != nil { err = fmt.Errorf("%s: %w", "uploading binary", err) return err From 5d10e449c91c08ec22febe6ea0b2845555932e00 Mon Sep 17 00:00:00 2001 From: Paolo Calao Date: Fri, 10 Sep 2021 19:43:00 +0200 Subject: [PATCH 17/17] Return consistent output --- cli/device/create.go | 9 ++++++++- cli/thing/clone.go | 9 ++++++++- cli/thing/create.go | 9 ++++++++- command/device/list.go | 10 +++++----- command/thing/thing.go | 8 ++++---- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/cli/device/create.go b/cli/device/create.go index 7fe8ae18..c472206f 100644 --- a/cli/device/create.go +++ b/cli/device/create.go @@ -62,5 +62,12 @@ func (r createResult) Data() interface{} { } func (r createResult) String() string { - return fmt.Sprintf("IoT Cloud device created with ID: %s", r.device.ID) + return fmt.Sprintf( + "name: %s\nid: %s\nboard: %s\nserial-number: %s\nfqbn: %s", + r.device.Name, + r.device.ID, + r.device.Board, + r.device.Serial, + r.device.FQBN, + ) } diff --git a/cli/thing/clone.go b/cli/thing/clone.go index f6f59ce9..4e9aed8c 100644 --- a/cli/thing/clone.go +++ b/cli/thing/clone.go @@ -3,6 +3,7 @@ package thing import ( "fmt" "os" + "strings" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" @@ -56,5 +57,11 @@ func (r cloneResult) Data() interface{} { } func (r cloneResult) String() string { - return fmt.Sprintf("IoT Cloud thing created with ID: %s", r.thing.ID) + return fmt.Sprintf( + "name: %s\nid: %s\ndevice-id: %s\nvariables: %s", + r.thing.Name, + r.thing.ID, + r.thing.DeviceID, + strings.Join(r.thing.Variables, ", "), + ) } diff --git a/cli/thing/create.go b/cli/thing/create.go index 8d4e4134..78bd20bd 100644 --- a/cli/thing/create.go +++ b/cli/thing/create.go @@ -3,6 +3,7 @@ package thing import ( "fmt" "os" + "strings" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" @@ -63,5 +64,11 @@ func (r createResult) Data() interface{} { } func (r createResult) String() string { - return fmt.Sprintf("IoT Cloud thing created with ID: %s", r.thing.ID) + return fmt.Sprintf( + "name: %s\nid: %s\ndevice-id: %s\nvariables: %s", + r.thing.Name, + r.thing.ID, + r.thing.DeviceID, + strings.Join(r.thing.Variables, ", "), + ) } diff --git a/command/device/list.go b/command/device/list.go index 82e8e438..d568c13f 100644 --- a/command/device/list.go +++ b/command/device/list.go @@ -8,11 +8,11 @@ import ( // DeviceInfo contains the most interesting // parameters of an Arduino IoT Cloud device. type DeviceInfo struct { - Name string - ID string - Board string - Serial string - FQBN string + Name string `json:"name"` + ID string `json:"id"` + Board string `json:"board"` + Serial string `json:"serial-number"` + FQBN string `json:"fqbn"` } // List command is used to list diff --git a/command/thing/thing.go b/command/thing/thing.go index 076570d1..df3552bb 100644 --- a/command/thing/thing.go +++ b/command/thing/thing.go @@ -5,10 +5,10 @@ import iotclient "github.com/arduino/iot-client-go" // ThingInfo contains the main parameters of // an Arduino IoT Cloud thing. type ThingInfo struct { - Name string - ID string - DeviceID string - Variables []string + Name string `json:"name"` + ID string `json:"id"` + DeviceID string `json:"device-id"` + Variables []string `json:"variables"` } func getThingInfo(thing *iotclient.ArduinoThing) *ThingInfo {