Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 475f6a7

Browse files
committedNov 12, 2021
Print feedbacks about successful, fail and invalid ota reqs
1 parent e5c6d9e commit 475f6a7

File tree

3 files changed

+73
-42
lines changed

3 files changed

+73
-42
lines changed
 

‎cli/ota/upload.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
package ota
1919

2020
import (
21+
"fmt"
2122
"os"
23+
"strings"
2224

2325
"github.com/arduino/arduino-cli/cli/errorcodes"
2426
"github.com/arduino/arduino-cli/cli/feedback"
@@ -70,11 +72,28 @@ func runUploadCommand(cmd *cobra.Command, args []string) {
7072
FQBN: uploadFlags.fqbn,
7173
}
7274

73-
err := ota.Upload(params)
75+
resp, err := ota.Upload(params)
7476
if err != nil {
7577
feedback.Errorf("Error during ota upload: %v", err)
7678
os.Exit(errorcodes.ErrGeneric)
7779
}
7880

81+
devs := strings.Join(resp.Updated, ",")
82+
devs = strings.TrimRight(devs, ",")
83+
success := fmt.Sprintf("Successfully sent OTA request to: %s", devs)
84+
85+
devs = strings.Join(resp.Invalid, ",")
86+
devs = strings.TrimRight(devs, ",")
87+
invalid := fmt.Sprintf("Cannot send OTA request to: %s", devs)
88+
89+
devs = strings.Join(resp.Failed, ",")
90+
devs = strings.TrimRight(devs, ",")
91+
fail := fmt.Sprintf("Failed to send OTA request to: %s", devs)
92+
93+
det := strings.Join(resp.Errors, "\n")
94+
det = strings.TrimRight(det, ",")
95+
details := fmt.Sprintf("\nDetails:\n%s", det)
96+
97+
feedback.Printf(success, invalid, fail, details)
7998
logrus.Info("Upload successfully started")
8099
}

‎command/ota/upload.go

+50-36
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ import (
2323
"io/ioutil"
2424
"os"
2525
"path/filepath"
26-
"strings"
2726

2827
"github.com/arduino/arduino-cloud-cli/internal/config"
2928
"github.com/arduino/arduino-cloud-cli/internal/iot"
29+
iotclient "github.com/arduino/iot-client-go"
3030
)
3131

