Skip to content

Commit acf791e

Browse files
committed
Refactoring 'upload' commands
1 parent 4696d07 commit acf791e

File tree

8 files changed

+270
-58
lines changed

8 files changed

+270
-58
lines changed

arduino/cores/fqbn.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func ParseFQBN(fqbnIn string) (*FQBN, error) {
3535
// Split fqbn
3636
fqbnParts := strings.Split(fqbnIn, ":")
3737
if len(fqbnParts) < 3 || len(fqbnParts) > 4 {
38-
return nil, fmt.Errorf("invalid fqbn: %s", fqbnIn)
38+
return nil, fmt.Errorf("not an FQBN: %s", fqbnIn)
3939
}
4040

4141
fqbn := &FQBN{
@@ -45,18 +45,18 @@ func ParseFQBN(fqbnIn string) (*FQBN, error) {
4545
Configs: properties.NewMap(),
4646
}
4747
if fqbn.BoardID == "" {
48-
return nil, fmt.Errorf(tr("invalid fqbn: empty board identifier"))
48+
return nil, fmt.Errorf(tr("empty board identifier"))
4949
}
5050
if len(fqbnParts) > 3 {
5151
for _, pair := range strings.Split(fqbnParts[3], ",") {
5252
parts := strings.SplitN(pair, "=", 2)
5353
if len(parts) != 2 {
54-
return nil, fmt.Errorf(tr("invalid fqbn config: %s"), pair)
54+
return nil, fmt.Errorf(tr("invalid config oprion: %s"), pair)
5555
}
5656
k := strings.TrimSpace(parts[0])
5757
v := strings.TrimSpace(parts[1])
5858
if k == "" {
59-
return nil, fmt.Errorf(tr("invalid fqbn config: %s"), pair)
59+
return nil, fmt.Errorf(tr("invalid config option: %s"), pair)
6060
}
6161
fqbn.Configs.Set(k, v)
6262
}

cli/compile/compile.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,18 @@ func run(cmd *cobra.Command, args []string) {
231231
Programmer: programmer,
232232
UserFields: fields,
233233
}
234-
var st *status.Status
234+
235+
var uploadError error
235236
if output.OutputFormat == "json" {
236237
// TODO: do not print upload output in json mode
237-
uploadOut := new(bytes.Buffer)
238-
uploadErr := new(bytes.Buffer)
239-
_, st = upload.Upload(context.Background(), uploadRequest, uploadOut, uploadErr)
238+
uploadStdOut := new(bytes.Buffer)
239+
uploadStdErr := new(bytes.Buffer)
240+
_, uploadError = upload.Upload(context.Background(), uploadRequest, uploadStdOut, uploadStdErr)
240241
} else {
241-
_, st = upload.Upload(context.Background(), uploadRequest, os.Stdout, os.Stderr)
242+
_, uploadError = upload.Upload(context.Background(), uploadRequest, os.Stdout, os.Stderr)
242243
}
243-
if st != nil {
244-
feedback.Errorf(tr("Error during Upload: %v"), st.Message())
244+
if uploadError != nil {
245+
feedback.Errorf(tr("Error during Upload: %v"), uploadError)
245246
os.Exit(errorcodes.ErrGeneric)
246247
}
247248
}

commands/daemon/daemon.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ type ArduinoCoreServerImpl struct {
4141

4242
var tr = i18n.Tr
4343

44+
func convertErrorToRPCStatus(err error) error {
45+
if cmdErr, ok := err.(commands.CommandError); ok {
46+
return cmdErr.ToRPCStatus().Err()
47+
}
48+
return err
49+
}
50+
4451
// BoardDetails FIXMEDOC
4552
func (s *ArduinoCoreServerImpl) BoardDetails(ctx context.Context, req *rpc.BoardDetailsRequest) (*rpc.BoardDetailsResponse, error) {
4653
resp, err := board.Details(ctx, req)
@@ -336,7 +343,7 @@ func (s *ArduinoCoreServerImpl) Upload(req *rpc.UploadRequest, stream rpc.Arduin
336343
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadResponse{ErrStream: data}) }),
337344
)
338345
if err != nil {
339-
return err.Err()
346+
return convertErrorToRPCStatus(err)
340347
}
341348
return stream.Send(resp)
342349
}
@@ -349,7 +356,7 @@ func (s *ArduinoCoreServerImpl) UploadUsingProgrammer(req *rpc.UploadUsingProgra
349356
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.UploadUsingProgrammerResponse{ErrStream: data}) }),
350357
)
351358
if err != nil {
352-
return err.Err()
359+
return convertErrorToRPCStatus(err)
353360
}
354361
return stream.Send(resp)
355362
}
@@ -362,15 +369,15 @@ func (s *ArduinoCoreServerImpl) BurnBootloader(req *rpc.BurnBootloaderRequest, s
362369
utils.FeedStreamTo(func(data []byte) { stream.Send(&rpc.BurnBootloaderResponse{ErrStream: data}) }),
363370
)
364371
if err != nil {
365-
return err.Err()
372+
return convertErrorToRPCStatus(err)
366373
}
367374
return stream.Send(resp)
368375
}
369376

