From 408a2ddeadec1b0b4f930ee5b051e1a12c16725c Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 11 Nov 2021 12:01:23 +0100 Subject: [PATCH] Added process.RunWithinContext method This method allows to bound process execution to a context. --- executils/process.go | 17 ++++++++++++ executils/process_test.go | 42 +++++++++++++++++++++++++++++ executils/testdata/delay/.gitignore | 1 + executils/testdata/delay/main.go | 11 ++++++++ 4 files changed, 71 insertions(+) create mode 100644 executils/process_test.go create mode 100644 executils/testdata/delay/.gitignore create mode 100644 executils/testdata/delay/main.go diff --git a/executils/process.go b/executils/process.go index 0f42eccde66..620f66a5d8d 100644 --- a/executils/process.go +++ b/executils/process.go @@ -16,6 +16,7 @@ package executils import ( + "context" "io" "os" "os/exec" @@ -141,3 +142,19 @@ func (p *Process) Run() error { func (p *Process) SetEnvironment(values []string) { p.cmd.Env = values } + +// RunWithinContext starts the specified command and waits for it to complete. If the given context +// is canceled before the normal process termination, the process is killed. +func (p *Process) RunWithinContext(ctx context.Context) error { + completed := make(chan struct{}) + defer close(completed) + go func() { + select { + case <-ctx.Done(): + p.Kill() + case <-completed: + } + }() + res := p.cmd.Run() + return res +} diff --git a/executils/process_test.go b/executils/process_test.go new file mode 100644 index 00000000000..966438f4de0 --- /dev/null +++ b/executils/process_test.go @@ -0,0 +1,42 @@ +// This file is part of arduino-cli. +// +// Copyright 2021 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package executils + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestProcessWithinContext(t *testing.T) { + // Build `delay` helper inside testdata/delay + builder, err := NewProcess("go", "build") + require.NoError(t, err) + builder.SetDir("testdata/delay") + require.NoError(t, builder.Run()) + + // Run delay and test if the process is terminated correctly due to context + process, err := NewProcess("testdata/delay/delay") + require.NoError(t, err) + start := time.Now() + ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond) + err = process.RunWithinContext(ctx) + require.Error(t, err) + require.Less(t, time.Since(start), 500*time.Millisecond) + cancel() +} diff --git a/executils/testdata/delay/.gitignore b/executils/testdata/delay/.gitignore new file mode 100644 index 00000000000..fd5812a40bb --- /dev/null +++ b/executils/testdata/delay/.gitignore @@ -0,0 +1 @@ +delay* diff --git a/executils/testdata/delay/main.go b/executils/testdata/delay/main.go new file mode 100644 index 00000000000..caaa9b0ed94 --- /dev/null +++ b/executils/testdata/delay/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + "time" +) + +func main() { + time.Sleep(3 * time.Second) + fmt.Println("Elapsed!") +}