exec

package
v0.0.0-...-03d6fc4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 23, 2019 License: BSD-3-Clause Imports: 13 Imported by: 0

Documentation

Overview

A wrapper around the os/exec package that supports timeouts and testing.

Example usage:

Simple command with argument:

err := Run(&Command{
	Name: "touch",
	Args: []string{file},
})

More complicated example: output := bytes.Buffer{}

err := Run(&Command{
	Name: "make",
	Args: []string{"all"},
	// Set environment:
	Env: []string{fmt.Sprintf("GOPATH=%s", projectGoPath)},
	// Set working directory:
	Dir: projectDir,
	// Capture output:
	CombinedOutput: &output,
	// Set a timeout:
	Timeout: 10*time.Minute,
})

Inject a Run function for testing: var actualCommand *Command

SetRunForTesting(func(command *Command) error {
	actualCommand = command
	return nil
})

defer SetRunForTesting(DefaultRun) TestCodeCallingRun() expect.Equal(t, "touch", actualCommand.Name) expect.Equal(t, 1, len(actualCommand.Args)) expect.Equal(t, file, actualCommand.Args[0])

Types and functions to help with testing code that uses exec.Run.

Index

Constants

View Source
const (
	TIMEOUT_ERROR_PREFIX = "Command killed since it took longer than"
)

Variables

View Source
var (
	WriteInfoLog    = WriteLog{LogFunc: sklog.Infof}
	WriteWarningLog = WriteLog{LogFunc: sklog.Warningf}
)

Functions

func DebugString

func DebugString(command *Command) string

Returns the Env, Name, and Args of command joined with spaces. Does not perform any quoting.

func DefaultRun

func DefaultRun(command *Command) error

DefaultRun can be passed to SetRunForTesting to go back to running commands as normal.

func IsTimeout

func IsTimeout(err error) bool

IsTimeout returns true if the specified error was raised due to a command timing out.

func NewContext

func NewContext(ctx context.Context, runFn func(*Command) error) context.Context

NewContext returns a context.Context instance which uses the given function to run Commands.

func NoInterruptContext

func NoInterruptContext(ctx context.Context) context.Context

NoInterruptContext returns a context.Context instance which launches subprocesses in a difference process group so that they are not killed when this process is killed.

This function is a no-op on Windows.

func Run

func Run(ctx context.Context, command *Command) error

Run runs command and waits for it to finish. If any failure, returns non-nil. If a timeout was specified, returns an error once the command has exceeded that timeout.

func RunCommand

func RunCommand(ctx context.Context, command *Command) (string, error)

RunCommand executes the given command and returns the combined stdout and stderr. May also return an error if the command exited with a non-zero status or there is any other error.

func RunCwd

func RunCwd(ctx context.Context, cwd string, args ...string) (string, error)

RunCwd executes the given command in the given directory. Returns the combined stdout and stderr. May also return an error if the command exited with a non-zero status or there is any other error.

func RunSimple

func RunSimple(ctx context.Context, commandLine string) (string, error)

RunSimple executes the given command line string; the command being run is expected to not care what its current working directory is. Returns the combined stdout and stderr. May also return an error if the command exited with a non-zero status or there is any other error.

Types

type Command

