@@ -23,10 +23,10 @@ import (
23
23
"io/ioutil"
24
24
"os"
25
25
"path/filepath"
26
- "strings"
27
26
28
27
"github.com/arduino/arduino-cloud-cli/internal/config"
29
28
"github.com/arduino/arduino-cloud-cli/internal/iot"
29
+ iotclient "github.com/arduino/iot-client-go"
30
30
)
31
31
32
32
const (
@@ -48,56 +48,77 @@ type UploadParams struct {
48
48
FQBN string
49
49
}
50
50
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
+
51
59
// Upload command is used to upload a firmware OTA,
52
60
// on a device of Arduino IoT Cloud.
53
- func Upload (params * UploadParams ) error {
61
+ func Upload (params * UploadParams ) ( * UploadResp , error ) {
54
62
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" )
56
64
} 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" )
58
66
}
59
67
60
- conf , err := config .Retrieve ()
68
+ // Generate .ota file
69
+ otaDir , err := ioutil .TempDir ("" , "" )
61
70
if err != nil {
62
- return err
71
+ return nil , fmt . Errorf ( "%s: %w" , "cannot create temporary folder" , err )
63
72
}
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 )
65
77
if err != nil {
66
- return err
78
+ return nil , fmt . Errorf ( "%s: %w" , "cannot generate .ota file" , err )
67
79
}
68
80
69
- d , err := idsGivenTags ( iotClient , params . Tags )
81
+ file , err := os . Open ( otaFile )
70
82
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 )
76
84
}
77
85
78
- otaDir , err := ioutil . TempDir ( "" , "" )
86
+ conf , err := config . Retrieve ( )
79
87
if err != nil {
80
- return fmt . Errorf ( "%s: %w" , "cannot create temporary folder" , err )
88
+ return nil , err
81
89
}
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 )
86
91
if err != nil {
87
- return fmt . Errorf ( "%s: %w" , "cannot generate .ota file" , err )
92
+ return nil , err
88
93
}
89
94
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 )
91
101
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
93
106
}
94
107
95
108
expiration := otaExpirationMins
96
109
if params .Deferred {
97
110
expiration = otaDeferredExpirationMins
98
111
}
99
112
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
101
122
}
102
123
103
124
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
168
189
}()
169
190
}
170
191
171
- var fails []string
172
- var details []string
173
192
for range ids {
174
193
r := <- results
175
194
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 )
178
199
}
179
200
}
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\n reasons:\n %s" , f , d )
186
- }
187
- return nil
201
+ return
188
202
}
0 commit comments