370377
// ListProgrammersAvailableForUpload FIXMEDOC
371378
func (s *ArduinoCoreServerImpl) ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadRequest) (*rpc.ListProgrammersAvailableForUploadResponse, error) {
372379
resp, err := upload.ListProgrammersAvailableForUpload(ctx, req)
373-
return resp, err.Err()
380+
return resp, convertErrorToRPCStatus(err)
374381
}
375382

376383
// LibraryDownload FIXMEDOC

commands/errors.go

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
4+
//
5+
// This software is released under the GNU General Public License version 3,
6+
// which covers the main part of arduino-cli.
7+
// The terms of this license can be found at:
8+
// https://www.gnu.org/licenses/gpl-3.0.en.html
9+
//
10+
// You can be released from the requirements of the above licenses by purchasing
11+
// a commercial license. Buying such a license is mandatory if you want to
12+
// modify or otherwise use the software for commercial activities involving the
13+
// Arduino software without disclosing the source code of your own applications.
14+
// To purchase a commercial license, send an email to license@arduino.cc.
15+
16+
package commands
17+
18+
import (
19+
"fmt"
20+
21+
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
22+
"google.golang.org/grpc/codes"
23+
"google.golang.org/grpc/status"
24+
)
25+
26+
func composeErrorMsg(msg string, cause error) string {
27+
if cause == nil {
28+
return msg
29+
}
30+
return fmt.Sprintf("%v: %v", msg, cause)
31+
}
32+
33+
// CommandError is an error that may be converted into a gRPC status.
34+
type CommandError interface {
35+
ToRPCStatus() *status.Status
36+
}
37+
38+
// InvalidInstanceError is returned if the instance used in the command is not valid.
39+
type InvalidInstanceError struct{}
40+
41+
func (e *InvalidInstanceError) Error() string {
42+
return tr("Invalid instance")
43+
}
44+
45+
func (e *InvalidInstanceError) ToRPCStatus() *status.Status {
46+
return status.New(codes.InvalidArgument, e.Error())
47+
}
48+
49+
// InvalidFQBNError is returned when the FQBN has syntax errors
50+
type InvalidFQBNError struct {
51+
Cause error
52+
}
53+
54+
func (e *InvalidFQBNError) Error() string {
55+
return composeErrorMsg(tr("Invalid FQBN"), e.Cause)
56+
}
57+
58+
func (e *InvalidFQBNError) ToRPCStatus() *status.Status {
59+
return status.New(codes.InvalidArgument, e.Error())
60+
}
61+
62+
func (e *InvalidFQBNError) Unwrap() error {
63+
return e.Cause
64+
}
65+
66+
// MissingFQBNError is returned when the FQBN is mandatory and not specified
67+
type MissingFQBNError struct{}
68+
69+
func (e *MissingFQBNError) Error() string {
70+
return tr("Missing FQBN (Fully Qualified Board Name)")
71+
}
72+
73+
func (e *MissingFQBNError) ToRPCStatus() *status.Status {
74+
return status.New(codes.InvalidArgument, e.Error())
75+
}
76+
77+
// UnknownFQBNError is returned when the FQBN is not found
78+
type UnknownFQBNError struct {
79+
Cause error
80+
}
81+
82+
func (e *UnknownFQBNError) Error() string {
83+
return composeErrorMsg(tr("Unknown FQBN"), e.Cause)
84+
}
85+
86+
func (e *UnknownFQBNError) Unwrap() error {
87+
return e.Cause
88+
}
89+
90+
func (e *UnknownFQBNError) ToRPCStatus() *status.Status {
91+
return status.New(codes.NotFound, e.Error())
92+
}
93+
94+
// MissingPortProtocolError is returned when the port protocol is mandatory and not specified
95+
type MissingPortProtocolError struct{}
96+
97+
func (e *MissingPortProtocolError) Error() string {
98+
return tr("Missing port protocol")
99+
}
100+
101+
func (e *MissingPortProtocolError) ToRPCStatus() *status.Status {
102+
return status.New(codes.InvalidArgument, e.Error())
103+
}
104+
105+
// MissingProgrammerError is returned when the programmer is mandatory and not specified
106+
type MissingProgrammerError struct{}
107+
108+
func (e *MissingProgrammerError) Error() string {
109+
return tr("Missing programmer")
110+
}
111+
112+
func (e *MissingProgrammerError) ToRPCStatus() *status.Status {
113+
return status.New(codes.InvalidArgument, e.Error())
114+
}
115+
116+
// ProgreammerRequiredForUploadError is returned then the upload can be done only using a programmer
117+
type ProgreammerRequiredForUploadError struct{}
118+
119+
func (e *ProgreammerRequiredForUploadError) Error() string {
120+
return tr("A programmer is required to upload")
121+
}
122+
123+
func (e *ProgreammerRequiredForUploadError) ToRPCStatus() *status.Status {
124+
st, _ := status.
125+
New(codes.InvalidArgument, e.Error()).
126+
WithDetails(&rpc.ProgrammerIsRequiredForUploadError{})
127+
return st
128+
}
129+
130+
// UnknownProgrammerError is returned when the programmer is not found
131+
type UnknownProgrammerError struct {
132+
Cause error
133+
}
134+
135+
func (e *UnknownProgrammerError) Error() string {
136+
return composeErrorMsg(tr("Unknown programmer"), e.Cause)
137+
}
138+
139+
func (e *UnknownProgrammerError) Unwrap() error {
140+
return e.Cause
141+
}
142+
143+
func (e *UnknownProgrammerError) ToRPCStatus() *status.Status {
144+
return status.New(codes.NotFound, e.Error())
145+
}
146+
147+
// InvalidPlatformPropertyError is returned when a property in the platform is not valid
148+
type InvalidPlatformPropertyError struct {
149+
Property string
150+
Value string
151+
}
152+
153+
func (e *InvalidPlatformPropertyError) Error() string {
154+
return tr("Invalid '%[1]s' property: %[2]s", e.Property, e.Value)
155+
}
156+
157+
func (e *InvalidPlatformPropertyError) ToRPCStatus() *status.Status {
158+
return status.New(codes.FailedPrecondition, e.Error())
159+
}
160+
161+
// MissingPlatformPropertyError is returned when a property in the platform is not found
162+
type MissingPlatformPropertyError struct {
163+
Property string
164+
}
165+
166+
func (e *MissingPlatformPropertyError) Error() string {
167+
return tr("Property '%s' is undefined", e.Property)
168+
}
169+
170+
func (e *MissingPlatformPropertyError) ToRPCStatus() *status.Status {
171+
return status.New(codes.FailedPrecondition, e.Error())
172+
}
173+
174+
// SketchNotFoundError is returned when the sketch is not found
175+
type SketchNotFoundError struct {
176+
Cause error
177+
}
178+
179+
func (e *SketchNotFoundError) Error() string {
180+
return composeErrorMsg(tr("Sketch not found"), e.Cause)
181+
}
182+
183+
func (e *SketchNotFoundError) Unwrap() error {
184+
return e.Cause
185+
}
186+
187+
func (e *SketchNotFoundError) ToRPCStatus() *status.Status {
188+
return status.New(codes.NotFound, e.Error())
189+
}
190+
191+
// FailedUploadError is returned when the upload fails
192+
type FailedUploadError struct {
193+
Message string
194+
Cause error
195+
}
196+
197+
func (e *FailedUploadError) Error() string {
198+
return composeErrorMsg(e.Message, e.Cause)
199+
}
200+
201+
func (e *FailedUploadError) Unwrap() error {
202+
return e.Cause
203+
}
204+
205+
func (e *FailedUploadError) ToRPCStatus() *status.Status {
206+
return status.New(codes.Internal, e.Error())
207+
}

