Skip to content

Instantly share code, notes, and snippets.

@MrSaints
Last active June 26, 2017 10:06
Show Gist options
  • Save MrSaints/278806e46ad305afb4a1 to your computer and use it in GitHub Desktop.
Save MrSaints/278806e46ad305afb4a1 to your computer and use it in GitHub Desktop.
A wrapper around `exec.Command(...).Output()` to execute external commands / binaries with support for cancellation signals via channels (i.e. terminate the running process).
package main
import (
"errors"
"log"
"os/exec"
)
var (
ErrCmdCancelled = errors.New("command cancelled")
)
func Execute(command []string, done <-chan struct{}) ([]byte, error) {
cmd := exec.Command(command[0], command[1:]...)
outCh := make(chan []byte, 1)
errCh := make(chan error, 1)
go func() {
out, err := cmd.Output()
if err != nil {
errCh <- err
return
}
outCh <- out
}()
select {
case out := <-outCh:
close(errCh)
return out, nil
case err := <-errCh:
close(outCh)
return nil, err
case <-done:
log.Println("exiting")
// if (cmd.ProcessState == nil || cmd.ProcessState.Exited() == false) && cmd.Process != nil {
if cmd.Process != nil {
if err := cmd.Process.Kill(); err != nil {
return nil, err
}
}
return nil, ErrCmdCancelled
}
}
@MrSaints
Copy link
Author

MrSaints commented Jun 26, 2017

Pro-tip: use a Context instead!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment