shell

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 11, 2019 License: MIT Imports: 16 Imported by: 7

Documentation

Overview

Package shell provides convenience wrappers around os/exec.

Specifically, it is designed to loosely emulate an ordinary shell session, with persistent directory context. It provides many helper functions around processing output streams into Go-friendly structures, and returning errors in an expected way.

In general, and functions that specifically look for exit codes or output on stderr do not return an error for non-zero exit codes; they still return errors for other problems, like the process not starting due to failure to attach pipes, the binary not existing, etc. All other helper functions return errors for non-zero exit codes.

This package is designed to aid with logging sessions, good for building CLI applications that shell out, and exposing these sessions to the user.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewTestCommand added in v1.0.1

func NewTestCommand() (*TestCommand, *TestCommandController)

NewTestCommand returns a new TestCommand and a TestCommandController with which it can be controlled and inspected.

func NewTestShell

func NewTestShell() (*TestShell, *TestShellController)

NewTestShell builds a test shell, notionally at path, with a set of files available to it built from the files map. Note that relative paths in the map are considered wrt the path

Types

type Cmd

type Cmd interface {
	// Stdout returns the stdout stream as a string. It returns an error for the
	// same reasons as .Succeed
	Stdout() (string, error)
	// Stderr is returns the stderr stream as a string. It returns an error for the
	// same reasons as .Result
	Stderr() (string, error)
	// Stdin sets the Stdin of the command
	SetStdin(io.Reader)
	// Lines returns Stdout split by newline. Leading and trailing empty lines are
	// removed, and each line is trimmed of whitespace.
	Lines() ([]string, error)
	// Table is similar to Lines, except lines are further split by whitespace.
	Table() ([][]string, error)
	// JSON tries to parse the stdout from the command as JSON, populating the
	// value you pass. (This value should be a pointer.)
	JSON(v interface{}) error
	// ExitCode only returns an error if there were io issues starting the command,
	// it does not return an error for a command which fails and returns an error
	// code, which is unlike most of Sh's methods. If it returns an error, then it
	// also returns -1 for the exit code.
	ExitCode() (int, error)
	// Result only returns an error if it's a startup error, not if the command
	// itself exits with an error code. If you need an error to be returned on
	// non-zero exit codes, use SucceedResult instead.
	Result() (*Result, error)
	// SucceedResult is similar to Result, except that it also returns an error if
	// the command itself fails (returns a non-zero exit code).
	SucceedResult() (*Result, error)
	// Succeed returns an error if the command fails for any reason (fails to start
	// or finishes with a non-zero exist code).
	Succeed() error
	// Fail returns an error if the command succeeds to execute, or if it fails to
	// start. It returns nil only if the command starts successfully and then exits
	// with a non-zero exit code.
	Fail() error
	// FailResult returns an error when the command fails to be invoked at all, or
	// when the command is successfully invoked, and then runs successfully. It
	// does not return an error when the command is invoked successfully and then
	// fails.
	FailResult() (*Result, error)
	// String prints out this command.
	String() string
}

Cmd is an interface to describe commands being executed by a Shell

type Command

type Command struct {
	// Dir is the directory this command will execute in.
	Dir,

	Name string
	// Args is a list of args to be passed to the command.
	Args []string
	// Stdin is (possibly) a string to feed to the command.
	Stdin io.Reader
	// ConsoleEcho will be passed the command just before it is executed,
	// and the resultant combined output afterwards.
	ConsoleEcho func(string)
	// TeeOut will be connected to stdout via a multireader, unless it is
	// nil.
	TeeOut,

	TeeErr io.Writer
	// Debug indicates if this command is in debug mode. If true, every
	// command and its combined output will be printed to screen.
	Debug bool
	// LongRunning indicates that this command is expected to take a while.
	// This is handled by attaching the stdout/stderr directly to the system
	// defaults. This also means the command's TTY is set to the user's.
	LongRunning bool
}

Command is a wrapper around an exec.Cmd

func (*Command) ExitCode

func (c *Command) ExitCode() (int, error)

ExitCode only returns an error if there were io issues starting the command, it does not return an error for a command which fails and returns an error code, which is unlike most of Sh's methods. If it returns an error, then it also returns -1 for the exit code.

func (*Command) Fail

func (c *Command) Fail() error

Fail returns an error if the command succeeds to execute, or if it fails to start. It returns nil only if the command starts successfully and then exits with a non-zero exit code.

func (*Command) FailResult

func (c *Command) FailResult() (*Result, error)

FailResult returns an error when the command fails to be invoked at all, or when the command is successfully invoked, and then runs successfully. It does not return an error when the command is invoked successfully and then fails.

func (*Command) JSON

func (c *Command) JSON(v interface{}) error

JSON tries to parse the stdout from the command as JSON, populating the value you pass. (This value should be a pointer.)

func (*Command) Lines

func (c *Command) Lines() ([]string, error)

Lines returns Stdout split by newline. Leading and trailing empty lines are removed, and each line is trimmed of whitespace.

func (*Command) Result

func (c *Command) Result() (*Result, error)

Result only returns an error if it's a startup error, not if the command itself exits with an error code. If you need an error to be returned on non-zero exit codes, use SucceedResult instead.

func (*Command) SetStdin

func (c *Command) SetStdin(in io.Reader)

SetStdin sets the stdin on the command

func (*Command) Stderr

func (c *Command) Stderr() (string, error)

Stderr is returns the stderr stream as a string. It returns an error for the same reasons as .Result

func (*Command) Stdout

func (c *Command) Stdout() (string, error)

Stdout returns the stdout stream as a string. It returns an error for the same reasons as .Succeed

func (*Command) String

func (c *Command) String() string

func (*Command) Succeed

func (c *Command) Succeed() error

Succeed returns an error if the command fails for any reason (fails to start or finishes with a non-zero exist code).

func (*Command) SucceedResult

func (c *Command) SucceedResult() (*Result, error)

SucceedResult is similar to Result, except that it also returns an error if the command itself fails (returns a non-zero exit code).

func (*Command) Table

func (c *Command) Table() ([][]string, error)

Table is similar to Lines, except lines are further split by whitespace.

type Error

type Error struct {
	// Err is the original error that was returned.
	Err error
	// Result is the complete result of the command execution that caused
	// this error.
	Result *Result
	// Command is the command which caused this error.
	Command Cmd
}

Error wraps command errors

func (Error) Error

func (e Error) Error() string

Error returns the error, prefixed with "shell> "

type Output

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

Output represents a read-only output stream of a command.

func (*Output) Bytes

func (o *Output) Bytes() []byte

Bytes returns the entire output as a byte slice.

func (*Output) Lines

func (o *Output) Lines() []string

Lines gives the entire output as a string slice, with each item in the slice representing one line of the output. Lines are determined by splitting the string on newline characters. Preceding and trailing empty lines are removed from the output, and each line is trimmed of whitespace.

func (*Output) Reader

func (o *Output) Reader() io.Reader

Reader returns a reader, allowing you to read the entire output.

func (*Output) String

func (o *Output) String() string

String is gives the entire output as a string, with whitespace trimmed.

func (*Output) Table

func (o *Output) Table() [][]string

Table treats the entire output like a table. First it splits the output into lines in the same way as Lines(). Then, each line is further split by all regions of contiguous whitespace. Empty lines are removed.

type Result

type Result struct {
	Command                  Cmd
	Stdout, Stderr, Combined *Output
	Err                      error
	ExitCode                 int
}

Result is the result of running a command to completion.

type Sh

type Sh struct {
	// Cwd is the working directory of the shell.
	Cwd string
	// Env is the environment variables of the shell.
	Env []string
	// If TeeEcho is non-nil, all the commands executed on this shell will be
	// written to it
	TeeEcho,

	TeeOut,

	TeeErr io.Writer
	// Debug sets each command issued by this shell into debug mode, or not
	// depending on this value.
	Debug bool
	// contains filtered or unexported fields
}

Sh is a shell helper.

func Default

func Default() (*Sh, error)

Default creates a new shell with all of the current environment variables from the current process added. This is useful if you want to, ensure that the PATH is set, along with all other environment variables the user had set when they invoked your Go program.

If you do not need the user's environment, you can create a new shell also using &shell.Sh{}

func DefaultInDir

func DefaultInDir(path string) (*Sh, error)

DefaultInDir is similar to Default, but immediately CDs into the specified directory. The path can be relative or absolute. If relative, it begins from the current working directory.

func (*Sh) Abs

func (s *Sh) Abs(path string) string

Abs returns the absolute path of the path provided in relation to this shell. If the path is already absolute, it is returned simplified but otherwise unchanged.

func (*Sh) CD

func (s *Sh) CD(dir string) error

CD changes the directory of this shell to the path specified. If the path is relative, the directory is attempted to be changed relative to the current dir. If the directory does not exist, CD returns an error.

func (*Sh) Clone

func (s *Sh) Clone() Shell

Clone returns a deep copy of this shell.

func (*Sh) Cmd

func (s *Sh) Cmd(name string, args ...interface{}) Cmd

Cmd creates a new Command based on this shell.

func (*Sh) ConsoleEcho

func (s *Sh) ConsoleEcho(line string)

ConsoleEcho prints the command that sous is executing out

func (*Sh) Dir

func (s *Sh) Dir() string

Dir returns the directory for this shell

func (*Sh) Exists

func (s *Sh) Exists(path string) bool

Exists returns true if the path definitely exists. It swallows any errors and returns false, in the case that e.g. permissions prevent the check from working correctly.

func (*Sh) ExitCode

func (s *Sh) ExitCode(name string, args ...interface{}) (int, error)

ExitCode (...) is a shortcut for shell.Cmd(...).ExitCode()

func (*Sh) JSON

func (s *Sh) JSON(v interface{}, name string, args ...interface{}) error

JSON (x, ...) is a shortcut for shell.Cmd(...).JSON(x)

func (*Sh) Lines

func (s *Sh) Lines(name string, args ...interface{}) ([]string, error)

Lines (...) is a shortcut for shell.Cmd(...).Lines()

func (*Sh) List

func (s *Sh) List() ([]os.FileInfo, error)

List returns all files (including dotfiles) inside Dir.

func (*Sh) LongRunning added in v0.0.3

func (s *Sh) LongRunning(yes bool)

LongRunning sets the longRunning flag

func (*Sh) Run

func (s *Sh) Run(name string, args ...interface{}) error

Run (...) is a shortcut for shell.Cmd(...).Succeed()

func (*Sh) Stat

func (s *Sh) Stat(path string) (os.FileInfo, error)

Stat calls os.Stat on the path provided, relative to the current shell's working directory.

func (*Sh) Stderr

func (s *Sh) Stderr(name string, args ...interface{}) (string, error)

Stderr (...) is a shortcut for shell.Cmd(...).Stderr()

func (*Sh) Stdout

func (s *Sh) Stdout(name string, args ...interface{}) (string, error)

Stdout (...) is a shortcut for shell.Cmd(...).Stdout()

type Shell

type Shell interface {
	// Clone returns a deep copy of this shell.
	Clone() Shell
	// Dir simply returns the current working directory for this Shell
	Dir() string
	// List returns all files (including dotfiles) inside Dir.
	List() ([]os.FileInfo, error)
	// Abs returns the absolute path of the path provided in relation to this shell.
	// If the path is already absolute, it is returned simplified but otherwise
	// unchanged.
	Abs(path string) string
	// Stat calls os.Stat on the path provided, relative to the current
	// shell's working directory.
	Stat(path string) (os.FileInfo, error)
	// Exists returns true if the path definitely exists. It swallows
	// any errors and returns false, in the case that e.g. permissions
	// prevent the check from working correctly.
	Exists(path string) bool
	// ConsoleEcho outputs the line as if it were typed at the console
	ConsoleEcho(line string)
	// LongRunning marks a Shell as dealing with long running commands
	LongRunning(bool)
	// Cmd creates a new Command based on this shell.
	Cmd(name string, args ...interface{}) Cmd
	// CD changes the directory of this shell to the path specified. If the path is
	// relative, the directory is attempted to be changed relative to the current
	// dir. If the directory does not exist, CD returns an error.
	CD(dir string) error
	// Run(...) is a shortcut for shell.Cmd(...).Succeed()
	Run(name string, args ...interface{}) error
	// Stdout(...) is a shortcut for shell.Cmd(...).Stdout()
	Stdout(name string, args ...interface{}) (string, error)
	// Stderr(...) is a shortcut for shell.Cmd(...).Stderr()
	Stderr(name string, args ...interface{}) (string, error)
	// ExitCode(...) is a shortcut for shell.Cmd(...).ExitCode()
	ExitCode(name string, args ...interface{}) (int, error)
	// Lines(...) is a shortcut for shell.Cmd(...).Lines()
	Lines(name string, args ...interface{}) ([]string, error)
	// JSON(x, ...) is a shortcut for shell.Cmd(...).JSON(x)
	JSON(v interface{}, name string, args ...interface{}) error
}

Shell is a shell helper.

type TestCommand added in v1.0.1

type TestCommand struct {
	*spies.Spy
}

TestCommand is a test wrapper for Command

func (*TestCommand) ExitCode added in v1.0.1

func (c *TestCommand) ExitCode() (int, error)

ExitCode implements Cmd on TestCommand

func (*TestCommand) Fail added in v1.0.1

func (c *TestCommand) Fail() error

Fail implements Cmd on TestCommand

func (*TestCommand) FailResult added in v1.0.1

func (c *TestCommand) FailResult() (*Result, error)

FailResult implements Cmd on TestCommand

func (*TestCommand) JSON added in v1.0.1

func (c *TestCommand) JSON(v interface{}) error

JSON implements Cmd on TestCommand

func (*TestCommand) Lines added in v1.0.1

func (c *TestCommand) Lines() ([]string, error)

Lines implements Cmd on TestCommand

func (*TestCommand) Result added in v1.0.1

func (c *TestCommand) Result() (*Result, error)

Result implements Cmd on TestCommand

func (*TestCommand) SetStdin added in v1.0.1

func (c *TestCommand) SetStdin(r io.Reader)

SetStdin implements Cmd on TestCommand

func (*TestCommand) Stderr added in v1.0.1

func (c *TestCommand) Stderr() (string, error)

Stderr implements Cmd on TestCommand

func (*TestCommand) Stdout added in v1.0.1

func (c *TestCommand) Stdout() (string, error)

Stdout implements Cmd on TestCommand

func (*TestCommand) String added in v1.0.1

func (c *TestCommand) String() string

String implements Cmd on TestCommand

func (*TestCommand) Succeed added in v1.0.1

func (c *TestCommand) Succeed() error

Succeed implements Cmd on TestCommand

func (*TestCommand) SucceedResult added in v1.0.1

func (c *TestCommand) SucceedResult() (*Result, error)

SucceedResult implements Cmd on TestCommand

func (*TestCommand) Table added in v1.0.1

func (c *TestCommand) Table() ([][]string, error)

Table implements Cmd on TestCommand

type TestCommandController added in v1.0.1

type TestCommandController struct {
	*spies.Spy
	// contains filtered or unexported fields
}

TestCommandController Allows an associated TestCommand to be controlled and inspected

func (*TestCommandController) ResultFailure added in v1.0.1

