Skip to content

Commit 1775552

Browse files
committed
Workaround arduino-cli blocking commands
1 parent 7feb9d8 commit 1775552

File tree

1 file changed

+50
-16
lines changed

1 file changed

+50
-16
lines changed

arduino/cli/commander.go

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ type commander struct {
4242
// programmatically call arduino-cli commands.
4343
// It directly imports the golang packages of the arduino-cli.
4444
func NewCommander() (arduino.Commander, error) {
45-
// Discard arduino-cli log info messages
45+
// Discard arduino-cli log info messages.
4646
logrus.SetLevel(logrus.PanicLevel)
47-
// Initialize arduino-cli configuration
47+
48+
// Initialize arduino-cli configuration.
4849
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.
5052
inst, err := instance.Create()
5153
if err != nil {
5254
err = fmt.Errorf("creating arduino-cli instance: %w", err)
@@ -56,7 +58,7 @@ func NewCommander() (arduino.Commander, error) {
5658
if len(errs) > 0 {
5759
err = errors.New("initializing arduino-cli instance: received errors: ")
5860
for _, e := range errs {
59-
err = fmt.Errorf("%w%v; ", err, e)
61+
err = fmt.Errorf("%v: %v; ", err, e)
6062
}
6163
return nil, err
6264
}
@@ -69,22 +71,40 @@ func NewCommander() (arduino.Commander, error) {
6971

7072
// BoardList executes the 'arduino-cli board list' command
7173
// and returns its result.
72-
func (c *commander) BoardList() ([]*rpc.DetectedPort, error) {
74+
func (c *commander) BoardList(ctx context.Context) ([]*rpc.DetectedPort, error) {
7375
req := &rpc.BoardListRequest{
7476
Instance: c.Instance,
7577
Timeout: time.Second.Milliseconds(),
7678
}
77-
ports, err := board.List(req)
78-
if err != nil {
79-
err = fmt.Errorf("%s: %w", "detecting boards", err)
80-
return nil, err
79+
80+
// There is no obvious way to cancel the execution of this command.
81+
// So, we execute it in a goroutine and leave it running alone if ctx gets cancelled.
82+
type resp struct {
83+
err error
84+
ports []*rpc.DetectedPort
85+
}
86+
quit := make(chan resp, 1)
87+
go func() {
88+
ports, err := board.List(req)
89+
quit <- resp{err: err, ports: ports}
90+
close(quit)
91+
}()
92+
93+
// Wait for the command to complete or the context to be terminated.
94+
select {
95+
case <-ctx.Done():
96+
return nil, errors.New("board list command cancelled")
97+
case r := <-quit:
98+
if r.err != nil {
99+
return nil, fmt.Errorf("executing board list command: %w", r.err)
100+
}
101+
return r.ports, nil
81102
}
82-
return ports, nil
83103
}
84104

85105
// UploadBin executes the 'arduino-cli upload -i' command
86106
// and returns its result.
87-
func (c *commander) UploadBin(fqbn, bin, address, protocol string) error {
107+
func (c *commander) UploadBin(ctx context.Context, fqbn, bin, address, protocol string) error {
88108
req := &rpc.UploadRequest{
89109
Instance: c.Instance,
90110
Fqbn: fqbn,
@@ -93,11 +113,25 @@ func (c *commander) UploadBin(fqbn, bin, address, protocol string) error {
93113
Port: &rpc.Port{Address: address, Protocol: protocol},
94114
Verbose: false,
95115
}
96-
97116
l := logrus.StandardLogger().WithField("source", "arduino-cli").Writer()
98-
if _, err := upload.Upload(context.Background(), req, l, l); err != nil {
99-
err = fmt.Errorf("%s: %w", "uploading binary", err)
100-
return err
117+
118+
// There is no obvious way to cancel the execution of this command.
119+
// So, we execute it in a goroutine and leave it running if ctx gets cancelled.
120+
quit := make(chan error, 1)
121+
go func() {
122+
_, err := upload.Upload(ctx, req, l, l)
123+
quit <- err
124+
close(quit)
125+
}()
126+
127+
// Wait for the upload to complete or the context to be terminated.
128+
select {
129+
case <-ctx.Done():
130+
return errors.New("upload cancelled")
131+
case err := <-quit:
132+
if err != nil {
133+
return fmt.Errorf("uploading binary: %w", err)
134+
}
135+
return nil
101136
}
102-
return nil
103137
}

0 commit comments

Comments
 (0)