gosh

package
v0.1.8 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2021 License: BSD-3-Clause Imports: 24 Imported by: 20

Documentation

Overview

Package gosh provides facilities for running and managing processes: start them, wait for them to exit, capture their output streams, pipe messages between them, terminate them (e.g. on SIGINT), and so on.

Gosh is meant to be used in situations where one might otherwise be tempted to write a shell script. (Oh my gosh, no more shell scripts!)

For usage examples, see shell_test.go and internal/gosh_example/main.go.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildGoPkg

func BuildGoPkg(sh *Shell, binDir, pkg string, flags ...string) string

BuildGoPkg compiles a Go package using the "go build" command and writes the resulting binary to the given binDir, or to the -o flag location if specified. If -o is relative, it is interpreted as relative to binDir. If the binary already exists at the target location, it is not rebuilt. Returns the absolute path to the binary.

func InitChildMain

func InitChildMain()

InitChildMain must be called early on in main() of child processes. It spawns goroutines to kill the current process when certain conditions are met, per Cmd.IgnoreParentExit and Cmd.ExitAfter.

func InitMain

func InitMain()

InitMain must be called early on in main(), before flags are parsed. In the parent process, it returns immediately with no effect. In a child process for a Shell.FuncCmd command, it runs the specified function, then exits.

func SendVars

func SendVars(vars map[string]string)

SendVars sends the given vars to the parent process. Writes a string of the form "<goshVars{ ... JSON-encoded vars ... }goshVars>\n" to stderr.

Types

type Cmd

type Cmd struct {
	// Err is the most recent error from this Cmd (may be nil).
	Err error
	// Path is the path of the command to run.
	Path string
	// Vars is the map of env vars for this Cmd.
	Vars map[string]string
	// Args is the list of args for this Cmd, starting with the resolved path.
	// Note, we set Args[0] to the resolved path (rather than the user-specified
	// name) so that a command started by Shell can reliably determine the path to
	// its executable.
	Args []string
	// IgnoreParentExit, if true, makes it so the child process does not exit when
	// its parent exits. Only takes effect if the child process was spawned via
	// Shell.FuncCmd or explicitly calls InitChildMain.
	IgnoreParentExit bool
	// ExitAfter, if non-zero, specifies that the child process should exit after
	// the given duration has elapsed. Only takes effect if the child process was
	// spawned via Shell.FuncCmd or explicitly calls InitChildMain.
	ExitAfter time.Duration
	// PropagateOutput is inherited from Shell.PropagateChildOutput.
	PropagateOutput bool
	// OutputDir is inherited from Shell.ChildOutputDir.
	OutputDir string
	// ExitErrorIsOk specifies whether an *exec.ExitError should be reported via
	// Shell.HandleError.
	ExitErrorIsOk bool
	// IgnoreClosedPipeError, if true, causes errors from read/write on a closed
	// pipe to be indistinguishable from success. These errors often occur in
	// command pipelines, e.g. "yes | head -1", where "yes" will receive a closed
	// pipe error when it tries to write on stdout, after "head" has exited. If a
	// closed pipe error occurs, Cmd.Err will be nil, and no err is reported to
	// Shell.HandleError.
	IgnoreClosedPipeError bool
	// ExtraFiles is used to populate ExtraFiles in the underlying exec.Cmd
	// object. Does not get cloned.
	ExtraFiles []*os.File
	// contains filtered or unexported fields
}

Cmd represents a command. Not thread-safe. Public fields should not be modified after calling Start.

func (*Cmd) AddStderrWriter

func (c *Cmd) AddStderrWriter(w io.Writer)

AddStderrWriter configures this Cmd to tee stderr to the given Writer. Must be called before Start. If the same Writer is passed to both AddStdoutWriter and AddStderrWriter, Cmd will ensure that Write is never called concurrently.

func (*Cmd) AddStdoutWriter

func (c *Cmd) AddStdoutWriter(w io.Writer)

AddStdoutWriter configures this Cmd to tee stdout to the given Writer. Must be called before Start. If the same Writer is passed to both AddStdoutWriter and AddStderrWriter, Cmd will ensure that Write is never called concurrently.

func (*Cmd) AwaitVars

func (c *Cmd) AwaitVars(keys ...string) map[string]string

AwaitVars waits for the child process to send values for the given vars (e.g. using SendVars). Must not be called before Start or after Wait.

func (*Cmd) Clone

func (c *Cmd) Clone() *Cmd

Clone returns a new Cmd with a copy of this Cmd's configuration.

func (*Cmd) CombinedOutput

func (c *Cmd) CombinedOutput() string

CombinedOutput calls Start followed by Wait, then returns the command's combined stdout and stderr.

func (*Cmd) Pid

func (c *Cmd) Pid() int

Pid returns the command's PID, or -1 if the command has not been started.

func (*Cmd) Run

func (c *Cmd) Run()

Run calls Start followed by Wait.

func (*Cmd) SetStdinReader

func (c *Cmd) SetStdinReader(r io.Reader)

SetStdinReader configures this Cmd to read stdin from the given Reader. Must be called before Start. Only one call may be made to StdinPipe or SetStdinReader; subsequent calls will fail.

