diff --git a/cli/device/list.go b/cli/device/list.go index 9e7a1036..718f17f3 100644 --- a/cli/device/list.go +++ b/cli/device/list.go @@ -19,6 +19,7 @@ package device import ( "os" + "strings" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" @@ -75,7 +76,7 @@ func (r listResult) String() string { return "No devices found." } t := table.New() - t.SetHeader("Name", "ID", "Board", "FQBN", "SerialNumber") + t.SetHeader("Name", "ID", "Board", "FQBN", "SerialNumber", "Tags") for _, device := range r.devices { t.AddRow( device.Name, @@ -83,6 +84,7 @@ func (r listResult) String() string { device.Board, device.FQBN, device.Serial, + strings.Join(device.Tags, ","), ) } return t.Render() diff --git a/cli/thing/list.go b/cli/thing/list.go index ad149c60..e81e3612 100644 --- a/cli/thing/list.go +++ b/cli/thing/list.go @@ -93,7 +93,7 @@ func (r result) String() string { } t := table.New() - h := []interface{}{"Name", "ID", "Device"} + h := []interface{}{"Name", "ID", "Device", "Tags"} if listFlags.variables { h = append(h, "Variables") } @@ -101,6 +101,7 @@ func (r result) String() string { 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, ", ")) } diff --git a/command/device/device.go b/command/device/device.go new file mode 100644 index 00000000..20678449 --- /dev/null +++ b/command/device/device.go @@ -0,0 +1,52 @@ +// This file is part of arduino-cloud-cli. +// +// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package device + +import ( + "github.com/arduino/arduino-cloud-cli/command/tag" + iotclient "github.com/arduino/iot-client-go" +) + +// DeviceInfo contains the most interesting +// parameters of an Arduino IoT Cloud device. +type DeviceInfo struct { + Name string `json:"name"` + ID string `json:"id"` + Board string `json:"board"` + Serial string `json:"serial-number"` + FQBN string `json:"fqbn"` + Tags []string `json:"tags,omitempty"` +} + +func getDeviceInfo(device *iotclient.ArduinoDevicev2) (*DeviceInfo, error) { + // Retrieve device tags + tags, err := tag.TagsInfo(device.Tags) + if err != nil { + return nil, err + } + + dev := &DeviceInfo{ + Name: device.Name, + ID: device.Id, + Board: device.Type, + Serial: device.Serial, + FQBN: device.Fqbn, + Tags: tags, + } + return dev, nil +} diff --git a/command/device/list.go b/command/device/list.go index cd707521..9ace969e 100644 --- a/command/device/list.go +++ b/command/device/list.go @@ -18,20 +18,12 @@ package device import ( + "fmt" + "github.com/arduino/arduino-cloud-cli/internal/config" "github.com/arduino/arduino-cloud-cli/internal/iot" ) -// DeviceInfo contains the most interesting -// parameters of an Arduino IoT Cloud device. -type DeviceInfo struct { - Name string `json:"name"` - ID string `json:"id"` - Board string `json:"board"` - Serial string `json:"serial-number"` - FQBN string `json:"fqbn"` -} - // ListParams contains the optional parameters needed // to filter the devices to be listed. type ListParams struct { @@ -57,14 +49,11 @@ func List(params *ListParams) ([]DeviceInfo, error) { var devices []DeviceInfo for _, foundDev := range foundDevices { - dev := DeviceInfo{ - Name: foundDev.Name, - ID: foundDev.Id, - Board: foundDev.Type, - Serial: foundDev.Serial, - FQBN: foundDev.Fqbn, + dev, err := getDeviceInfo(&foundDev) + if err != nil { + return nil, fmt.Errorf("parsing device %s from cloud: %w", foundDev.Id, err) } - devices = append(devices, dev) + devices = append(devices, *dev) } return devices, nil diff --git a/command/tag/tag.go b/command/tag/tag.go new file mode 100644 index 00000000..319bb6b1 --- /dev/null +++ b/command/tag/tag.go @@ -0,0 +1,34 @@ +// This file is part of arduino-cloud-cli. +// +// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package tag + +import "fmt" + +// TagsInfo transforms tags into user-readable strings +// An error is returned if a tag value is not a string +func TagsInfo(tags map[string]interface{}) ([]string, error) { + var str []string + for key, value := range tags { + valStr, ok := value.(string) + if !ok { + return nil, fmt.Errorf("value of tag `%s` should be of type `string` but is of type `%T`", key, value) + } + str = append(str, key+"="+valStr) + } + return str, nil +} diff --git a/command/thing/clone.go b/command/thing/clone.go index d0a8c0a1..514268e8 100644 --- a/command/thing/clone.go +++ b/command/thing/clone.go @@ -54,7 +54,11 @@ func Clone(params *CloneParams) (*ThingInfo, error) { return nil, err } - return getThingInfo(newThing), nil + t, err := getThingInfo(newThing) + if err != nil { + return nil, fmt.Errorf("parsing thing %s from cloud: %w", newThing.Id, err) + } + return t, nil } func retrieve(client iot.Client, thingID string) (*iotclient.Thing, error) { diff --git a/command/thing/create.go b/command/thing/create.go index 4be2bac7..a9572146 100644 --- a/command/thing/create.go +++ b/command/thing/create.go @@ -19,6 +19,7 @@ package thing import ( "errors" + "fmt" "github.com/arduino/arduino-cloud-cli/internal/config" "github.com/arduino/arduino-cloud-cli/internal/iot" @@ -62,5 +63,9 @@ func Create(params *CreateParams) (*ThingInfo, error) { return nil, err } - return getThingInfo(newThing), nil + t, err := getThingInfo(newThing) + if err != nil { + return nil, fmt.Errorf("parsing the new thing %s from cloud: %w", newThing.Id, err) + } + return t, nil } diff --git a/command/thing/list.go b/command/thing/list.go index e0d647a7..9fc4a95b 100644 --- a/command/thing/list.go +++ b/command/thing/list.go @@ -18,6 +18,8 @@ package thing import ( + "fmt" + "github.com/arduino/arduino-cloud-cli/internal/config" "github.com/arduino/arduino-cloud-cli/internal/iot" ) @@ -50,7 +52,10 @@ func List(params *ListParams) ([]ThingInfo, error) { var things []ThingInfo for _, foundThing := range foundThings { - info := getThingInfo(&foundThing) + info, err := getThingInfo(&foundThing) + if err != nil { + return nil, fmt.Errorf("parsing thing %s from cloud: %w", foundThing.Id, err) + } things = append(things, *info) } diff --git a/command/thing/thing.go b/command/thing/thing.go index c5753de2..edbc9f6b 100644 --- a/command/thing/thing.go +++ b/command/thing/thing.go @@ -17,7 +17,10 @@ package thing -import iotclient "github.com/arduino/iot-client-go" +import ( + "github.com/arduino/arduino-cloud-cli/command/tag" + iotclient "github.com/arduino/iot-client-go" +) // ThingInfo contains the main parameters of // an Arduino IoT Cloud thing. @@ -26,18 +29,27 @@ type ThingInfo struct { ID string `json:"id"` DeviceID string `json:"device-id"` Variables []string `json:"variables"` + Tags []string `json:"tags,omitempty"` } -func getThingInfo(thing *iotclient.ArduinoThing) *ThingInfo { +func getThingInfo(thing *iotclient.ArduinoThing) (*ThingInfo, error) { + // Process thing variables var vars []string for _, p := range thing.Properties { vars = append(vars, p.Name) } + // Process thing tags + tags, err := tag.TagsInfo(thing.Tags) + if err != nil { + return nil, err + } + info := &ThingInfo{ Name: thing.Name, ID: thing.Id, DeviceID: thing.DeviceId, Variables: vars, + Tags: tags, } - return info + return info, nil }