github.com/reconquest/executil-go@v0.0.0-20181110204642-1f5c2d67813f/run.go (about)

     1  package executil
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"os/exec"
     7  )
     8  
     9  type option int
    10  
    11  const (
    12  	// IgnoreStdout is option for executil.Run() which should be passed if
    13  	// stdout data should be ignored.
    14  	IgnoreStdout option = iota
    15  
    16  	// IgnoreStderr is option for executil.Run() which should be passed if
    17  	// stderr data should be ignored.
    18  	IgnoreStderr
    19  )
    20  
    21  // Run sets writers for stdout and stderr, starts the specified command and
    22  // waits for it to complete.
    23  //
    24  // The returned error is nil if the command runs, has no problems
    25  // copying stdin, stdout, and stderr, and exits with a zero exit
    26  // status.
    27  // Otherwise, the error is of type Error.
    28  func Run(
    29  	cmd *exec.Cmd, options ...option,
    30  ) (stdout []byte, stderr []byte, err error) {
    31  	var (
    32  		stdoutBuffer   = &bytes.Buffer{}
    33  		stderrBuffer   = &bytes.Buffer{}
    34  		combinedBuffer = &threadsafeBuffer{}
    35  
    36  		ignoreStdout bool
    37  		ignoreStderr bool
    38  	)
    39  
    40  	for _, option := range options {
    41  		switch option {
    42  		case IgnoreStdout:
    43  			ignoreStdout = true
    44  
    45  		case IgnoreStderr:
    46  			ignoreStderr = true
    47  		}
    48  	}
    49  
    50  	if !ignoreStdout {
    51  		cmd.Stdout = io.MultiWriter(stdoutBuffer, combinedBuffer)
    52  	}
    53  	if !ignoreStderr {
    54  		cmd.Stderr = io.MultiWriter(stderrBuffer, combinedBuffer)
    55  	}
    56  
    57  	runErr := cmd.Run()
    58  	if runErr != nil {
    59  		err = &Error{
    60  			RunErr: runErr,
    61  			Cmd:    cmd,
    62  			Output: combinedBuffer.Bytes(),
    63  		}
    64  	}
    65  
    66  	return stdoutBuffer.Bytes(), stderrBuffer.Bytes(), err
    67  }