func (*Cmd) Shell

func (c *Cmd) Shell() *Shell

Shell returns the shell that this Cmd was created from.

func (*Cmd) Signal

func (c *Cmd) Signal(sig os.Signal)

Signal sends a signal to the underlying process.

func (*Cmd) Start

func (c *Cmd) Start()

Start starts the command.

func (*Cmd) StderrPipe

func (c *Cmd) StderrPipe() io.ReadCloser

StderrPipe returns a ReadCloser backed by an unlimited-size pipe for the command's stderr. The pipe will be closed when the process exits, but may also be closed earlier by the caller, e.g. if all expected output has been received. Must be called before Start. May be called more than once; each call creates a new pipe.

func (*Cmd) StdinPipe

func (c *Cmd) StdinPipe() io.WriteCloser

StdinPipe returns a WriteCloser backed by an unlimited-size pipe for the command's stdin. The pipe will be closed when the process exits, but may also be closed earlier by the caller, e.g. if the command does not exit until its stdin is closed. Must be called before Start. Only one call may be made to StdinPipe or SetStdinReader; subsequent calls will fail.

func (*Cmd) Stdout

func (c *Cmd) Stdout() string

Stdout calls Start followed by Wait, then returns the command's stdout.

func (*Cmd) StdoutPipe

func (c *Cmd) StdoutPipe() io.ReadCloser

StdoutPipe returns a ReadCloser backed by an unlimited-size pipe for the command's stdout. The pipe will be closed when the process exits, but may also be closed earlier by the caller, e.g. if all expected output has been received. Must be called before Start. May be called more than once; each call creates a new pipe.

func (*Cmd) StdoutStderr

func (c *Cmd) StdoutStderr() (string, string)

StdoutStderr calls Start followed by Wait, then returns the command's stdout and stderr.

func (*Cmd) Terminate

func (c *Cmd) Terminate(sig os.Signal)

Terminate sends a signal to the underlying process, then waits for it to exit. Terminate is different from Signal followed by Wait: Terminate succeeds as long as the process exits, whereas Wait fails if the exit code isn't 0.

func (*Cmd) Wait

func (c *Cmd) Wait()

Wait waits for the command to exit.

type Func

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

Func is a registered, callable function.

func RegisterFunc

func RegisterFunc(name string, fi interface{}) *Func

RegisterFunc registers the given function with the given name. 'fi' must be a function that accepts gob-encodable arguments and returns an error or nothing.

type Pipeline

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

Pipeline represents a pipeline of commands, where the stdout and/or stderr of one command is connected to the stdin of the next command.

The failure semantics of a pipeline are determined by the failure semantics of each command; by default the pipeline fails if any command fails, and read/write errors on closed pipes are ignored. This is different from bash, where the default is to only check the status of the last command, unless "set -o pipefail" is enabled to check the status of all commands, causing closed pipe errors to fail the pipeline. Use Cmd.ExitErrorIsOk and Cmd.IgnoreClosedPipeError to fine-tune the failure semantics.

The implementation of Pipeline only uses exported methods from Shell and Cmd.

func NewPipeline

func NewPipeline(c *Cmd, cmds ...*Cmd) *Pipeline

NewPipeline returns a new Pipeline starting with c. The stdout of each command is connected to the stdin of the next command, via calls to Pipeline.PipeStdout. To construct pipelines involving stderr, call Pipeline.PipeStderr or Pipeline.PipeCombinedOutput directly.

Each command must have been created from the same Shell. Errors are reported to c.Shell, via Shell.HandleError. Sets Cmd.IgnoreClosedPipeError to true for all commands.

func (*Pipeline) Clone

func (p *Pipeline) Clone() *Pipeline

Clone returns a new Pipeline where p's commands are cloned and connected with the same pipeline structure as in p.

func (*Pipeline) Cmds

func (p *Pipeline) Cmds() []*Cmd

Cmds returns the commands in the pipeline.

func (*Pipeline) CombinedOutput

func (p *Pipeline) CombinedOutput() string

CombinedOutput calls Start followed by Wait, then returns the last command's combined stdout and stderr.

func (*Pipeline) PipeCombinedOutput

func (p *Pipeline) PipeCombinedOutput(c *Cmd)

PipeCombinedOutput connects the combined stdout and stderr of the last command in p to the stdin of c, and appends c to the commands in p. Must be called before Start. Sets c.IgnoreClosedPipeError to true.

func (*Pipeline) PipeStderr

func (p *Pipeline) PipeStderr(c *Cmd)

PipeStderr connects the stderr of the last command in p to the stdin of c, and appends c to the commands in p. Must be called before Start. Sets c.IgnoreClosedPipeError to true.

func (*Pipeline) PipeStdout

func (p *Pipeline) PipeStdout(c *Cmd)

PipeStdout connects the stdout of the last command in p to the stdin of c, and appends c to the commands in p. Must be called before Start. Sets c.IgnoreClosedPipeError to true.

func (*Pipeline) Run

func (p *Pipeline) Run()

Run calls Start followed by Wait.

func (*Pipeline) Signal

func (p *Pipeline) Signal(sig os.Signal)

Signal sends a signal to all underlying processes in the pipeline.

func (*Pipeline) Start

func (p *Pipeline) Start()

Start starts all commands in the pipeline.

func (*Pipeline) Stdout

func (p *Pipeline) Stdout() string

Stdout calls Start followed by Wait, then returns the last command's stdout.

func (*Pipeline) StdoutStderr

func (p *Pipeline) StdoutStderr() (string, string)

StdoutStderr calls Start followed by Wait, then returns the last command's stdout and stderr.

func (*Pipeline) Terminate

func (p *Pipeline) Terminate(sig os.Signal)

Terminate sends a signal to all underlying processes in the pipeline, then waits for all processes to exit. Terminate is different from Signal followed by Wait: Terminate succeeds as long as all processes exit, whereas Wait fails if any process's exit code isn't 0.

func (*Pipeline) Wait

func (p *Pipeline) Wait()

Wait waits for all commands in the pipeline to exit.

type Shell

type Shell struct {
	// Err is the most recent error from this Shell or any of its child Cmds (may
	// be nil).
	Err error
	// PropagateChildOutput specifies whether to propagate child stdout and stderr
	// up to the parent's stdout and stderr.
	PropagateChildOutput bool
	// ChildOutputDir, if non-empty, makes it so child stdout and stderr are tee'd
	// to files in the specified directory.
	ChildOutputDir string
	// ContinueOnError specifies whether to invoke TB.FailNow on error, i.e.
	// whether to panic on error. Users that set ContinueOnError to true should
	// inspect sh.Err after each Shell method invocation.
	ContinueOnError bool
	// Vars is the map of env vars for this Shell.
	Vars map[string]string
	// Args is the list of args to append to subsequent command invocations.
	Args []string
	// Set the depth to use for runtime.Caller when generating error messages.
	ErrorDepth int
	// contains filtered or unexported fields
}

Shell represents a shell. Not thread-safe.

func NewShell

func NewShell(tb TB) *Shell

NewShell returns a new Shell. Tests and benchmarks should pass their testing.TB instance; non-tests should pass nil.

func (*Shell) AddCleanupHandler

func (sh *Shell) AddCleanupHandler(f func())

AddCleanupHandler registers the given function to be called during cleanup. Cleanup handlers are called in LIFO order, possibly in a separate goroutine spawned by gosh.

func (*Shell) Cleanup

func (sh *Shell) Cleanup()

Cleanup cleans up all resources (child processes, temporary files and directories) associated with this Shell. It is safe (and recommended) to call Cleanup after a Shell error. It is also safe to call Cleanup multiple times; calls after the first return immediately with no effect. Cleanup never calls HandleError.

func (*Shell) Cmd

func (sh *Shell) Cmd(name string, args ...string) *Cmd

Cmd returns a Cmd for an invocation of the named program. The given arguments are passed to the child as command-line arguments.

func (*Shell) FuncCmd

func (sh *Shell) FuncCmd(f *Func, args ...interface{}) *Cmd

FuncCmd returns a Cmd for an invocation of the given registered Func. The given arguments are gob-encoded in the parent process, then gob-decoded in the child and passed to the Func as parameters. To specify command-line arguments for the child invocation, append to the returned Cmd's Args.

func (*Shell) HandleError

func (sh *Shell) HandleError(err error)

HandleError sets sh.Err. If err is not nil and sh.ContinueOnError is false, it also calls TB.FailNow.

func (*Shell) HandleErrorWithSkip

func (sh *Shell) HandleErrorWithSkip(err error, skip int)

HandleErrorWithSkip is like HandleError, but allows clients to specify the skip value to pass to runtime.Caller.

func (*Shell) MakeTempDir

func (sh *Shell) MakeTempDir() string

MakeTempDir creates a new temporary directory in os.TempDir and returns the path of the new directory.

func (*Shell) MakeTempFile

func (sh *Shell) MakeTempFile() *os.File

MakeTempFile creates a new temporary file in os.TempDir, opens the file for reading and writing, and returns the resulting *os.File.

func (*Shell) Move

func (sh *Shell) Move(oldpath, newpath string)

Move moves a file from 'oldpath' to 'newpath'. It first attempts os.Rename; if that fails, it copies 'oldpath' to 'newpath', then deletes 'oldpath'. Requires that 'newpath' does not exist, and that the parent directory of 'newpath' does exist. Currently only supports moving an individual file; moving a directory is not yet supported.

func (*Shell) Ok

func (sh *Shell) Ok()

Ok panics iff this Shell is in a state where it's invalid to call other methods. This method is public to facilitate Shell wrapping.

func (*Shell) Popd

func (sh *Shell) Popd()

Popd behaves like Bash popd.

func (*Shell) Pushd

func (sh *Shell) Pushd(dir string)

Pushd behaves like Bash pushd.

func (*Shell) Wait

func (sh *Shell) Wait()

Wait waits for all commands started by this Shell to exit.

type TB

type TB interface {
	FailNow()
	Logf(format string, args ...interface{})
}

TB is a subset of the testing.TB interface, defined here to avoid depending on the testing package.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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