Documentation ¶
Overview ¶
Package shx provides shell-like operations for Go.
A Job represents one or more operations. A single-operation Job may represent running a command (Exec, System), or reading or writing a file (ReadFile, WriteFile), or a user defined operation (Func). A multiple-operation Job runs several single operation jobs in a sequence (Script) or pipeline (Pipe). Taken together, these primitive types allow the composition of more and more complex operations.
Users control how a Job runs using State. State controls the Job input and output, as well as its working directory and environment.
Users may produce a human-readable representation of a complex Job in a shell-like syntax using the Description. Because some operations have no shell equivalent, the result is only representative.
Examples are provided for all primitive Job types: Exec, System, Func, Pipe, Script. Additional convenience Jobs make creating more complex operations a little easier. Advanced users may create their own Job types for more flexibility.
Example ¶
sc := Script( // Set environment in Script State. SetEnv("KEY", "ORIGINAL"), Script( // Overwrite environment in sub-Script. SetEnv("KEY", "SUBSCRIPT"), Exec("env"), ), // Original Script State environment was not modified by sub-Script. Exec("env"), // Overwrite environment using command output. SetEnvFromJob("KEY", System("basename $( pwd )")), Exec("env"), ) s := New() s.Env = nil // Clear state environment for example. err := sc.Run(context.Background(), s) if err != nil { panic(err) }
Output: KEY=SUBSCRIPT KEY=ORIGINAL KEY=shx
Index ¶
- Variables
- func NewReaderContext(ctx context.Context, r io.Reader) io.Reader
- type Description
- type ExecJob
- type FuncJob
- type Job
- func Chdir(dir string) Job
- func IfFileMissing(file string, job Job) Job
- func IfVarEmpty(key string, job Job) Job
- func Println(message string) Job
- func Read(r io.Reader) Job
- func ReadFile(path string) Job
- func SetEnv(name string, value string) Job
- func SetEnvFromJob(name string, job Job) Job
- func Write(w io.Writer) Job
- func WriteFile(path string, perm os.FileMode) Job
- type PipeJob
- type ScriptJob
- type State
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrScriptError = errors.New("script execution error")
ErrScriptError is a base Script error.
Functions ¶
Types ¶
type Description ¶
type Description struct { // Depth is used to control line prefix indentation in complex Jobs. Depth int // contains filtered or unexported fields }
Description is used to produce a representation of a Job. Custom Job types should use the Description interface to represent their behavior in a helpful, human-readable form. After collecting a description, serialize using the String() method.
func (*Description) Append ¶
func (d *Description) Append(cmd string)
Append adds a new command to the output buffer. Typically, the command is formatted as a new line at the end of the current buffer. If StartSequence was called before calling Append, then the command is formatted as a continuation of the current line.
func (*Description) StartSequence ¶
func (d *Description) StartSequence(start, sep string) (endlist func(end string))
StartSequence begins formatting a multi-part expression on a single line, such as a list, pipeline, or similar expression. StartSequence begins with "start" and subsequent calls to Append add commands to the end of the current line, separating sequential commands with "sep". StartSequence returns a function that ends the line and restores the default behavior of Append.
func (*Description) String ¶
func (d *Description) String() string
String serializes a description produced by running Job.Describe(). Calling String resets the Description buffer.
type ExecJob ¶
type ExecJob struct {
// contains filtered or unexported fields
}
ExecJob implements the Job interface for basic process execution.
func System ¶
System is an Exec job that interprets the given command using "/bin/sh".
Example ¶
sys := System("echo a b") s := &State{ Stdout: os.Stdout, } err := sys.Run(context.Background(), s) if err != nil { panic(err) }
Output: a b
func (*ExecJob) Describe ¶
func (f *ExecJob) Describe(d *Description)
Describe generates a description for this command.
type FuncJob ¶
type FuncJob struct { Job func(ctx context.Context, s *State) error Desc func(d *Description) }
FuncJob is a generic Job type that allows creating new operations without creating a totally new type. When created directly, both Job and Desc fields must be defined.
func Func ¶
Func creates a new FuncJob that runs the given function. Job functions should honor the context to support cancelation. The given name is used to describe this function.
func (*FuncJob) Describe ¶
func (f *FuncJob) Describe(d *Description)
Describe generates a description for this custom function.
func (*FuncJob) Run ¶
Run executes the job function.
Example ¶
f := Func("example", func(ctx context.Context, s *State) error { b, err := ioutil.ReadAll(s.Stdin) if err != nil { return err } _, err = s.Stdout.Write([]byte(base64.URLEncoding.EncodeToString(b))) return err }) s := &State{ Stdin: bytes.NewBuffer([]byte(`{"key":"value"}\n`)), Stdout: os.Stdout, } err := f.Run(context.Background(), s) if err != nil { panic(err) }
Output: eyJrZXkiOiJ2YWx1ZSJ9XG4=
type Job ¶
type Job interface { // Describe produces a readable representation of the Job operation. After // calling Describe, use Description.String() to report the result. Describe(d *Description) // Run executes the Job using the given State. A Job should terminate when // the given context is cancelled. Run(ctx context.Context, s *State) error }
Job is the interface for an operation. A Job controls how an operation is run and represented.
func Chdir ¶
Chdir creates Job that changes the State Dir to the given directory at runtime. This does not alter the process working directory. Chdir is helpful in Script() Jobs.
func IfFileMissing ¶
IfFileMissing creates a Job that runs the given job if the named file does not exist.
func IfVarEmpty ¶
IfVarEmpty creates a Job that runs the given job if the named variable is empty.
func Println ¶
Println writes the given message to the State Stdout and expands variable references from the running State environment. Println supports the same variable syntax as os.Expand, e.g. $NAME or ${NAME}.
func Read ¶
Read creates a Job that reads from the given reader and writes it to Job's stdout. Read creates a context-aware reader from the given io.Reader.
func ReadFile ¶
ReadFile creates a Job that reads from the named file and writes it to the Job's stdout.
func SetEnv ¶
SetEnv creates a Job to assign the given name=value in the running State Env. SetEnv is helpful in Script() Jobs.
func SetEnvFromJob ¶
SetEnvFromJob creates a new Job that sets the given name in Env to the result written to stdout by running the given Job. Errors from the given Job are returned.
type PipeJob ¶
type PipeJob struct {
Jobs []Job
}
PipeJob implements the Job interface for running multiple Jobs in a pipeline.
func Pipe ¶
Pipe creates a Job that executes the given Jobs as a "shell pipeline", passing the output of the first to the input of the next, and so on. If any Job returns an error, the first error is returned.
func (*PipeJob) Describe ¶
func (c *PipeJob) Describe(d *Description)
Describe generates a description for all jobs in the pipeline.
Example ¶
p := Pipe( Exec("ls"), Exec("tail", "-1"), Exec("wc", "-l"), ) d := &Description{} p.Describe(d) fmt.Println(d.String())
Output: 1: ls | tail -1 | wc -l
func (*PipeJob) Run ¶
Run executes every Job in the pipeline. The stdout from the first command is passed to the stdin to the next command. The stderr for all commands is inherited from the given State. If any Job returns an error, the first error is returned for the entire PipeJob.
Example ¶
p := Pipe( Exec("ls"), Exec("tail", "-1"), Exec("wc", "-l"), ) s := New() err := p.Run(context.Background(), s) if err != nil { panic(err) }
Output: 1
type ScriptJob ¶
type ScriptJob struct {
Jobs []Job
}
ScriptJob implements the Job interface for running an ordered sequence of Jobs.
func Script ¶
Script creates a Job that executes the given Job parameters in sequence. If any Job returns an error, execution stops.
func (*ScriptJob) Describe ¶
func (c *ScriptJob) Describe(d *Description)
Describe generates a description for all jobs in the script.
Example ¶
sc := Script( SetEnv("FOO", "BAR"), Exec("env"), ) d := &Description{} sc.Describe(d) fmt.Println("\n" + d.String())
Output: 1: ( 2: export FOO="BAR" 3: env 4: )
func (*ScriptJob) Run ¶
Run sequentially executes every Job in the script. Any Job error stops execution and generates an error describing the command that failed.
Example ¶
sc := Script( SetEnv("FOO", "BAR"), Exec("env"), ) s := &State{ Stdout: os.Stdout, } err := sc.Run(context.Background(), s) if err != nil { panic(err) }
Output: FOO=BAR
type State ¶
State is a Job configuration. Callers provide the first initial State, and as a Job executes it creates new State instances derived from the original, e.g. for Pipes and subcommands.
func New ¶
func New() *State
New creates a State instance based on the current process state, using os.Stdin, os.Stdout, and os.Stderr, as well as the current working directory and environment.
func (*State) GetEnv ¶
GetEnv reads the named variable from the State environment. If name is not found, an empty value is returned. An undefined variable and a variable set to the empty value are indistinguishable.
func (*State) Path ¶
Path produces a path relative to the State's current directory. If arguments represent an absolute path, then that is used. If multiple arguments are provided, they're joined using filepath.Join.