func (c *TestCommandController) ResultFailure(out, err string)

ResultFailure see above but unsuccessfully

func (*TestCommandController) ResultSuccess added in v1.0.1

func (c *TestCommandController) ResultSuccess(out, err string)

ResultSuccess sets up the TestCommand to behave like it ran successfully with particular stdout/stderr.

type TestCommandResult added in v1.0.1

type TestCommandResult struct {
	SO, SE []byte
	Err    error
	Status int
}

TestCommandResult describes the dummy results of a dummy command

type TestShell

type TestShell struct {
	*spies.Spy
}

TestShell is a test instance for Sh

func (*TestShell) Abs added in v1.0.1

func (s *TestShell) Abs(path string) string

Abs implements Shell on TestShell

func (*TestShell) CD added in v1.0.1

func (s *TestShell) CD(dir string) error

CD implements Shell on TestShell

func (*TestShell) Clone added in v1.0.1

func (s *TestShell) Clone() Shell

Clone implements Shell on TestShell

func (*TestShell) Cmd

func (s *TestShell) Cmd(name string, args ...interface{}) Cmd

Cmd creates a new Command based on this shell.

func (*TestShell) ConsoleEcho added in v1.0.1

func (s *TestShell) ConsoleEcho(line string)

ConsoleEcho implements Shell on TestShell

func (*TestShell) Dir added in v1.0.1

func (s *TestShell) Dir() string

Dir implements Shell on TestShell

func (*TestShell) Exists

func (s *TestShell) Exists(path string) bool

Exists returns true if the path definitely exists. It swallows any errors and returns false, in the case that e.g. permissions prevent the check from working correctly.

func (*TestShell) ExitCode

func (s *TestShell) ExitCode(name string, args ...interface{}) (int, error)

ExitCode (...) is a shortcut for shell.Cmd(...).ExitCode()

func (*TestShell) JSON

func (s *TestShell) JSON(v interface{}, name string, args ...interface{}) error

JSON (x, ...) is a shortcut for shell.Cmd(...).JSON(x)

func (*TestShell) Lines

func (s *TestShell) Lines(name string, args ...interface{}) ([]string, error)

Lines (...) is a shortcut for shell.Cmd(...).Lines()

func (*TestShell) List

func (s *TestShell) List() ([]os.FileInfo, error)

List returns all files (including dotfiles) inside Dir.

func (*TestShell) LongRunning added in v1.0.1

func (s *TestShell) LongRunning(is bool)

LongRunning implements Shell on TestShell

func (*TestShell) Run

func (s *TestShell) Run(name string, args ...interface{}) error

Run (...) is a shortcut for shell.Cmd(...).Succeed()

func (*TestShell) Stat

func (s *TestShell) Stat(path string) (os.FileInfo, error)

Stat calls os.Stat on the path provided, relative to the current shell's working directory.

func (*TestShell) Stderr

func (s *TestShell) Stderr(name string, args ...interface{}) (string, error)

Stderr (...) is a shortcut for shell.Cmd(...).Stderr()

func (*TestShell) Stdout

func (s *TestShell) Stdout(name string, args ...interface{}) (string, error)

Stdout (...) is a shortcut for shell.Cmd(...).Stdout()

type TestShellController added in v1.0.1

type TestShellController struct {
	*spies.Spy
}

A TestShellController manages the spy-ness of a TestShell.

func (*TestShellController) CmdFor added in v1.0.1

func (ctl *TestShellController) CmdFor(parts ...string) (*TestCommand, *TestCommandController)

CmdFor sets up a TestCommand to be returned to calls to Cmd with a particular prefix of arguments.

func (*TestShellController) CmdsLike added in v1.0.1

func (ctl *TestShellController) CmdsLike(parts ...string) []spies.Call

CmdsLike returns calls to Cmd with a prefix of arguments.

Jump to

Keyboard shortcuts

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