18
18
package upload
19
19
20
20
import (
21
+ "context"
21
22
"fmt"
23
+ "io"
22
24
"os"
23
25
"path/filepath"
24
26
"strings"
25
27
"time"
26
28
27
29
"github.com/arduino/arduino-cli/arduino/cores"
28
30
"github.com/arduino/arduino-cli/cli"
31
+ "github.com/arduino/arduino-cli/commands"
29
32
"github.com/arduino/arduino-cli/common/formatter"
30
33
"github.com/arduino/arduino-cli/executils"
34
+ "github.com/arduino/arduino-cli/rpc"
31
35
paths "github.com/arduino/go-paths-helper"
32
36
properties "github.com/arduino/go-properties-orderedmap"
33
37
"github.com/sirupsen/logrus"
34
- "github.com/spf13/cobra"
35
38
serial "go.bug.st/serial.v1"
36
39
)
37
40
38
- // InitCommand prepares the command.
39
- func InitCommand () * cobra.Command {
40
- uploadCommand := & cobra.Command {
41
- Use : "upload" ,
42
- Short : "Upload Arduino sketches." ,
43
- Long : "Upload Arduino sketches." ,
44
- Example : " " + cli .AppName + " upload /home/user/Arduino/MySketch" ,
45
- Args : cobra .MaximumNArgs (1 ),
46
- Run : run ,
47
- }
48
- uploadCommand .Flags ().StringVarP (
49
- & flags .fqbn , "fqbn" , "b" , "" ,
50
- "Fully Qualified Board Name, e.g.: arduino:avr:uno" )
51
- uploadCommand .Flags ().StringVarP (
52
- & flags .port , "port" , "p" , "" ,
53
- "Upload port, e.g.: COM10 or /dev/ttyACM0" )
54
- uploadCommand .Flags ().StringVarP (
55
- & flags .importFile , "input" , "i" , "" ,
56
- "Input file to be uploaded." )
57
- uploadCommand .Flags ().BoolVarP (
58
- & flags .verify , "verify" , "t" , false ,
59
- "Verify uploaded binary after the upload." )
60
- uploadCommand .Flags ().BoolVarP (
61
- & flags .verbose , "verbose" , "v" , false ,
62
- "Optional, turns on verbose mode." )
63
- return uploadCommand
64
- }
65
-
66
- var flags struct {
67
- fqbn string
68
- port string
69
- verbose bool
70
- verify bool
71
- importFile string
72
- }
73
-
74
- func run (command * cobra.Command , args []string ) {
41
+ func Upload (ctx context.Context , req * rpc.UploadReq , outStream io.Writer , errStream io.Writer ) (* rpc.UploadResp , error ) {
42
+ logrus .Info ("Executing `arduino upload`" )
75
43
var sketchPath * paths.Path
76
- if len ( args ) > 0 {
77
- sketchPath = paths .New (args [ 0 ] )
44
+ if req . GetSketchPath () != "" {
45
+ sketchPath = paths .New (req . GetSketchPath () )
78
46
}
79
47
sketch , err := cli .InitSketch (sketchPath )
80
48
if err != nil {
81
- formatter .PrintError (err , "Error opening sketch." )
82
- os .Exit (cli .ErrGeneric )
49
+ return nil , fmt .Errorf ("opening sketch: %s" , err )
83
50
}
84
-
85
51
// FIXME: make a specification on how a port is specified via command line
86
- port := flags . port
52
+ port := req . GetPort ()
87
53
if port == "" {
88
- formatter .PrintErrorMessage ("No port provided." )
89
- os .Exit (cli .ErrBadCall )
54
+ return nil , fmt .Errorf ("No port provided." )
90
55
}
91
56
92
- if flags .fqbn == "" && sketch != nil {
93
- flags .fqbn = sketch .Metadata .CPU .Fqbn
57
+ fqbnIn := req .GetFqbn ()
58
+ if fqbnIn == "" && sketch != nil && sketch .Metadata != nil {
59
+ fqbnIn = sketch .Metadata .CPU .Fqbn
94
60
}
95
- if flags .fqbn == "" {
96
- formatter .PrintErrorMessage ("No Fully Qualified Board Name provided." )
97
- os .Exit (cli .ErrBadCall )
61
+ if fqbnIn == "" {
62
+ return nil , fmt .Errorf ("No Fully Qualified Board Name provided" )
98
63
}
99
- fqbn , err := cores .ParseFQBN (flags . fqbn )
64
+ fqbn , err := cores .ParseFQBN (fqbnIn )
100
65
if err != nil {
101
- formatter .PrintError (err , "Invalid FQBN." )
102
- os .Exit (cli .ErrBadCall )
66
+ return nil , fmt .Errorf ("incorrect FQBN: %s" , err )
103
67
}
104
68
105
- pm , _ := cli . InitPackageAndLibraryManager ( )
69
+ pm := commands . GetPackageManager ( req )
106
70
107
71
// Find target board and board properties
108
72
_ , _ , board , boardProperties , _ , err := pm .ResolveFQBN (fqbn )
109
73
if err != nil {
110
- formatter .PrintError (err , "Invalid FQBN." )
111
- os .Exit (cli .ErrBadCall )
74
+ return nil , fmt .Errorf ("Invalid FQBN: %s" , err )
112
75
}
113
76
114
77
// Load programmer tool
115
78
uploadToolPattern , have := boardProperties .GetOk ("upload.tool" )
116
79
if ! have || uploadToolPattern == "" {
117
- formatter .PrintErrorMessage ("The board does not define an 'upload.tool' property." )
118
- os .Exit (cli .ErrGeneric )
80
+ return nil , fmt .Errorf ("The board does not define an 'upload.tool' property." )
119
81
}
120
82
121
83
var referencedPlatformRelease * cores.PlatformRelease
122
84
if split := strings .Split (uploadToolPattern , ":" ); len (split ) > 2 {
123
- formatter .PrintErrorMessage ("The board defines an invalid 'upload.tool' property: " + uploadToolPattern )
124
- os .Exit (cli .ErrGeneric )
85
+ return nil , fmt .Errorf ("The board defines an invalid 'upload.tool' property: " + uploadToolPattern )
125
86
} else if len (split ) == 2 {
126
87
referencedPackageName := split [0 ]
127
88
uploadToolPattern = split [1 ]
128
89
architecture := board .PlatformRelease .Platform .Architecture
129
90
130
91
if referencedPackage := pm .GetPackages ().Packages [referencedPackageName ]; referencedPackage == nil {
131
- formatter .PrintErrorMessage ("The board requires platform '" + referencedPackageName + ":" + architecture + "' that is not installed." )
132
- os .Exit (cli .ErrGeneric )
92
+ return nil , fmt .Errorf ("The board requires platform '" + referencedPackageName + ":" + architecture + "' that is not installed." )
133
93
} else if referencedPlatform := referencedPackage .Platforms [architecture ]; referencedPlatform == nil {
134
- formatter .PrintErrorMessage ("The board requires platform '" + referencedPackageName + ":" + architecture + "' that is not installed." )
135
- os .Exit (cli .ErrGeneric )
94
+ return nil , fmt .Errorf ("The board requires platform '" + referencedPackageName + ":" + architecture + "' that is not installed." )
136
95
} else {
137
96
referencedPlatformRelease = pm .GetInstalledPlatformRelease (referencedPlatform )
138
97
}
@@ -157,7 +116,8 @@ func run(command *cobra.Command, args []string) {
157
116
}
158
117
159
118
// Set properties for verbose upload
160
- if flags .verbose {
119
+ Verbose := req .GetVerbose ()
120
+ if Verbose {
161
121
if v , ok := uploadProperties .GetOk ("upload.params.verbose" ); ok {
162
122
uploadProperties .Set ("upload.verbose" , v )
163
123
}
@@ -168,7 +128,8 @@ func run(command *cobra.Command, args []string) {
168
128
}
169
129
170
130
// Set properties for verify
171
- if flags .verify {
131
+ Verify := req .GetVerify ()
132
+ if Verify {
172
133
uploadProperties .Set ("upload.verify" , uploadProperties .Get ("upload.params.verify" ))
173
134
} else {
174
135
uploadProperties .Set ("upload.verify" , uploadProperties .Get ("upload.params.noverify" ))
@@ -181,19 +142,18 @@ func run(command *cobra.Command, args []string) {
181
142
182
143
var importPath * paths.Path
183
144
var importFile string
184
- if flags . importFile == "" {
145
+ if req . GetImportFile () == "" {
185
146
importPath = sketch .FullPath
186
147
importFile = sketch .Name + "." + fqbnSuffix
187
148
} else {
188
- importPath = paths .New (flags . importFile ).Parent ()
189
- importFile = paths .New (flags . importFile ).Base ()
149
+ importPath = paths .New (req . GetImportFile () ).Parent ()
150
+ importFile = paths .New (req . GetImportFile () ).Base ()
190
151
}
191
152
192
153
outputTmpFile , ok := uploadProperties .GetOk ("recipe.output.tmp_file" )
193
154
outputTmpFile = uploadProperties .ExpandPropsInString (outputTmpFile )
194
155
if ! ok {
195
- formatter .PrintErrorMessage ("The platform does not define the required property 'recipe.output.tmp_file'." )
196
- os .Exit (cli .ErrGeneric )
156
+ return nil , fmt .Errorf ("The platform does not define the required property 'recipe.output.tmp_file'." )
197
157
}
198
158
ext := filepath .Ext (outputTmpFile )
199
159
if strings .HasSuffix (importFile , ext ) {
@@ -205,25 +165,22 @@ func run(command *cobra.Command, args []string) {
205
165
uploadFile := importPath .Join (importFile + ext )
206
166
if _ , err := uploadFile .Stat (); err != nil {
207
167
if os .IsNotExist (err ) {
208
- formatter . PrintErrorMessage ("Compiled sketch not found: " + uploadFile .String () + ". Please compile first." )
168
+ return nil , fmt . Errorf ("Compiled sketch not found: " + uploadFile .String ()+ ". Please compile first." , err )
209
169
} else {
210
- formatter . PrintError ( err , "Could not open compiled sketch." )
170
+ return nil , fmt . Errorf ( "Could not open compiled sketch." , err )
211
171
}
212
- os .Exit (cli .ErrGeneric )
213
172
}
214
173
215
174
// Perform reset via 1200bps touch if requested
216
175
if uploadProperties .GetBoolean ("upload.use_1200bps_touch" ) {
217
176
ports , err := serial .GetPortsList ()
218
177
if err != nil {
219
- formatter .PrintError (err , "Can't get serial port list" )
220
- os .Exit (cli .ErrGeneric )
178
+ return nil , fmt .Errorf ("Can't get serial port list" , err )
221
179
}
222
180
for _ , p := range ports {
223
181
if p == port {
224
182
if err := touchSerialPortAt1200bps (p ); err != nil {
225
- formatter .PrintError (err , "Can't perform reset via 1200bps-touch on serial port" )
226
- os .Exit (cli .ErrGeneric )
183
+ return nil , fmt .Errorf ("Can't perform reset via 1200bps-touch on serial port" , err )
227
184
}
228
185
break
229
186
}
@@ -240,8 +197,7 @@ func run(command *cobra.Command, args []string) {
240
197
actualPort := port // default
241
198
if uploadProperties .GetBoolean ("upload.wait_for_upload_port" ) {
242
199
if p , err := waitForNewSerialPort (); err != nil {
243
- formatter .PrintError (err , "Could not detect serial ports" )
244
- os .Exit (cli .ErrGeneric )
200
+ return nil , fmt .Errorf ("Could not detect serial ports" , err )
245
201
} else if p == "" {
246
202
formatter .Print ("No new serial port detected." )
247
203
} else {
@@ -267,28 +223,28 @@ func run(command *cobra.Command, args []string) {
267
223
cmdLine := uploadProperties .ExpandPropsInString (recipe )
268
224
cmdArgs , err := properties .SplitQuotedString (cmdLine , `"'` , false )
269
225
if err != nil {
270
- formatter .PrintError (err , "Invalid recipe in platform." )
271
- os .Exit (cli .ErrCoreConfig )
226
+ return nil , fmt .Errorf ("Invalid recipe in platform." , err )
272
227
}
273
228
274
229
// Run Tool
275
230
cmd , err := executils .Command (cmdArgs )
276
231
if err != nil {
277
- formatter .PrintError (err , "Could not execute upload tool." )
278
- os .Exit (cli .ErrGeneric )
232
+ return nil , fmt .Errorf ("Could not execute upload tool." , err )
279
233
}
280
234
281
235
executils .AttachStdoutListener (cmd , executils .PrintToStdout )
282
236
executils .AttachStderrListener (cmd , executils .PrintToStderr )
237
+ cmd .Stdout = outStream
238
+ cmd .Stderr = errStream
283
239
284
240
if err := cmd .Start (); err != nil {
285
- formatter .PrintError (err , "Could not execute upload tool." )
286
- os .Exit (cli .ErrGeneric )
241
+ return nil , fmt .Errorf ("Could not execute upload tool." , err )
287
242
}
243
+
288
244
if err := cmd .Wait (); err != nil {
289
- formatter .PrintError (err , "Error during upload." )
290
- os .Exit (cli .ErrGeneric )
245
+ return nil , fmt .Errorf ("Error during upload." , err )
291
246
}
247
+ return & rpc.UploadResp {}, nil
292
248
}
293
249
294
250
func touchSerialPortAt1200bps (port string ) error {
0 commit comments