Documentation
¶
Overview ¶
Package runner exposes a simple interface for executing commands, enabling easy mocking and wrapping of executed commands.
The Runner interface is basic and minimal, but it is sufficient for most use cases. This makes it easy to mock Runner for testing purposes.
It's also easy to create wrapper runners which modify commands before executing them. The Sudo struct is a simple example of this.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrSSHCLI = fmt.Errorf("%w: sshcli: ", Err) ErrSSHCLINoDestination = fmt.Errorf( "%w: destination must be set", ErrSSHCLI, ) )
var Err = errors.New("runner")
Functions ¶
This section is empty.
Types ¶
type Local ¶
type Local struct {
// contains filtered or unexported fields
}
Local is a Runner implementation that executes commands locally on the host machine.
func (*Local) Env ¶
Env sets the environment which will apply to all commands invoked by the runner. Each entry is of the form "key=value".
func (*Local) Run ¶
func (r *Local) Run( stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
Run executes the given command locally on the host machine.
func (*Local) RunContext ¶
func (r *Local) RunContext( ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
RunContext executes the given command locally on the host machine, using the provided context to kill the process if the context becomes done before the command completes on its own.
type Runner ¶
type Runner interface { // Run executes the given command with any provided arguments. Stdin, // Stdout, and Stderr can be provided/captured if the io.Reader/Writer is // not nil. Run( stdin io.Reader, stdout, stderr io.Writer, command string, args ...string, ) error // RunContext is like Run but includes a context. // // The provided context is used to kill the command process if the context // becomes done before the command completes on its own. RunContext( ctx context.Context, stdin io.Reader, stdout, stderr io.Writer, command string, args ...string, ) error // Env specifies the environment variables which will be available to all // commands invoked by the runner. Each entry is of the form "key=value". // Entries with duplicate keys will cause all but the last to be ignored. // // Multiple calls to Env will overwrite any previous calls to Env. // // If no env is set, no environment variables will be set for executed // commands. // // To set the environment to match that of the Go runtime, call Env with // os.Environ(). Env(env ...string) }
Runner is the interface that all runner structs implements. It makes it easy to replace the underlying command runner with a mock for testing, or a different runner that executes givens commands in a different manner.
Example (Basic) ¶
var stdout bytes.Buffer r := runner.New() _ = r.Run(nil, &stdout, nil, "echo", "Hello world!") fmt.Print(stdout.String())
Output: Hello world!
Example (Combined) ¶
var out bytes.Buffer r := runner.New() err := r.Run( nil, &out, &out, "sh", "-c", "echo 'Hello world!'; echo 'Oh noes! :(' >&2", ) if err != nil { fmt.Println(err) } fmt.Print(out.String())
Output: Hello world! Oh noes! :(
Example (Context) ¶
var stdout bytes.Buffer ctx, cancel := context.WithTimeout( context.Background(), 1*time.Second, ) defer cancel() r := runner.New() err := r.RunContext( ctx, nil, &stdout, nil, "sh", "-c", "sleep 0.5 && echo 'Hello world!'", ) if err != nil { fmt.Println(err) } fmt.Print(stdout.String())
Output: Hello world!
Example (ContextTimeout) ¶
var stdout, stderr bytes.Buffer ctx, cancel := context.WithTimeout( context.Background(), 100*time.Millisecond, ) defer cancel() r := runner.New() err := r.RunContext( ctx, nil, &stdout, &stderr, "sh", "-c", "sleep 0.5 && echo 'Hello world!'", ) if err != nil { fmt.Println(err) }
Output: signal: killed
Example (Environment) ¶
var stdout bytes.Buffer r := runner.New() r.Env("USER=johndoe", "HOME=/home/johnny") _ = r.Run(nil, &stdout, nil, "sh", "-c", `echo "Hi, ${USER} (${HOME})"`) fmt.Print(stdout.String())
Output: Hi, johndoe (/home/johnny)
Example (Failure) ¶
var stdout, stderr bytes.Buffer r := runner.New() err := r.Run( nil, &stdout, &stderr, "sh", "-c", "echo 'Hello world!'; echo 'Oh noes! :(' >&2; exit 3", ) if err != nil { fmt.Printf("%s: %s", err.Error(), stderr.String()) }
Output: exit status 3: Oh noes! :(
Example (Stderr) ¶
var stderr bytes.Buffer r := runner.New() err := r.Run(nil, nil, &stderr, "sh", "-c", "echo 'Oh noes! :(' >&2") if err != nil { fmt.Println(err) } fmt.Print(stderr.String())
Output: Oh noes! :(
Example (Stdin) ¶
var stdout bytes.Buffer r := runner.New() _ = r.Run(bytes.NewBufferString("Hello world!"), &stdout, nil, "cat") fmt.Print(stdout.String())
Output: Hello world!
Example (StdinStdoutAndStderr) ¶
stdin := bytes.NewBufferString("Hello world!") var stdout, stderr bytes.Buffer r := runner.New() err := r.Run( stdin, &stdout, &stderr, "sh", "-c", "cat; echo 'Oh noes! :(' >&2", ) if err != nil { fmt.Println(err) } fmt.Print(stderr.String()) fmt.Print(stdout.String())
Output: Oh noes! :( Hello world!
Example (StdoutAndStderr) ¶
var stdout, stderr bytes.Buffer r := runner.New() err := r.Run( nil, &stdout, &stderr, "sh", "-c", "echo 'Hello world!'; echo 'Oh noes! :(' >&2", ) if err != nil { fmt.Println(err) } fmt.Print(stderr.String()) fmt.Print(stdout.String())
Output: Oh noes! :( Hello world!
type SSHCLI ¶ added in v0.1.4
type SSHCLI struct { // Runner is the underlying Runner to run commands with, after wrapping them // with ssh. If not set, running commands will cause a panic. Runner Runner // Destination is the remote SSH destination to connect to, which may be // specified as either "[user@]hostname" or a URI of the form // "ssh://[user@]hostname[:port]". Destination string // Port is the remote SSH port (-p) flag to use. When 0, no -p flag will be // used. Port int // IdentityFile is the remote SSH identity file (-i) flag to use. When // empty, no -i flag will be used. IdentityFile string // Login is the remote SSH login (-l) flag to use. When empty, no -l flag // will be used. Login string // Args is a string slice of extra arguments to pass to ssh. Args []string // contains filtered or unexported fields }
SSHCLI is a Runner that wraps another Runner, essentially prefixing given commands and arguments with "ssh", relevant SSH CLI arguments, and the given destination. It then passes this new "ssh" command to the underlying Runner.
This is useful for running commands on remote hosts via SSH, without having to use the Go ssh package.
Interactive commands are not supported, meaning SSH password prompts will not work, and the remote machine's hostkey should already be known and trusted by the ssh CLI client.
func (*SSHCLI) Env ¶ added in v0.1.4
Env sets the environment by calling Env on the underlying Runner. Will panic if Runner field is nil on SSH instance.
func (*SSHCLI) Run ¶ added in v0.1.4
func (rsc *SSHCLI) Run( stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
Run executes the command remotely via ssh by calling Run on the underlying Runner.
Will panic if Runner field is nil. Will return a error if Destination field is empty.
func (*SSHCLI) RunContext ¶ added in v0.1.4
func (rsc *SSHCLI) RunContext( ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
RunContext executes the command remotely via ssh by calling RunContext on the underlying Runner.
Will panic if Runner field is nil. Will return a error if Destination field is empty.
type Sudo ¶
type Sudo struct { // Runner is the underlying Runner to run commands with, after wrapping them // with sudo. If not set, running commands will cause a panic. Runner Runner // User value passed to sudo via -u flag. User string // Args is a string slice of extra arguments to pass to sudo. Args []string // contains filtered or unexported fields }
Sudo is a Runner that wraps another Runner and runs commands via sudo.
Password prompts are not supported, hence commands must be set to NOPASS via the sudoers file before they can be run.
func (*Sudo) Env ¶
Env sets the environment by calling Env on the underlying Runner. Will panic if Runner field is nil on Sudo instance.
func (*Sudo) Run ¶
func (r *Sudo) Run( stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
Run executes the command via sudo by calling Run on the underlying Runner. Will panic if Runner field is nil on Sudo instance.
func (*Sudo) RunContext ¶
func (r *Sudo) RunContext( ctx context.Context, stdin io.Reader, stdout io.Writer, stderr io.Writer, command string, args ...string, ) error
RunContext executes the command via sudo by calling RunContext on the underlying Runner. Will panic if Runner field is nil on Sudo instance.
type Testing ¶ added in v0.1.2
type Testing struct { // Runner is the underlying Runner to run commands with. If not set, running // commands will cause a panic. Runner Runner // TestingT is the *testing.T instance used to log output. If not set, // running commands will cause a panic. TestingT TestingT // LogEnv indicates if calls to Env() should be logged. LogEnv bool }
Testing is a Runner that wraps another Runner, and logs all executed commands and their arguments to a *testing.T instance.
Both Runner and T must be non-nil, or running commands will cause a panic.
func (*Testing) Env ¶ added in v0.1.2
Env sets the environment variables for the underlying Runner, and if LogEnv is true it logs the given environment variables to TestingT.