github.com/zhb127/air@v0.0.2-0.20231109030911-fb911e430cdd/runner/util_unix.go (about)

     1  //go:build unix && !linux
     2  
     3  package runner
     4  
     5  import (
     6  	"io"
     7  	"os"
     8  	"os/exec"
     9  	"syscall"
    10  	"time"
    11  )
    12  
    13  func (e *Engine) killCmd(cmd *exec.Cmd) (pid int, err error) {
    14  	pid = cmd.Process.Pid
    15  
    16  	if e.config.Build.SendInterrupt {
    17  		// Sending a signal to make it clear to the process that it is time to turn off
    18  		if err = syscall.Kill(-pid, syscall.SIGINT); err != nil {
    19  			return
    20  		}
    21  		time.Sleep(e.config.Build.KillDelay)
    22  	}
    23  	// https://stackoverflow.com/questions/22470193/why-wont-go-kill-a-child-process-correctly
    24  	err = syscall.Kill(-pid, syscall.SIGKILL)
    25  	// Wait releases any resources associated with the Process.
    26  	_, _ = cmd.Process.Wait()
    27  	return pid, err
    28  }
    29  
    30  func (e *Engine) startCmd(cmd string) (*exec.Cmd, io.ReadCloser, io.ReadCloser, error) {
    31  	c := exec.Command("/bin/sh", "-c", cmd)
    32  	// because using pty cannot have same pgid
    33  	c.SysProcAttr = &syscall.SysProcAttr{
    34  		Setpgid: true,
    35  	}
    36  
    37  	stderr, err := c.StderrPipe()
    38  	if err != nil {
    39  		return nil, nil, nil, err
    40  	}
    41  	stdout, err := c.StdoutPipe()
    42  	if err != nil {
    43  		return nil, nil, nil, err
    44  	}
    45  
    46  	c.Stdout = os.Stdout
    47  	c.Stderr = os.Stderr
    48  
    49  	err = c.Start()
    50  	if err != nil {
    51  		return nil, nil, nil, err
    52  	}
    53  	return c, stdout, stderr, nil
    54  }