type Command struct {
	// Name of the command, as passed to osexec.Command. Can be the path to a binary or the
	// name of a command that osexec.Lookpath can find.
	Name string
	// Arguments of the command, not including Name.
	Args []string
	// The environment of the process. If nil, the current process's environment is used.
	Env []string
	// If Env is non-nil, adds the current process's entire environment to Env, excluding
	// variables that are set in Env.
	InheritEnv bool
	// If Env is non-nil, adds the current process's PATH to Env. Do not include PATH in Env.
	InheritPath bool
	// The working directory of the command. If nil, runs in the current process's current
	// directory.
	Dir string
	// See docs for osexec.Cmd.Stdin.
	Stdin io.Reader
	// If true, duplicates stdout of the command to WriteInfoLog.
	LogStdout bool
	// Sends the stdout of the command to this Writer, e.g. os.File or bytes.Buffer.
	Stdout io.Writer
	// If true, duplicates stderr of the command to WriteWarningLog.
	LogStderr bool
	// Sends the stderr of the command to this Writer, e.g. os.File or bytes.Buffer.
	Stderr io.Writer
	// Sends the combined stdout and stderr of the command to this Writer, in addition to
	// Stdout and Stderr. Only one goroutine will write at a time. Note: the Go runtime seems to
	// combine stdout and stderr into one stream as long as LogStdout and LogStderr are false
	// and Stdout and Stderr are nil. Otherwise, the stdout and stderr of the command could be
	// arbitrarily reordered when written to CombinedOutput.
	CombinedOutput io.Writer
	// Time limit to wait for the command to finish. No limit if not specified.
	Timeout time.Duration
	// Whether to log when the command starts.
	Verbose Verbosity
	// SysProcAttr holds optional, operating system-specific attributes.
	// Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
	SysProcAttr *syscall.SysProcAttr
}

func ParseCommand

func ParseCommand(commandLine string) Command

Divides commandLine at spaces; treats the first token as the program name and the other tokens as arguments. Note: don't expect this function to do anything smart with quotes or escaped spaces.

type CommandCollector

type CommandCollector struct {
	// contains filtered or unexported fields
}

CommandCollector collects arguments to the Run method for later inspection. Safe for use in multiple goroutines as long as the function passed to SetDelegateRun is. Example usage:

mock := CommandCollector{}
SetRunForTesting(mock.Run)
defer SetRunForTesting(DefaultRun)
err := Run(&Command{
	Name: "touch",
	Args: []string{"/tmp/file"},
})
assert.Equal(t, "touch /tmp/file"", DebugString(mock.Commands()[0]))

func (*CommandCollector) ClearCommands

func (c *CommandCollector) ClearCommands()

func (*CommandCollector) Commands

func (c *CommandCollector) Commands() []*Command

func (*CommandCollector) Run

func (c *CommandCollector) Run(command *Command) error

Collects command into c and delegates to the function specified by SetDelegateRun. Returns nil if SetDelegateRun has not been called. The command will be visible in Commands() before the SetDelegateRun function is called.

func (*CommandCollector) SetDelegateRun

func (c *CommandCollector) SetDelegateRun(delegateRun func(*Command) error)

type MockRun

type MockRun struct {
	// contains filtered or unexported fields
}

Provides a Run method that returns based on regexp matches of DebugString(command). Safe for use in multiple goroutines. Example usage:

mock := MockRun{}
SetRunForTesting(mock.Run)
defer SetRunForTesting(DefaultRun)
mock.AddRule("touch /tmp/bar", fmt.Errorf("baz"))
assert.NoError(t, Run(&Command{
	Name: "touch",
	Args: []string{"/tmp/foo"},
}))
err := Run(&Command{
	Name: "touch",
	Args: []string{"/tmp/bar"},
})
assert.Error(t, err)
assert.Contains(t, err.Error(), "baz")

func (*MockRun) AddRule

func (m *MockRun) AddRule(expr string, err error)

Panics if expr is not a valid regexp.

func (*MockRun) Run

func (m *MockRun) Run(command *Command) error

Tries to match DebugString(command) against the regexps in the order of the calls to AddRule, with the first matched giving the return value. Returns nil if no regexps match.

type Process

type Process interface {
	Kill() error
}

func RunIndefinitely

func RunIndefinitely(command *Command) (Process, <-chan error, error)

RunIndefinitely starts the command and then returns. Clients can listen for the command to end on the returned channel or kill the process manually using the Process handle. The timeout param is ignored if it is set. If starting the command returns an error, that error is returned.

type Verbosity

type Verbosity int
const (
	Info Verbosity = iota
	Debug
	Silent
)

type WriteLog

type WriteLog struct {
	LogFunc func(format string, args ...interface{})
}

WriteLog implements the io.Writer interface and writes to the given log function.

func (WriteLog) Write

func (wl WriteLog) Write(p []byte) (n int, err error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL