exec

package
v0.3.3 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2024 License: BSD-3-Clause Imports: 11 Imported by: 3

Documentation

Overview

Package exec provides an easy way to execute commands, improving the ease-of-use and error handling of the standard library os/exec package. For example:

err := exec.Run("git", "commit", "-am")
// or
err := exec.RunSh("git commit -am")
// or
err := exec.Verbose().Run("git", "commit", "-am")

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CloseReader added in v0.1.4

func CloseReader(r io.Reader)

CloseReader closes given Reader, if it has a Close() method

func CloseWriter added in v0.1.4

func CloseWriter(w io.Writer)

CloseWriter closes given Writer, if it has a Close() method

func CmdRan

func CmdRan(err error) bool

CmdRan examines the error to determine if it was generated as a result of a command running via os/exec.Command. If the error is nil, or the command ran (even if it exited with a non-zero exit code), CmdRan reports true. If the error is an unrecognized type, or it is an error from exec.Command that says the command failed to run (usually due to the command not existing or not being executable), it reports false.

func ExitStatus

func ExitStatus(err error) int

ExitStatus returns the exit status of the error if it is an exec.ExitError or if it implements ExitStatus() int. 0 if it is nil or 1 if it is a different error.

func IsPipe added in v0.1.4

func IsPipe(rw any) bool

IsPipe returns true if the given object is an os.File corresponding to a Pipe, which is also not the same as the current os.Stdout, in case that is a Pipe.

func LookPath

func LookPath(file string) (string, error)

LookPath searches for an executable named file in the directories named by the PATH environment variable. If file contains a slash, it is tried directly and the PATH is not consulted. Otherwise, on success, the result is an absolute path.

In older versions of Go, LookPath could return a path relative to the current directory. As of Go 1.19, LookPath will instead return that path along with an error satisfying errors.Is(err, ErrDot). See the package documentation for more details.

func MkdirAll

func MkdirAll(path string, perm os.FileMode) error

MkdirAll calls Config.MkdirAll on Major

func Output

func Output(cmd string, args ...string) (string, error)

Output calls Config.Output on Major

func PrintCmd

func PrintCmd(cmd string, err error)

PrintCmd calls Config.PrintCmd on Major

func RemoveAll

func RemoveAll(path string) error

RemoveAll calls Config.RemoveAll on Major

func Run

func Run(cmd string, args ...string) error

Run calls Config.Run on Major

func SetMajor

func SetMajor(c *Config)

SetMajor sets the config object that Major returns. It should be used sparingly, and only in cases where there is a clear property that should be set for all commands. If the given config object is nil, Major will go back to returning its default value.

func SetMinor

func SetMinor(c *Config)

SetMinor sets the config object that Minor returns. It should be used sparingly, and only in cases where there is a clear property that should be set for all commands. If the given config object is nil, Minor will go back to returning its default value.

func SetSilent

func SetSilent(c *Config)

SetSilent sets the config object that Silent returns. It should be used sparingly, and only in cases where there is a clear property that should be set for all commands. If the given config object is nil, Silent will go back to returning its default value.

func SetVerbose

func SetVerbose(c *Config)

SetVerbose sets the config object that Verbose returns. It should be used sparingly, and only in cases where there is a clear property that should be set for all commands. If the given config object is nil, Verbose will go back to returning its default value.

func Start added in v0.1.4

func Start(cmd string, args ...string) (*exec.Cmd, error)

Start calls Config.Start on Major

Types

type Cmd added in v0.1.4

type Cmd = exec.Cmd

Cmd is a type alias for exec.Cmd.

type CmdIO added in v0.1.4

type CmdIO struct {
	StdIOState

	// Cmd is the [exec.Cmd]
	Cmd *exec.Cmd
}

CmdIO maintains an exec.Cmd pointer and IO state saved for the command

func NewCmdIO added in v0.1.4

func NewCmdIO(c *Config) *CmdIO

NewCmdIO returns a new CmdIO initialized with StdIO settings from given Config

func (*CmdIO) String added in v0.1.4

func (c *CmdIO) String() string

type Config

type Config struct {

	// Buffer is whether to buffer the output of Stdout and Stderr,
	// which is necessary for the correct printing of commands and output
	// when there is an error with a command, and for correct coloring
	// on Windows. Therefore, it should be kept at the default value of
	// true in most cases, except for when a command will run for a log
	// time and print output throughout (eg: a log command).
	Buffer bool

	// PrintOnly is whether to only print commands that would be run and
	// not actually run them. It can be used, for example, for safely testing
	// an app.
	PrintOnly bool

	// The directory to execute commands in. If it is unset,
	// commands are run in the current directory.
	Dir string

	// Env contains any additional environment variables specified.
	// The current environment variables will also be passed to the
	// command, but they will be overridden by any variables here
	// if there are conflicts.
	Env map[string]string `set:"-"`

	// Echo is the writer for echoing the command string to.
	// It can be set to nil to disable echoing.
	Echo io.Writer

	// Standard Input / Output management
	StdIO StdIO
}

Config contains the configuration information that controls the behavior of exec. It is passed to most high-level functions, and a default version of it can be easily constructed using [DefaultConfig].

func Major

func Major() *Config

Major returns the default Config object for a major command, based on logx.UserLevel. It should be used for commands that are central to an app's logic and are more important for the user to know about and be able to see the output of. It results in commands and output being printed with a logx.UserLevel of slog.LevelInfo or below, whereas Minor results in that when it is slog.LevelDebug or below. Most commands in a typical use case should be Major, which is why the global helper functions operate on it. The object returned by Major is guaranteed to be unique, so it can be modified directly.

func Minor

func Minor() *Config

Minor returns the default Config object for a minor command, based on logx.UserLevel. It should be used for commands that support an app behind the scenes and are less important for the user to know about and be able to see the output of. It results in commands and output being printed with a logx.UserLevel of slog.LevelDebug or below, whereas Major results in that when it is slog.LevelInfo or below. The object returned by Minor is guaranteed to be unique, so it can be modified directly.

func Silent

func Silent() *Config

Silent returns the default Config object for a silent command, based on logx.UserLevel. It should be used for commands that whose output/input is private and needs to be always hidden from the user; for example, for a command that involves passwords. It results in commands and output never being printed. The object returned by Silent is guaranteed to be unique, so it can be modified directly.

func Verbose

func Verbose() *Config

Verbose returns the default Config object for a verbose command, based on logx.UserLevel. It should be used for commands whose output are central to an application; for example, for a logger or app runner. It results in commands and output being printed with a logx.UserLevel of slog.LevelWarn or below, whereas Major and Minor result in that when it is slog.LevelInfo and [slog.levelDebug] or below, respectively. The object returned by Verbose is guaranteed to be unique, so it can be modified directly.

func (*Config) GetWriter

func (c *Config) GetWriter(w io.Writer, err error) io.Writer

GetWriter returns the appropriate writer to use based on the given writer and error. If the given error is non-nil, the returned writer is guaranteed to be non-nil, with [Config.Stderr] used as a backup. Otherwise, the returned writer will only be non-nil if the passed one is.

func (*Config) MkdirAll

func (c *Config) MkdirAll(path string, perm os.FileMode) error

MkdirAll is a helper function that calls os.MkdirAll and Config.PrintCmd.

func (*Config) Output

func (c *Config) Output(cmd string, args ...string) (string, error)

Output runs the command and returns the text from stdout.

func (*Config) OutputIO added in v0.1.4

func (c *Config) OutputIO(cio *CmdIO, cmd string, args ...string) (string, error)

OutputIO runs the command and returns the text from stdout.

func (*Config) PrintCmd

func (c *Config) PrintCmd(cmd string, err error)

PrintCmd uses [GetWriter] to print the given command to [Config.Echo] or [Config.Stderr], based on the given error and the config settings. A newline is automatically inserted.

func (*Config) RemoveAll

func (c *Config) RemoveAll(path string) error

RemoveAll is a helper function that calls os.RemoveAll and Config.PrintCmd.

func (*Config) Run

func (c *Config) Run(cmd string, args ...string) error

Run runs the given command using the given configuration information and arguments, waiting for it to complete before returning.

func (*Config) RunIO added in v0.1.4

func (c *Config) RunIO(cio *CmdIO, cmd string, args ...string) error

RunIO runs the given command using the given configuration information and arguments, waiting for it to complete before returning. This IO version of Run uses specified stdio and sets the command in it as well, for easier management of dynamically updated IO routing.

func (*Config) SetBuffer

func (t *Config) SetBuffer(v bool) *Config

SetBuffer sets the [Config.Buffer]: Buffer is whether to buffer the output of Stdout and Stderr, which is necessary for the correct printing of commands and output when there is an error with a command, and for correct coloring on Windows. Therefore, it should be kept at the default value of true in most cases, except for when a command will run for a log time and print output throughout (eg: a log command).

func (*Config) SetDir

func (t *Config) SetDir(v string) *Config

SetDir sets the [Config.Dir]: The directory to execute commands in. If it is unset, commands are run in the current directory.

func (*Config) SetEcho added in v0.1.4

func (t *Config) SetEcho(v io.Writer) *Config

SetEcho sets the [Config.Echo]: Echo is the writer for echoing the command string to. It can be set to nil to disable echoing.

func (*Config) SetEnv

func (c *Config) SetEnv(key, val string) *Config

SetEnv sets the given environment variable.

func (*Config) SetPrintOnly

func (t *Config) SetPrintOnly(v bool) *Config

SetPrintOnly sets the [Config.PrintOnly]: PrintOnly is whether to only print commands that would be run and not actually run them. It can be used, for example, for safely testing an app.

func (*Config) SetStdIO added in v0.1.4

func (t *Config) SetStdIO(v StdIO) *Config

SetStdIO sets the [Config.StdIO]: Standard Input / Output management

func (*Config) SetStderr

func (c *Config) SetStderr(w io.Writer) *Config

SetStderr sets the standard error

func (*Config) SetStdin

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

SetStdin sets the standard input

func (*Config) SetStdout

func (c *Config) SetStdout(w io.Writer) *Config

SetStdout sets the standard output

func (*Config) Start added in v0.1.4

func (c *Config) Start(cmd string, args ...string) (*exec.Cmd, error)

Start starts the given command using the given configuration information and arguments, just starting the command but not waiting for it to finish. Returns the exec.Cmd command on which you can Wait for the command to finish (in a separate goroutine). See [StartIO] for a version that manages dynamic IO routing for you.

func (*Config) StartIO added in v0.1.4

func (c *Config) StartIO(cio *CmdIO, cmd string, args ...string) error

StartIO starts the given command using the given configuration information and arguments, just starting the command but not waiting for it to finish. This IO version of Start uses specified stdio and sets the command in it as well, which should be used to Wait for the command to finish (in a separate goroutine). For dynamic IO routing uses, call [CmdIO.StackStart] prior to setting the IO values using Push commands, and then call [PopToStart] after Wait finishes, to close any open IO and reset.

type ReadWrapper added in v0.1.4

type ReadWrapper struct {
	io.Reader
}

ReadWrapper is an io.Reader that wraps another io.Reader

type StdIO added in v0.1.4

type StdIO struct {
	// Out is the writer to write the standard output of called commands to.
	// It can be set to nil to disable the writing of the standard output.
	Out io.Writer

	// Err is the writer to write the standard error of called commands to.
	// It can be set to nil to disable the writing of the standard error.
	Err io.Writer

	// In is the reader to use as the standard input.
	In io.Reader
}

StdIO contains one set of standard input / output Reader / Writers.

func (*StdIO) ErrPrint added in v0.2.0

func (st *StdIO) ErrPrint(v ...any)

ErrPrint prints to the [StdIO.Err]

func (*StdIO) ErrPrintf added in v0.2.0

func (st *StdIO) ErrPrintf(f string, v ...any)

ErrPrintf prints to the [StdIO.Err]

func (*StdIO) ErrPrintln added in v0.2.0

func (st *StdIO) ErrPrintln(v ...any)

ErrPrintln prints to the [StdIO.Err]

func (*StdIO) GetWrapped added in v0.1.4

func (st *StdIO) GetWrapped() *StdIO

GetWrapped returns the current wrapped values as a StdIO. The wrappers must have been created using NewWrappers initially.

func (*StdIO) NewWrappers added in v0.1.4

func (st *StdIO) NewWrappers(o *StdIO)

NewWrappers initializes this StdIO with wrappers around given StdIO

func (*StdIO) OutIsPipe added in v0.1.4

func (st *StdIO) OutIsPipe() bool

OutIsPipe returns true if current Out is a Pipe

func (*StdIO) Print added in v0.1.4

func (st *StdIO) Print(v ...any)

Print prints to the [StdIO.Out]

func (*StdIO) Printf added in v0.1.4

func (st *StdIO) Printf(f string, v ...any)

Printf prints to the [StdIO.Out]

func (*StdIO) Println added in v0.1.4

func (st *StdIO) Println(v ...any)

Println prints to the [StdIO.Out]

func (*StdIO) Set added in v0.1.4

func (st *StdIO) Set(o *StdIO) *StdIO

Set sets our values from other StdIO, returning the current values at time of call, to restore later.

func (*StdIO) SetAll added in v0.1.4

func (st *StdIO) SetAll(out, err io.Writer, in io.Reader)

SetAll sets all our IO from given args

func (*StdIO) SetFromOS added in v0.1.4

func (st *StdIO) SetFromOS()

SetFromOS sets all our IO to current os.Std*

func (*StdIO) SetToOS added in v0.1.4

func (st *StdIO) SetToOS() *StdIO

SetToOS sets the current IO to os.Std*, returning a StdIO with the current IO settings prior to this call, which can be used to restore. Note: os.Std* are *os.File types, and this function will panic if the current IO are not actually *os.Files. The results of a prior SetToOS call will do the right thing for saving and restoring the os state.

func (*StdIO) SetWrappedErr added in v0.2.0

func (st *StdIO) SetWrappedErr(w io.Writer)

SetWrappedErr sets the wrapped Err to given writer. The wrappers must have been created using NewWrappers initially.

func (*StdIO) SetWrappedIn added in v0.2.0

func (st *StdIO) SetWrappedIn(r io.Reader)

SetWrappedIn sets the wrapped In to given reader. The wrappers must have been created using NewWrappers initially.

func (*StdIO) SetWrappedOut added in v0.2.0

func (st *StdIO) SetWrappedOut(w io.Writer)

SetWrappedOut sets the wrapped Out to given writer. The wrappers must have been created using NewWrappers initially.

func (*StdIO) SetWrappers added in v0.1.4

func (st *StdIO) SetWrappers(o *StdIO) *StdIO

SetWrappers sets the wrappers to current values from given StdIO, returning a copy of the wrapped values previously in place at start of call, which can be used in restoring state later. The wrappers must have been created using NewWrappers initially.

type StdIOState added in v0.1.4

type StdIOState struct {
	StdIO

	// OutStack is stack of out
	OutStack stack.Stack[io.Writer]

	// ErrStack is stack of err
	ErrStack stack.Stack[io.Writer]

	// InStack is stack of in
	InStack stack.Stack[io.Reader]

	// PipeIn is a stack of the os.File to use for reading from the Out,
	// when Out is a Pipe, created by [PushOutPipe].
	// Use [OutIsPipe] function to determine if the current output is a Pipe
	// in order to determine whether to use the current [PipeIn.Peek()].
	// These will be automatically closed during [PopToStart] whenever the
	// corresponding Out is a Pipe.
	PipeIn stack.Stack[*os.File]

	// Starting depths of the respective stacks, for unwinding the stack
	// to a defined starting point.
	OutStart, ErrStart, InStart int
}

StdIOState maintains a stack of StdIO settings for easier management of dynamic IO routing. Call [StackStart] prior to setting the IO values using Push commands, and then call [PopToStart] when done to close any open IO and reset.

func (*StdIOState) ErrIsInOut added in v0.1.4

func (st *StdIOState) ErrIsInOut(er io.Writer) bool

ErrIsInOut returns true if the given Err writer is also present within the active (> [OutStart]) stack of Outs. If this is true, then Err should not be closed, as it will be closed when the Out is closed.

func (*StdIOState) PopErr added in v0.1.4

func (st *StdIOState) PopErr() io.Writer

PopErr restores previous io.Writer as [Err] from the stack, saved during [PushErr], returning the current Err at time of call. This does NOT close the current one, in case you need to use it before closing, so that is your responsibility (see [PopToStart] that does this for you). Note that Err is often the same as Out, in which case only Out should be closed.

func (*StdIOState) PopIn added in v0.1.4

func (st *StdIOState) PopIn() io.Reader

PopIn restores previous io.Reader as [In] from the stack, saved during [PushIn], returning the current In at time of call. This does NOT close the current one, in case you need to use it before closing, so that is your responsibility (see [PopToStart] that does this for you).

func (*StdIOState) PopOut added in v0.1.4

func (st *StdIOState) PopOut() io.Writer

PopOut restores previous io.Writer as [Out] from the stack, saved during [PushOut], returning the current Out at time of call. Pops and closes corresponding PipeIn if current Out is a Pipe. This does NOT close the current one, in case you need to use it before closing, so that is your responsibility (see [PopToStart] that does this for you).

func (*StdIOState) PopToStart added in v0.1.4

func (st *StdIOState) PopToStart()

PopToStart unwinds the IO stacks to the depths recorded at [StackStart], automatically closing the ones that are popped. It automatically checks if any of the Err items are the same as Out and does not redundantly close those.

func (*StdIOState) PushErr added in v0.1.4

func (st *StdIOState) PushErr(err io.Writer)

PushErr pushes a new io.Writer as the current [Err], saving the current one on a stack, which can be restored using [PopErr].

func (*StdIOState) PushIn added in v0.1.4

func (st *StdIOState) PushIn(in io.Reader)

PushIn pushes a new io.Reader as the current [In], saving the current one on a stack, which can be restored using [PopIn].

func (*StdIOState) PushOut added in v0.1.4

func (st *StdIOState) PushOut(out io.Writer)

PushOut pushes a new io.Writer as the current [Out], saving the current one on a stack, which can be restored using [PopOut].

func (*StdIOState) PushOutPipe added in v0.1.4

func (st *StdIOState) PushOutPipe()

PushOutPipe calls os.Pipe() and pushes the writer side as the new [Out], and pushes the Reader side to [PipeIn] which should then be used as the [In] for any other relevant process. Call [OutIsPipe] to determine if the current Out is a Pipe, to know whether to use the PipeIn.Peek() value.

func (*StdIOState) StackStart added in v0.1.4

func (st *StdIOState) StackStart()

StackStart records the starting depths of the IO stacks

type WriteWrapper added in v0.1.4

type WriteWrapper struct {
	io.Writer
}

WriteWrapper is an io.Writer that wraps another io.Writer

Jump to

Keyboard shortcuts

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