Documentation ¶
Overview ¶
Package script implements a small, customizable, platform-agnostic scripting language.
Scripts are run by an Engine configured with a set of available commands and conditions that guard those commands. Each script has an associated working directory and environment, along with a buffer containing the stdout and stderr output of a prior command, tracked in a State that commands can inspect and modify.
The default commands configured by NewEngine resemble a simplified Unix shell.
Script Language ¶
Each line of a script is parsed into a sequence of space-separated command words, with environment variable expansion within each word and # marking an end-of-line comment. Additional variables named ':' and '/' are expanded within script arguments (expanding to the value of os.PathListSeparator and os.PathSeparator respectively) but are not inherited in subprocess environments.
Adding single quotes around text keeps spaces in that text from being treated as word separators and also disables environment variable expansion. Inside a single-quoted block of text, a repeated single quote indicates a literal single quote, as in:
'Don''t communicate by sharing memory.'
A line beginning with # is a comment and conventionally explains what is being done or tested at the start of a new section of the script.
Commands are executed one at a time, and errors are checked for each command; if any command fails unexpectedly, no subsequent commands in the script are executed. The command prefix ! indicates that the command on the rest of the line (typically go or a matching predicate) must fail instead of succeeding. The command prefix ? indicates that the command may or may not succeed, but the script should continue regardless.
The command prefix [cond] indicates that the command on the rest of the line should only run when the condition is satisfied.
A condition can be negated: [!root] means to run the rest of the line only if the user is not root. Multiple conditions may be given for a single command, for example, '[linux] [amd64] skip'. The command will run if all conditions are satisfied.
Index ¶
- Variables
- func DefaultCmds() map[string]Cmd
- func DefaultConds() map[string]Cond
- type Cmd
- func Cat() Cmd
- func Cd() Cmd
- func Chmod() Cmd
- func Cmp() Cmd
- func Cmpenv() Cmd
- func Command(usage CmdUsage, run func(*State, ...string) (WaitFunc, error)) Cmd
- func Cp() Cmd
- func Echo() Cmd
- func Env() Cmd
- func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd
- func Exists() Cmd
- func Grep() Cmd
- func Help() Cmd
- func Mkdir() Cmd
- func Mv() Cmd
- func Program(name string, cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd
- func Replace() Cmd
- func Rm() Cmd
- func Sleep() Cmd
- func Stderr() Cmd
- func Stdout() Cmd
- func Stop() Cmd
- func Symlink() Cmd
- func Wait() Cmd
- type CmdUsage
- type CommandError
- type Cond
- func BoolCondition(summary string, v bool) Cond
- func CachedCondition(summary string, eval func(string) (bool, error)) Cond
- func Condition(summary string, eval func(*State) (bool, error)) Cond
- func OnceCondition(summary string, eval func() (bool, error)) Cond
- func PrefixCondition(summary string, eval func(*State, string) (bool, error)) Cond
- type CondUsage
- type Engine
- type State
- func (s *State) Chdir(path string) error
- func (s *State) CloseAndWait(log io.Writer) error
- func (s *State) Context() context.Context
- func (s *State) Environ() []string
- func (s *State) ExpandEnv(str string, inRegexp bool) string
- func (s *State) ExtractFiles(ar *txtar.Archive) error
- func (s *State) Getwd() string
- func (s *State) Logf(format string, args ...any)
- func (s *State) LookupEnv(key string) (string, bool)
- func (s *State) Path(path string) string
- func (s *State) Setenv(key, value string) error
- func (s *State) Stderr() string
- func (s *State) Stdout() string
- type UsageError
- type WaitFunc
Constants ¶
This section is empty.
Variables ¶
var ErrUnexpectedSuccess = errors.New("unexpected success")
ErrUnexpectedSuccess indicates that a script command that was expected to fail (as indicated by a "!" prefix) instead completed successfully.
var ErrUsage = errors.New("invalid usage")
ErrUsage may be returned by a Command to indicate that it was called with invalid arguments; its Usage method may be called to obtain details.
Functions ¶
func DefaultCmds ¶
DefaultCmds returns a set of broadly useful script commands.
Run the 'help' command within a script engine to view a list of the available commands.
func DefaultConds ¶
DefaultConds returns a set of broadly useful script conditions.
Run the 'help' command within a script engine to view a list of the available conditions.
Types ¶
type Cmd ¶
type Cmd interface { // Run begins running the command. // // If the command produces output or can be run in the background, run returns // a WaitFunc that will be called to obtain the result of the command and // update the engine's stdout and stderr buffers. // // Run itself and the returned WaitFunc may inspect and/or modify the State, // but the State's methods must not be called concurrently after Run has // returned. // // Run may retain and access the args slice until the WaitFunc has returned. Run(s *State, args ...string) (WaitFunc, error) // Usage returns the usage for the command, which the caller must not modify. Usage() *CmdUsage }
A Cmd is a command that is available to a script.
func Cat ¶
func Cat() Cmd
Cat writes the concatenated contents of the named file(s) to the script's stdout buffer.
func Cmp ¶
func Cmp() Cmd
Cmp compares the contents of two files, or the contents of either the "stdout" or "stderr" buffer and a file, returning a non-nil error if the contents differ.
func Cmpenv ¶
func Cmpenv() Cmd
Cmpenv is like Compare, but also performs environment substitutions on the contents of both arguments.
func Command ¶
Command returns a new Cmd with a Usage method that returns a copy of the given CmdUsage and a Run method calls the given function.
func Env ¶
func Env() Cmd
Env sets or logs the values of environment variables.
With no arguments, Env reports all variables in the environment. "key=value" arguments set variables, and arguments without "=" cause the corresponding value to be printed to the stdout buffer.
func Exec ¶
Exec runs an arbitrary executable as a subprocess.
When the Script's context is canceled, Exec sends the interrupt signal, then waits for up to the given delay for the subprocess to flush output before terminating it with os.Kill.
func Grep ¶
func Grep() Cmd
Grep checks that file content matches a regexp. Like stdout/stderr and unlike Unix grep, it accepts Go regexp syntax.
Grep does not modify the State's stdout or stderr buffers. (Its output goes to the script log, not stdout.)
func Program ¶
Program returns a new command that runs the named program, found from the host process's PATH (not looked up in the script's PATH).
func Replace ¶
func Replace() Cmd
Replace replaces all occurrences of a string in a file with another string.
func Rm ¶
func Rm() Cmd
Rm removes a file or directory.
If a directory, Rm also recursively removes that directory's contents.
func Sleep ¶
func Sleep() Cmd
Sleep sleeps for the given Go duration or until the script's context is cancelled, whichever happens first.
type CmdUsage ¶
type CmdUsage struct { Summary string // in the style of the Name section of a Unix 'man' page, omitting the name Args string // a brief synopsis of the command's arguments (only) Detail []string // zero or more sentences in the style of the Description section of a Unix 'man' page // If Async is true, the Cmd is meaningful to run in the background, and its // Run method must return either a non-nil WaitFunc or a non-nil error. Async bool // RegexpArgs reports which arguments, if any, should be treated as regular // expressions. It takes as input the raw, unexpanded arguments and returns // the list of argument indices that will be interpreted as regular // expressions. // // If RegexpArgs is nil, all arguments are assumed not to be regular // expressions. RegexpArgs func(rawArgs ...string) []int }
A CmdUsage describes the usage of a Cmd, independent of its name (which can change based on its registration).
type CommandError ¶
A CommandError describes an error resulting from attempting to execute a specific command.
func (*CommandError) Error ¶
func (e *CommandError) Error() string
func (*CommandError) Unwrap ¶
func (e *CommandError) Unwrap() error
type Cond ¶
type Cond interface { // Eval reports whether the condition applies to the given State. // // If the condition's usage reports that it is a prefix, // the condition must be used with a suffix. // Otherwise, the passed-in suffix argument is always the empty string. Eval(s *State, suffix string) (bool, error) // Usage returns the usage for the condition, which the caller must not modify. Usage() *CondUsage }
A Cond is a condition deciding whether a command should be run.
func BoolCondition ¶
BoolCondition returns a Cond with the given truth value and summary. The Cond rejects the use of condition suffixes.
func CachedCondition ¶
CachedCondition is like Condition but only calls eval the first time the condition is evaluated for a given suffix. Future calls with the same suffix reuse the earlier result.
The eval function is not passed a *State because the condition is cached across all execution states and must not vary by state.
func OnceCondition ¶
OnceCondition returns a Cond that calls eval the first time the condition is evaluated. Future calls reuse the same result.
The eval function is not passed a *State because the condition is cached across all execution states and must not vary by state.
type CondUsage ¶
type CondUsage struct { Summary string // a single-line summary of when the condition is true // If Prefix is true, the condition is a prefix and requires a // colon-separated suffix (like "[GOOS:linux]" for the "GOOS" condition). // The suffix may be the empty string (like "[prefix:]"). Prefix bool }
A CondUsage describes the usage of a Cond, independent of its name (which can change based on its registration).
type Engine ¶
type Engine struct { Cmds map[string]Cmd Conds map[string]Cond // If Quiet is true, Execute deletes log prints from the previous // section when starting a new section. Quiet bool }
An Engine stores the configuration for executing a set of scripts.
The same Engine may execute multiple scripts concurrently.
func NewEngine ¶
func NewEngine() *Engine
NewEngine returns an Engine configured with a basic set of commands and conditions.
func (*Engine) Execute ¶
Execute reads and executes script, writing the output to log.
Execute stops and returns an error at the first command that does not succeed. The returned error's text begins with "file:line: ".
If the script runs to completion or ends by a 'stop' command, Execute returns nil.
Execute does not stop background commands started by the script before returning. To stop those, use State.CloseAndWait or the Wait command.
func (*Engine) ListCmds ¶
ListCmds prints to w a list of the named commands, annotating each with its arguments and a short usage summary. If verbose is true, ListCmds prints full details for each command.
Each of the name arguments should be a command name. If no names are passed as arguments, ListCmds lists all the commands registered in e.
func (*Engine) ListConds ¶
ListConds prints to w a list of conditions, one per line, annotating each with a description and whether the condition is true in the state s (if s is non-nil).
Each of the tag arguments should be a condition string of the form "name" or "name:suffix". If no tags are passed as arguments, ListConds lists all conditions registered in the engine e.
type State ¶
type State struct {
// contains filtered or unexported fields
}
A State encapsulates the current state of a running script engine, including the script environment and any running background commands.
func NewState ¶
NewState returns a new State permanently associated with ctx, with its initial working directory in workdir and its initial environment set to initialEnv (or os.Environ(), if initialEnv is nil).
The new State also contains pseudo-environment-variables for ${/} and ${:} (for the platform's path and list separators respectively), but does not pass those to subprocesses.
func (*State) CloseAndWait ¶
CloseAndWait cancels the State's Context and waits for any background commands to finish. If any remaining background command ended in an unexpected state, Close returns a non-nil error.
func (*State) Environ ¶
Environ returns a copy of the current script environment, in the form "key=value".
func (*State) ExpandEnv ¶
ExpandEnv replaces ${var} or $var in the string according to the values of the environment variables in s. References to undefined variables are replaced by the empty string.
func (*State) ExtractFiles ¶
ExtractFiles extracts the files in ar to the state's current directory, expanding any environment variables within each name.
The files must reside within the working directory with which the State was originally created.
func (*State) Logf ¶
Logf writes output to the script's log without updating its stdout or stderr buffers. (The output log functions as a kind of meta-stderr.)
func (*State) LookupEnv ¶
LookupEnv retrieves the value of the environment variable in s named by the key.
func (*State) Path ¶
Path returns the absolute path in the host operaating system for a script-based (generally slash-separated and relative) path.
type UsageError ¶
A UsageError reports the valid arguments for a command.
It may be returned in response to invalid arguments.
func (*UsageError) Error ¶
func (e *UsageError) Error() string
Directories ¶
Path | Synopsis |
---|---|
Package scripttest adapts the script engine for use in tests.
|
Package scripttest adapts the script engine for use in tests. |