commands/upload/burnbootloader.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ import (
2222
"github.com/arduino/arduino-cli/commands"
2323
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
2424
"github.com/sirupsen/logrus"
25-
"google.golang.org/grpc/status"
2625
)
2726

2827
// BurnBootloader FIXMEDOC
29-
func BurnBootloader(ctx context.Context, req *rpc.BurnBootloaderRequest, outStream io.Writer, errStream io.Writer) (*rpc.BurnBootloaderResponse, *status.Status) {
28+
func BurnBootloader(ctx context.Context, req *rpc.BurnBootloaderRequest, outStream io.Writer, errStream io.Writer) (*rpc.BurnBootloaderResponse, error) {
3029
logrus.
3130
WithField("fqbn", req.GetFqbn()).
3231
WithField("port", req.GetPort()).

commands/upload/programmers_list.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,25 @@ import (
2121
"github.com/arduino/arduino-cli/arduino/cores"
2222
"github.com/arduino/arduino-cli/commands"
2323
rpc "github.com/arduino/arduino-cli/rpc/cc/arduino/cli/commands/v1"
24-
"google.golang.org/grpc/codes"
25-
"google.golang.org/grpc/status"
2624
)
2725

2826
// ListProgrammersAvailableForUpload FIXMEDOC
29-
func ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadRequest) (*rpc.ListProgrammersAvailableForUploadResponse, *status.Status) {
27+
func ListProgrammersAvailableForUpload(ctx context.Context, req *rpc.ListProgrammersAvailableForUploadRequest) (*rpc.ListProgrammersAvailableForUploadResponse, error) {
3028
pm := commands.GetPackageManager(req.GetInstance().GetId())
3129

3230
fqbnIn := req.GetFqbn()
3331
if fqbnIn == "" {
34-
return nil, status.New(codes.InvalidArgument, tr("No FQBN (Fully Qualified Board Name) provided"))
32+
return nil, &commands.MissingFQBNError{}
3533
}
3634
fqbn, err := cores.ParseFQBN(fqbnIn)
3735
if err != nil {
38-
return nil, status.Newf(codes.InvalidArgument, tr("Invalid FQBN: %s"), err)
36+
return nil, &commands.InvalidFQBNError{Cause: err}
3937
}
4038

4139
// Find target platforms
4240
_, platform, _, _, refPlatform, err := pm.ResolveFQBN(fqbn)
4341
if err != nil {
44-
return nil, status.Newf(codes.Unknown, tr("Invalid FQBN: %s"), err)
42+
return nil, &commands.UnknownFQBNError{Cause: err}
4543
}
4644

4745
result := []*rpc.Programmer{}

0 commit comments

Comments
 (0)