3232
const (
@@ -48,56 +48,77 @@ type UploadParams struct {
4848
FQBN string
4949
}
5050

51+
// UploadResp contains the results of the ota upload
52+
type UploadResp struct {
53+
Updated []string // Ids of devices updated
54+
Invalid []string // Ids of device not valid (mismatched fqbn)
55+
Failed []string // Ids of device failed
56+
Errors []string // Contains detailed errors for each failure
57+
}
58+
5159
// Upload command is used to upload a firmware OTA,
5260
// on a device of Arduino IoT Cloud.
53-
func Upload(params *UploadParams) error {
61+
func Upload(params *UploadParams) (*UploadResp, error) {
5462
if params.DeviceIDs == nil && params.Tags == nil {
55-
return errors.New("provide either DeviceID or Tags")
63+
return nil, errors.New("provide either DeviceIDs or Tags")
5664
} else if params.DeviceIDs != nil && params.Tags != nil {
57-
return errors.New("cannot use both DeviceID and Tags. only one of them should be not nil")
65+
return nil, errors.New("cannot use both DeviceIDs and Tags. only one of them should be not nil")
5866
}
5967

60-
conf, err := config.Retrieve()
68+
// Generate .ota file
69+
otaDir, err := ioutil.TempDir("", "")
6170
if err != nil {
62-
return err
71+
return nil, fmt.Errorf("%s: %w", "cannot create temporary folder", err)
6372
}
64-
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
73+
otaFile := filepath.Join(otaDir, "temp.ota")
74+
defer os.RemoveAll(otaDir)
75+
76+
err = Generate(params.File, otaFile, params.FQBN)
6577
if err != nil {
66-
return err
78+
return nil, fmt.Errorf("%s: %w", "cannot generate .ota file", err)
6779
}
6880

69-
d, err := idsGivenTags(iotClient, params.Tags)
81+
file, err := os.Open(otaFile)
7082
if err != nil {
71-
return err
72-
}
73-
devs := append(params.DeviceIDs, d...)
74-
if len(devs) == 0 {
75-
return errors.New("no device found")
83+
return nil, fmt.Errorf("%s: %w", "cannot open ota file", err)
7684
}
7785

78-
otaDir, err := ioutil.TempDir("", "")
86+
conf, err := config.Retrieve()
7987
if err != nil {
80-
return fmt.Errorf("%s: %w", "cannot create temporary folder", err)
88+
return nil, err
8189
}
82-
otaFile := filepath.Join(otaDir, "temp.ota")
83-
defer os.RemoveAll(otaDir)
84-
85-
err = Generate(params.File, otaFile, params.FQBN)
90+
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
8691
if err != nil {
87-
return fmt.Errorf("%s: %w", "cannot generate .ota file", err)
92+
return nil, err
8893
}
8994

90-
file, err := os.Open(otaFile)
95+
d, err := idsGivenTags(iotClient, params.Tags)
96+
if err != nil {
97+
return nil, err
98+
}
99+
d = append(params.DeviceIDs, d...)
100+
valid, invalid, details, err := validateDevices(iotClient, d, params.FQBN)
91101
if err != nil {
92-
return fmt.Errorf("%s: %w", "cannot open ota file", err)
102+
return nil, fmt.Errorf("failed to validate devices: %w", err)
103+
}
104+
if len(valid) == 0 {
105+
return &UploadResp{Invalid: invalid}, nil
93106
}
94107

95108
expiration := otaExpirationMins
96109
if params.Deferred {
97110
expiration = otaDeferredExpirationMins
98111
}
99112

100-
return run(iotClient, devs, file, expiration)
113+
good, fail, ers := run(iotClient, valid, file, expiration)
114+
if err != nil {
115+
return nil, err
116+
}
117+
118+
// Merge the failure details with the details of invalid devices
119+
ers = append(details, ers...)
120+
121+
return &UploadResp{Updated: good, Invalid: invalid, Failed: fail, Errors: ers}, nil
101122
}
102123

103124
func idsGivenTags(iotClient iot.Client, tags map[string]string) ([]string, error) {
@@ -168,21 +189,14 @@ func run(iotClient iot.Client, ids []string, file *os.File, expiration int) (upd
168189
}()
169190
}
170191

171-
var fails []string
172-
var details []string
173192
for range ids {
174193
r := <-results
175194
if r.err != nil {
176-
fails = append(fails, r.id)
177-
details = append(details, fmt.Sprintf("%s: %s", r.id, r.err.Error()))
195+
failed = append(failed, r.id)
196+
errors = append(errors, fmt.Sprintf("%s: %s", r.id, r.err.Error()))
197+
} else {
198+
updated = append(updated, r.id)
178199
}
179200
}
180-
181-
if len(fails) > 0 {
182-
f := strings.Join(fails, ",")
183-
f = strings.TrimRight(f, ",")
184-
d := strings.Join(details, "\n")
185-
return fmt.Errorf("failed to update these devices: %s\nreasons:\n%s", f, d)
186-
}
187-
return nil
201+
return
188202
}

‎command/ota/upload_test.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"github.com/arduino/arduino-cloud-cli/internal/iot/mocks"
12+
iotclient "github.com/arduino/iot-client-go"
1213
"github.com/stretchr/testify/mock"
1314
)
1415

@@ -23,14 +24,11 @@ func TestRun(t *testing.T) {
2324
}
2425
mockClient.On("DeviceOTA", mock.Anything, mock.Anything, mock.Anything).Return(mockDeviceOTA, nil)
2526

26-
err := run(mockClient, []string{"dont-fail", "fail-1", "dont-fail", "fail-2"}, nil, 0)
27+
good, fail, err := run(mockClient, []string{"dont-fail", "fail-1", "dont-fail", "fail-2", "dont-fail"}, nil, 0)
2728
if err == nil {
2829
t.Error("should return error")
2930
}
30-
fmt.Println(err.Error())
31-
failed := strings.Split(err.Error(), ",")
32-
if len(failed) != 2 {
33-
fmt.Println(len(failed), failed)
31+
if len(fail) != 2 {
3432
t.Error("two updates should have failed")
3533
}
3634
if len(good) != 3 {

0 commit comments

Comments
 (0)
Please sign in to comment.