@@ -44,9 +44,11 @@ type commander struct {
44
44
func NewCommander () (arduino.Commander , error ) {
45
45
// Discard arduino-cli log info messages
46
46
logrus .SetLevel (logrus .ErrorLevel )
47
- // Initialize arduino-cli configuration
47
+
48
+ // Initialize arduino-cli configuration.
48
49
configuration .Settings = configuration .Init (configuration .FindConfigFileInArgsOrWorkingDirectory (os .Args ))
49
- // Create arduino-cli instance, needed to execute arduino-cli commands
50
+
51
+ // Create and init an arduino-cli instance, needed to execute arduino-cli commands.
50
52
inst , err := instance .Create ()
51
53
if err != nil {
52
54
err = fmt .Errorf ("creating arduino-cli instance: %w" , err )
@@ -61,34 +63,64 @@ func NewCommander() (arduino.Commander, error) {
61
63
return cmd , nil
62
64
}
63
65
66
+ func mergeErrors (err error , errs []error ) error {
67
+ merr := errors .New ("merged errors: " )
68
+ empty := true
69
+
70
+ if err != nil {
71
+ merr = fmt .Errorf ("%w%v; " , merr , err )
72
+ empty = false
73
+ }
74
+
75
+ if len (errs ) > 0 {
76
+ empty = false
77
+ for _ , e := range errs {
78
+ merr = fmt .Errorf ("%w%v; " , merr , e )
79
+ }
80
+ }
81
+
82
+ if ! empty {
83
+ return merr
84
+ }
85
+ return nil
86
+ }
87
+
64
88
// BoardList executes the 'arduino-cli board list' command
65
89
// and returns its result.
66
- func (c * commander ) BoardList () ([]* rpc.DetectedPort , error ) {
90
+ func (c * commander ) BoardList (ctx context. Context ) ([]* rpc.DetectedPort , error ) {
67
91
req := & rpc.BoardListRequest {
68
92
Instance : c .Instance ,
69
93
Timeout : time .Second .Milliseconds (),
70
94
}
71
95
72
- ports , errs , err := board .List (req )
73
- if err != nil {
74
- err = fmt .Errorf ("%s: %w" , "detecting boards" , err )
75
- return nil , err
96
+ // There is no obvious way to cancel the execution of this command.
97
+ // So, we execute it in a goroutine and leave it running alone if ctx gets cancelled.
98
+ type resp struct {
99
+ err error
100
+ ports []* rpc.DetectedPort
76
101
}
102
+ quit := make (chan resp , 1 )
103
+ go func () {
104
+ ports , errs , err := board .List (req )
105
+ quit <- resp {err : mergeErrors (err , errs ), ports : ports }
106
+ close (quit )
107
+ }()
77
108
78
- if len (errs ) > 0 {
79
- err = errors .New ("starting discovery procedure: received errors: " )
80
- for _ , e := range errs {
81
- err = fmt .Errorf ("%w%v; " , err , e )
109
+ // Wait for the command to complete or the context to be terminated.
110
+ select {
111
+ case <- ctx .Done ():
112
+ return nil , errors .New ("board list command cancelled" )
113
+ case r := <- quit :
114
+ if r .err != nil {
115
+ return nil , fmt .Errorf ("executing board list command: %w" , r .err )
82
116
}
83
- return nil , err
117
+ return r . ports , nil
84
118
}
85
-
86
- return ports , nil
87
119
}
88
120
89
121
// UploadBin executes the 'arduino-cli upload -i' command
90
122
// and returns its result.
91
- func (c * commander ) UploadBin (fqbn , bin , address , protocol string ) error {
123
+ func (c * commander ) UploadBin (ctx context. Context , fqbn , bin , address , protocol string ) error {
92
124
req := & rpc.UploadRequest {
93
125
Instance : c .Instance ,
94
126
Fqbn : fqbn ,
@@ -97,11 +129,25 @@ func (c *commander) UploadBin(fqbn, bin, address, protocol string) error {
97
129
Port : & rpc.Port {Address : address , Protocol : protocol },
98
130
Verbose : false ,
99
131
}
100
-
101
132
l := logrus .StandardLogger ().WithField ("source" , "arduino-cli" ).Writer ()
102
- if _ , err := upload .Upload (context .Background (), req , l , l ); err != nil {
103
- err = fmt .Errorf ("%s: %w" , "uploading binary" , err )
104
- return err
133
+
134
+ // There is no obvious way to cancel the execution of this command.
135
+ // So, we execute it in a goroutine and leave it running if ctx gets cancelled.
136
+ quit := make (chan error , 1 )
137
+ go func () {
138
+ _ , err := upload .Upload (ctx , req , l , l )
139
+ quit <- err
140
+ close (quit )
141
+ }()
142
+
143
+ // Wait for the upload to complete or the context to be terminated.
144
+ select {
145
+ case <- ctx .Done ():
146
+ return errors .New ("upload cancelled" )
147
+ case err := <- quit :
148
+ if err != nil {
149
+ return fmt .Errorf ("uploading binary: %w" , err )
150
+ }
151
+ return nil
105
152
}
106
- return nil
107
153
}
0 commit comments