script

Imports

Imports #

"bytes"
"context"
"fmt"
"internal/txtar"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"cmd/internal/pathcache"
"cmd/internal/robustio"
"errors"
"fmt"
"internal/diff"
"io/fs"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"sync"
"time"
"errors"
"syscall"
"fmt"
"internal/syslist"
"os"
"runtime"
"sync"
"bufio"
"context"
"errors"
"fmt"
"io"
"sort"
"strings"
"time"
"errors"
"fmt"

Constants & Variables

ErrUnexpectedSuccess var #

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

var ErrUnexpectedSuccess = *ast.CallExpr

ErrUsage var #

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 = *ast.CallExpr

argSepChars const #

const argSepChars = " \t\r\n#"

failure const #

const failure expectedStatus = "!"

matchUsage const #

const matchUsage = "[-count=N] [-q] 'pattern'"

success const #

const success expectedStatus = ""

successOrFailure const #

const successOrFailure expectedStatus = "?"

Type Aliases

WaitFunc type #

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

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

expectedStatus type #

An expectedStatus describes the expected outcome of a command. Script execution halts when a command does not match its expected status.

type expectedStatus string

Interfaces

Cmd interface #

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

type Cmd interface {
Run(s *State, args ...string) (WaitFunc, error)
Usage() *CmdUsage
}

Cond interface #

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

type Cond interface {
Eval(s *State, suffix string) (bool, error)
Usage() *CondUsage
}

Structs

CmdUsage struct #

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

type CmdUsage struct {
Summary string
Args string
Detail []string
Async bool
RegexpArgs func(rawArgs ...string) []int
}

CommandError struct #

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
}

CondUsage struct #

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

type CondUsage struct {
Summary string
Prefix bool
}

Engine struct #

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
Quiet bool
}

State struct #

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

type State struct {
engine *Engine
ctx context.Context
cancel context.CancelFunc
file string
log bytes.Buffer
workdir string
pwd string
env []string
envMap map[string]string
stdout string
stderr string
background []backgroundCmd
}

UsageError struct #

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
}

argFragment struct #

type argFragment struct {
s string
quoted bool
}

backgroundCmd struct #

type backgroundCmd struct {
*command
wait WaitFunc
}

boolCond struct #

type boolCond struct {
v bool
usage CondUsage
}

cachedCond struct #

type cachedCond struct {
m sync.Map
eval func(string) (bool, error)
usage CondUsage
}

command struct #

A command is a complete command parsed from a script.

type command struct {
file string
line int
want expectedStatus
conds []condition
name string
rawArgs [][]argFragment
args []string
background bool
}

condition struct #

type condition struct {
want bool
tag string
}

funcCmd struct #

A funcCmd implements Cmd using a function value.

type funcCmd struct {
usage CmdUsage
run func(*State, ...string) (WaitFunc, error)
}

funcCond struct #

type funcCond struct {
eval func(*State) (bool, error)
usage CondUsage
}

onceCond struct #

type onceCond struct {
eval func() (bool, error)
usage CondUsage
}

prefixCond struct #

type prefixCond struct {
eval func(*State, string) (bool, error)
usage CondUsage
}

stopError struct #

stopError is the sentinel error type returned by the Stop command.

type stopError struct {
msg string
}

waitError struct #

A waitError wraps one or more errors returned by background commands.

type waitError struct {
errs []*CommandError
}

Functions

BoolCondition function #

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

func BoolCondition(summary string, v bool) Cond

CachedCondition function #

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 CachedCondition(summary string, eval func(string) (bool, error)) Cond

Cat function #

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

func Cat() Cmd

Cd function #

Cd changes the current working directory.

func Cd() Cmd

Chdir method #

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

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

Chmod function #

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

func Chmod() Cmd

CloseAndWait method #

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 (s *State) CloseAndWait(log io.Writer) error

Cmp function #

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 Cmp() Cmd

Cmpenv function #

Cmpenv is like Compare, but also performs environment substitutions on the contents of both arguments.

func Cmpenv() Cmd

Command function #

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 Command(usage CmdUsage, run func(*State, ...string) (WaitFunc, error)) Cmd

Condition function #

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

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

Context method #

Context returns the Context with which the State was created.

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

Cp function #

Cp copies one or more files to a new location.

func Cp() Cmd

DefaultCmds function #

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 DefaultCmds() map[string]Cmd

DefaultConds function #

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.

func DefaultConds() map[string]Cond

Echo function #

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

func Echo() Cmd

Env function #

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 Env() Cmd

Environ method #

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

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

Error method #

func (s stopError) Error() string

Error method #

func (w waitError) Error() string

Error method #

func (e *CommandError) Error() string

Error method #

func (e *UsageError) Error() string

Eval method #

func (b *boolCond) Eval(s *State, suffix string) (bool, error)

Eval method #

func (c *funcCond) Eval(s *State, suffix string) (bool, error)

Eval method #

func (c *prefixCond) Eval(s *State, suffix string) (bool, error)

Eval method #

func (c *cachedCond) Eval(_ *State, suffix string) (bool, error)

Eval method #

func (l *onceCond) Eval(s *State, suffix string) (bool, error)

