...

Package script

import "cmd/go/internal/script"
Overview
Index
Subdirectories

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
    func (e *CommandError) Error() string
    func (e *CommandError) Unwrap() error
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
    func NewEngine() *Engine
    func (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Writer) (err error)
    func (e *Engine) ListCmds(w io.Writer, verbose bool, names ...string) error
    func (e *Engine) ListConds(w io.Writer, s *State, tags ...string) error
type State
    func NewState(ctx context.Context, workdir string, initialEnv []string) (*State, error)
    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
    func (e *UsageError) Error() string
type WaitFunc

Package files

cmds.go cmds_posix.go conds.go engine.go errors.go state.go

Variables

ErrUnexpectedSuccess indicates that a script command that was expected to fail (as indicated by a "!" prefix) instead completed successfully.

var ErrUnexpectedSuccess = errors.New("unexpected success")

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.

var ErrUsage = errors.New("invalid usage")

func DefaultCmds

func DefaultCmds() map[string]Cmd

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

func DefaultConds() map[string]Cond

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.

type Cmd

A Cmd is a command that is available to a script.

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
}

func Cat

func Cat() Cmd

Cat writes the concatenated contents of the named file(s) to the script's stdout buffer.

func Cd

func Cd() Cmd

Cd changes the current working directory.

func Chmod

func Chmod() Cmd

Chmod changes the permissions of a file or a directory..

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

func Command(usage CmdUsage, run func(*State, ...string) (WaitFunc, error)) Cmd

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 Cp

func Cp() Cmd

Cp copies one or more files to a new location.

func Echo

func Echo() Cmd

Echo writes its arguments to stdout, followed by a newline.

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

func Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd

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 Exists

func Exists() Cmd

Exists checks that the named file(s) exist.

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 Help

func Help() Cmd

Help writes command documentation to the script log.

func Mkdir

func Mkdir() Cmd

Mkdir creates a directory and any needed parent directories.

func Mv

func Mv() Cmd

Mv renames an existing file or directory to a new path.

func Program

func Program(name string, cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd

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.

func Stderr

func Stderr() Cmd

Stderr searches for a regular expression in the stderr buffer.

func Stdout

func Stdout() Cmd

Stdout searches for a regular expression in the stdout buffer.

func Stop

func Stop() Cmd

Stop returns a sentinel error that causes script execution to halt and s.Execute to return with a nil error.

func Symlink() Cmd

Symlink creates a symbolic link.

func Wait

func Wait() Cmd

Wait waits for the completion of background commands.

When Wait returns, the stdout and stderr buffers contain the concatenation of the background commands' respective outputs in the order in which those commands were started.

type CmdUsage

A CmdUsage describes the usage of a Cmd, independent of its name (which can change based on its registration).

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
}

type CommandError

A CommandError describes an error resulting from attempting to execute a specific command.

type CommandError struct {
    File string
    Line int
    Op   string
    Args []string
    Err  error
}

func (*CommandError) Error

func (e *CommandError) Error() string

func (*CommandError) Unwrap

func (e *CommandError) Unwrap() error

type Cond

A Cond is a condition deciding whether a command should be run.

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
}

func BoolCondition

func BoolCondition(summary string, v bool) Cond

BoolCondition returns a Cond with the given truth value and summary. The Cond rejects the use of condition suffixes.

func CachedCondition

func CachedCondition(summary string, eval func(string) (bool, error)) Cond

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 Condition

func Condition(summary string, eval func(*State) (bool, error)) Cond

Condition returns a Cond with the given summary and evaluation function.

func OnceCondition

func OnceCondition(summary string, eval func() (bool, error)) Cond

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.

func PrefixCondition

func PrefixCondition(summary string, eval func(*State, string) (bool, error)) Cond

PrefixCondition returns a Cond with the given summary and evaluation function.

type CondUsage

A CondUsage describes the usage of a Cond, independent of its name (which can change based on its registration).

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
}

type Engine

An Engine stores the configuration for executing a set of scripts.

The same Engine may execute multiple scripts concurrently.

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
}

func NewEngine

func NewEngine() *Engine

NewEngine returns an Engine configured with a basic set of commands and conditions.

func (*Engine) Execute

func (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Writer) (err error)

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

func (e *Engine) ListCmds(w io.Writer, verbose bool, names ...string) error

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

func (e *Engine) ListConds(w io.Writer, s *State, tags ...string) error

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

A State encapsulates the current state of a running script engine, including the script environment and any running background commands.

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

func NewState

func NewState(ctx context.Context, workdir string, initialEnv []string) (*State, error)

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) Chdir

func (s *State) Chdir(path string) error

Chdir changes the State's working directory to the given path.

func (*State) CloseAndWait

func (s *State) CloseAndWait(log io.Writer) error

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) Context

func (s *State) Context() context.Context

Context returns the Context with which the State was created.

func (*State) Environ

func (s *State) Environ() []string

Environ returns a copy of the current script environment, in the form "key=value".

func (*State) ExpandEnv

func (s *State) ExpandEnv(str string, inRegexp bool) string

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

func (s *State) ExtractFiles(ar *txtar.Archive) error

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) Getwd

func (s *State) Getwd() string

Getwd returns the directory in which to run the next script command.

func (*State) Logf

func (s *State) Logf(format string, args ...any)

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

func (s *State) LookupEnv(key string) (string, bool)

LookupEnv retrieves the value of the environment variable in s named by the key.

func (*State) Path

func (s *State) Path(path string) string

Path returns the absolute path in the host operating system for a script-based (generally slash-separated and relative) path.

func (*State) Setenv

func (s *State) Setenv(key, value string) error

Setenv sets the value of the environment variable in s named by the key.

func (*State) Stderr

func (s *State) Stderr() string

Stderr returns the stderr output of the last command run, or the empty string if no command has been run.

func (*State) Stdout

func (s *State) Stdout() string

Stdout returns the stdout output of the last command run, or the empty string if no command has been run.

type UsageError

A UsageError reports the valid arguments for a command.

It may be returned in response to invalid arguments.

type UsageError struct {
    Name    string
    Command Cmd
}

func (*UsageError) Error

func (e *UsageError) Error() string

type WaitFunc

A WaitFunc is a function called to retrieve the results of a Cmd.

type WaitFunc func(*State) (stdout, stderr string, err error)

Subdirectories

Name Synopsis
..