func KillPID(pid int, log Log) error {
	log.Debugf("Searching OS for %d to kill", pid)
	process, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("Error finding OS process: %s", err)
	}
	if process == nil {
		return fmt.Errorf("No process found with pid %d", pid)
	}
	return process.Kill()
}
KillPID kills process at pid (sends a SIGKILL on unix)
package process
import (
	"fmt"
	"os"
	"runtime"
	"syscall"
	"time"
	"github.com/keybase/go-ps"
)
type Log interface {
	Debugf(s string, args ...interface{})
	Infof(s string, args ...interface{})
	Warningf(s string, args ...interface{})
	Errorf(s string, args ...interface{})
}
type processesFn func() ([]ps.Process, error)
type breakFn func([]ps.Process) bool
func FindProcesses(matcher Matcher, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) {
	breakFn := func(procs []ps.Process) bool {
		return len(procs) > 0
	}
	return findProcesses(matcher, breakFn, wait, delay, log)
}
func WaitForExit(matcher Matcher, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) {
	breakFn := func(procs []ps.Process) bool {
		return len(procs) == 0
	}
	return findProcesses(matcher, breakFn, wait, delay, log)
}
func findProcesses(matcher Matcher, breakFn breakFn, wait time.Duration, delay time.Duration, log Log) ([]ps.Process, error) {
	start := time.Now()
	for {
		log.Debugf("Find process %s (%s < %s)", matcher.match, time.Since(start), wait)
		procs, err := findProcessesWithFn(ps.Processes, matcher.Fn(), 0)
		if err != nil {
			return nil, err
		}
		if breakFn(procs) {
			return procs, nil
		}
		if time.Since(start) >= wait {
			break
		}
		time.Sleep(delay)
	}
	return nil, nil
}
func findProcessWithPID(pid int) (ps.Process, error) {
	matchPID := func(p ps.Process) bool { return p.Pid() == pid }
	procs, err := findProcessesWithFn(ps.Processes, matchPID, 1)
	if err != nil {
		return nil, err
	}
	if len(procs) == 0 {
		return nil, nil
	}
	return procs[0], nil
}
var _ = findProcessWithPID
func findProcessesWithFn(fn processesFn, matchFn MatchFn, max int) ([]ps.Process, error) {
	processes, err := fn()
	if err != nil {
		return nil, fmt.Errorf("Error listing processes: %s", err)
	}
	if processes == nil {
		return nil, nil
	}
	procs := []ps.Process{}
	for _, p := range processes {
		if matchFn(p) {
			procs = append(procs, p)
		}
		if max != 0 && len(procs) >= max {
			break
		}
	}
	return procs, nil
}
func FindPIDsWithMatchFn(matchFn MatchFn, log Log) ([]int, error) {
	return findPIDsWithFn(ps.Processes, matchFn, log)
}
func findPIDsWithFn(fn processesFn, matchFn MatchFn, log Log) ([]int, error) {
	procs, err := findProcessesWithFn(fn, matchFn, 0)
	if err != nil {
		log.Errorf("Error finding matching processes")
		return nil, err
	}
	pids := []int{}
	for _, p := range procs {
		pids = append(pids, p.Pid())
	}
	log.Debugf("Found %d matching processes with pids: %s", len(procs), pids)
	return pids, nil
}
func TerminateAll(matcher Matcher, killDelay time.Duration, log Log) []int {
	return TerminateAllWithProcessesFn(ps.Processes, matcher.Fn(), killDelay, log)
}
func TerminateAllWithProcessesFn(fn processesFn, matchFn MatchFn, killDelay time.Duration, log Log) (terminatedPids []int) {
	pids, err := findPIDsWithFn(fn, matchFn, log)
	if err != nil {
		log.Errorf("Error finding process: %s", err)
		return terminatedPids
	}
	if len(pids) == 0 {
		return terminatedPids
	}
	for _, pid := range pids {
		if err := TerminatePID(pid, killDelay, log); err != nil {
			log.Errorf("Error terminating %d: %s", pid, err)
			continue
		}
		log.Debugf("Successfully terminated %s", pid)
		terminatedPids = append(terminatedPids, pid)
	}
	return terminatedPids
}
func TerminatePID(pid int, killDelay time.Duration, log Log) error {
	log.Debugf("Searching OS for %d to terminate", pid)
	process, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("Error finding OS process: %s", err)
	}
	if process == nil {
		return fmt.Errorf("No process found with pid %d", pid)
	}
	if runtime.GOOS == "windows" {
		return process.Kill()
	}
	log.Debugf("Terminating: %#v", process)
	err = process.Signal(syscall.SIGTERM)
	if err != nil {
		log.Warningf("Error sending terminate: %s", err)
	}
	log.Debugf("Waiting %s", killDelay)
	time.Sleep(killDelay)
	log.Debugf("Done waiting")
	_ = process.Kill()
	return err
}
func KillAll(matcher Matcher, log Log) (pids []int) {
	pids, err := findPIDsWithFn(ps.Processes, matcher.Fn(), log)
	if err != nil {
		log.Errorf("Error finding process: %s", err)
		return
	}
	if len(pids) == 0 {
		return
	}
	for _, pid := range pids {
		if err := KillPID(pid, log); err != nil {
			log.Errorf("Error killing %d: %s", pid, err)
		}
	}
	return
}