Exec function #

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 Exec(cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd

Execute method #

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 (e *Engine) Execute(s *State, file string, script *bufio.Reader, log io.Writer) (err error)

Exists function #

Exists checks that the named file(s) exist.

func Exists() Cmd

ExpandEnv method #

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 (s *State) ExpandEnv(str string, inRegexp bool) string

ExtractFiles method #

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 (s *State) ExtractFiles(ar *txtar.Archive) error

Getwd method #

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

func (s *State) Getwd() string

Grep function #

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 Grep() Cmd

Help function #

Help writes command documentation to the script log.

func Help() Cmd

ListCmds method #

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 (e *Engine) ListCmds(w io.Writer, verbose bool, names ...string) error

ListConds method #

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.

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

Logf method #

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 (s *State) Logf(format string, args ...any)

LookupEnv method #

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

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

Mkdir function #

Mkdir creates a directory and any needed parent directories.

func Mkdir() Cmd

Mv function #

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

func Mv() Cmd

NewEngine function #

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

func NewEngine() *Engine

NewState function #

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 NewState(ctx context.Context, workdir string, initialEnv []string) (*State, error)

OnceCondition function #

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 OnceCondition(summary string, eval func() (bool, error)) Cond

Path method #

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

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

PrefixCondition function #

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

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

Program function #

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 Program(name string, cancel func(*exec.Cmd) error, waitDelay time.Duration) Cmd

Replace function #

Replace replaces all occurrences of a string in a file with another string.

func Replace() Cmd

Rm function #

Rm removes a file or directory. If a directory, Rm also recursively removes that directory's contents.

func Rm() Cmd

Run method #

func (c *funcCmd) Run(s *State, args ...string) (WaitFunc, error)

Setenv method #

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

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

Sleep function #

Sleep sleeps for the given Go duration or until the script's context is canceled, whichever happens first.

func Sleep() Cmd

Stderr method #

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

func (s *State) Stderr() string

Stderr function #

Stderr searches for a regular expression in the stderr buffer.

func Stderr() Cmd

Stdout method #

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

func (s *State) Stdout() string

Stdout function #

Stdout searches for a regular expression in the stdout buffer.

func Stdout() Cmd

Stop function #

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

func Stop() Cmd

Unwrap method #

func (e *CommandError) Unwrap() error

Unwrap method #

func (w waitError) Unwrap() error

Usage method #

func (c *funcCond) Usage() *CondUsage

Usage method #

func (c *prefixCond) Usage() *CondUsage

Usage method #

func (b *boolCond) Usage() *CondUsage

Usage method #

func (c *funcCmd) Usage() *CmdUsage

Usage method #

func (c *cachedCond) Usage() *CondUsage

Usage method #

func (l *onceCond) Usage() *CondUsage

Wait function #

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.

func Wait() Cmd

checkStatus function #

func checkStatus(cmd *command, err error) error

cleanEnv function #

cleanEnv returns a copy of env with any duplicates removed in favor of later values and any required system variables defined. If env is nil, cleanEnv copies the environment from os.Environ().

func cleanEnv(env []string, pwd string) []string

cmdError function #

func cmdError(cmd *command, err error) *CommandError

conditionsActive method #

func (e *Engine) conditionsActive(s *State, conds []condition) (bool, error)

doCompare function #

func doCompare(s *State, env bool, args ...string) error

expandArgs function #

expandArgs expands the shell variables in rawArgs and joins them to form the final arguments to pass to a command.

func expandArgs(s *State, rawArgs [][]argFragment, regexpArgs []int) []string

firstNonFlag function #

firstNonFlag returns a slice containing the index of the first argument in rawArgs that is not a flag, or nil if all arguments are flags.

func firstNonFlag(rawArgs ...string) []int

flushLog method #

flushLog writes the contents of the script's log to w and clears the log.

func (s *State) flushLog(w io.Writer) error

isETXTBSY function #

func isETXTBSY(err error) bool

isETXTBSY function #

func isETXTBSY(err error) bool

lookPath function #

lookPath is (roughly) like exec.LookPath, but it uses the script's current PATH to find the executable.

func lookPath(s *State, command string) (string, error)

match function #

match implements the Grep, Stdout, and Stderr commands.

func match(s *State, args []string, text string, name string) error

parse function #

parse parses a single line as a list of space-separated arguments. subject to environment variable expansion (but not resplitting). Single quotes around text disable splitting and expansion. To embed a single quote, double it: 'Don''t communicate by sharing memory.'

func parse(filename string, lineno int, line string) (cmd *command, err error)

pathEnvName function #

pathEnvName returns the platform-specific variable used by os/exec.LookPath to look up executable names (either "PATH" or "path"). TODO(bcmills): Investigate whether we can instead use PATH uniformly and rewrite it to $path when executing subprocesses.

func pathEnvName() string

quoteArgs function #

quoteArgs returns a string that parse would parse as args when passed to a command. TODO(bcmills): This function should have a fuzz test.

func quoteArgs(args []string) string

removeAll function #

removeAll removes dir and all files and directories it contains. Unlike os.RemoveAll, removeAll attempts to make the directories writable if needed in order to remove their contents.

func removeAll(dir string) error

runCommand method #

func (e *Engine) runCommand(s *State, cmd *command, impl Cmd) error

startCommand function #

func startCommand(s *State, name string, path string, args []string, cancel func(*exec.Cmd) error, waitDelay time.Duration) (WaitFunc, error)

wrapLine function #

func wrapLine(w io.Writer, line string, cols int, indent string) error

Generated with Arrow