github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/command/local_command.go (about)

     1  package command
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"os/exec"
     7  	"strings"
     8  	"sync"
     9  
    10  	"github.com/mongodb/grip"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  type LocalCommand struct {
    15  	CmdString        string
    16  	WorkingDirectory string
    17  	Shell            string
    18  	Environment      []string
    19  	ScriptMode       bool
    20  	Stdout           io.Writer
    21  	Stderr           io.Writer
    22  	Cmd              *exec.Cmd
    23  	mutex            sync.RWMutex
    24  }
    25  
    26  func (lc *LocalCommand) Run() error {
    27  	err := lc.Start()
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	lc.mutex.RLock()
    33  	defer lc.mutex.RUnlock()
    34  
    35  	return lc.Cmd.Wait()
    36  }
    37  
    38  func (lc *LocalCommand) GetPid() int {
    39  	lc.mutex.RLock()
    40  	defer lc.mutex.RUnlock()
    41  
    42  	if lc.Cmd == nil {
    43  		return -1
    44  	}
    45  
    46  	return lc.Cmd.Process.Pid
    47  }
    48  
    49  func (lc *LocalCommand) Start() error {
    50  	lc.mutex.Lock()
    51  	defer lc.mutex.Unlock()
    52  
    53  	if lc.Shell == "" {
    54  		lc.Shell = "sh"
    55  	}
    56  
    57  	var cmd *exec.Cmd
    58  	if lc.ScriptMode {
    59  		cmd = exec.Command(lc.Shell)
    60  		cmd.Stdin = strings.NewReader(lc.CmdString)
    61  	} else {
    62  		cmd = exec.Command(lc.Shell, "-c", lc.CmdString)
    63  	}
    64  
    65  	// create the command, set the options
    66  	if lc.WorkingDirectory != "" {
    67  		cmd.Dir = lc.WorkingDirectory
    68  	}
    69  	cmd.Env = lc.Environment
    70  	if cmd.Env == nil {
    71  		cmd.Env = os.Environ()
    72  	}
    73  	cmd.Stdout = lc.Stdout
    74  	cmd.Stderr = lc.Stderr
    75  
    76  	// cache the command running
    77  	lc.Cmd = cmd
    78  
    79  	// start the command
    80  	return cmd.Start()
    81  }
    82  
    83  func (lc *LocalCommand) Stop() error {
    84  	lc.mutex.Lock()
    85  	defer lc.mutex.Unlock()
    86  
    87  	if lc.Cmd != nil && lc.Cmd.Process != nil {
    88  		return lc.Cmd.Process.Kill()
    89  	}
    90  	grip.Warning("Trying to stop command but Cmd / Process was nil")
    91  	return nil
    92  }
    93  
    94  func (lc *LocalCommand) PrepToRun(expansions *Expansions) error {
    95  	lc.mutex.Lock()
    96  	defer lc.mutex.Unlock()
    97  
    98  	var err error
    99  
   100  	lc.CmdString, err = expansions.ExpandString(lc.CmdString)
   101  	if err != nil {
   102  		return errors.WithStack(err)
   103  	}
   104  
   105  	lc.WorkingDirectory, err = expansions.ExpandString(lc.WorkingDirectory)
   106  	return errors.WithStack(err)
   107  }
   108  
   109  type LocalCommandGroup struct {
   110  	Commands   []*LocalCommand
   111  	Expansions *Expansions
   112  }
   113  
   114  func (lc *LocalCommandGroup) PrepToRun() error {
   115  	for _, cmd := range lc.Commands {
   116  		if err := cmd.PrepToRun(lc.Expansions); err != nil {
   117  			return err
   118  		}
   119  	}
   120  	return nil
   121  }