Skip to content

Commit bf4a784

Browse files
authored
[skip-changelog] Added process.RunWithinContext method (#1546)
This method allows to bound process execution to a context.
1 parent c8a3f2e commit bf4a784

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

Diff for: executils/process.go

+17
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package executils
1717

1818
import (
19+
"context"
1920
"io"
2021
"os"
2122
"os/exec"
@@ -141,3 +142,19 @@ func (p *Process) Run() error {
141142
func (p *Process) SetEnvironment(values []string) {
142143
p.cmd.Env = values
143144
}
145+
146+
// RunWithinContext starts the specified command and waits for it to complete. If the given context
147+
// is canceled before the normal process termination, the process is killed.
148+
func (p *Process) RunWithinContext(ctx context.Context) error {
149+
completed := make(chan struct{})
150+
defer close(completed)
151+
go func() {
152+
select {
153+
case <-ctx.Done():
154+
p.Kill()
155+
case <-completed:
156+
}
157+
}()
158+
res := p.cmd.Run()
159+
return res
160+
}

Diff for: executils/process_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This file is part of arduino-cli.
2+
//
3+
// Copyright 2021 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 [email protected].
15+
16+
package executils
17+
18+
import (
19+
"context"
20+
"testing"
21+
"time"
22+
23+
"github.com/stretchr/testify/require"
24+
)
25+
26+
func TestProcessWithinContext(t *testing.T) {
27+
// Build `delay` helper inside testdata/delay
28+
builder, err := NewProcess("go", "build")
29+
require.NoError(t, err)
30+
builder.SetDir("testdata/delay")
31+
require.NoError(t, builder.Run())
32+
33+
// Run delay and test if the process is terminated correctly due to context
34+
process, err := NewProcess("testdata/delay/delay")
35+
require.NoError(t, err)
36+
start := time.Now()
37+
ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond)
38+
err = process.RunWithinContext(ctx)
39+
require.Error(t, err)
40+
require.Less(t, time.Since(start), 500*time.Millisecond)
41+
cancel()
42+
}

Diff for: executils/testdata/delay/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
delay*

Diff for: executils/testdata/delay/main.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"time"
6+
)
7+
8+
func main() {
9+
time.Sleep(3 * time.Second)
10+
fmt.Println("Elapsed!")
11+
}

0 commit comments

Comments
 (0)