Documentation
¶
Index ¶
- Constants
- Variables
- func Compile(ctx context.Context, pkgdir, binfile string) error
- func CompilePackage(ctx context.Context, pkg *packages.Package, binfile string) error
- func Describe(target Target) string
- func GetArgs(ctx context.Context) []string
- func GetForce(ctx context.Context) bool
- func GetVerbose(ctx context.Context) bool
- func Indentf(ctx context.Context, format string, args ...any)
- func IndentingCopier(ctx context.Context, w io.Writer, prefix string) io.Writer
- func ListTargets()
- func OpenHashDB(ctx context.Context, dir string) (*sqlite.DB, error)
- func ReadYAML(r io.Reader) error
- func ReadYAMLFile() error
- func RegisterYAMLStringList(name string, fn YAMLStringListFunc)
- func RegisterYAMLTarget(name string, fn YAMLTargetFunc)
- func RegistryNames() []string
- func Run(ctx context.Context, targets ...Target) error
- func WithArgs(ctx context.Context, args ...string) context.Context
- func WithForce(ctx context.Context, force bool) context.Context
- func WithHashDB(ctx context.Context, db HashDB) context.Context
- func WithRunner(ctx context.Context, r *Runner) context.Context
- func WithVerbose(ctx context.Context, verbose bool) context.Context
- func YAMLStringList(node *yaml.Node) ([]string, error)
- func YAMLStringListFromNodes(nodes []*yaml.Node) ([]string, error)
- type Command
- type CommandErr
- type HashDB
- type Main
- type Runner
- type Target
- func All(targets ...Target) Target
- func ArgTarget(target Target, args ...string) Target
- func Clean(files ...string) Target
- func Deps(target Target, depTargets ...Target) Target
- func F(f func(context.Context) error) Target
- func Files(target Target, in, out []string) Target
- func ParseArgs(args []string) ([]Target, error)
- func RegisterTarget(name, doc string, target Target) (Target, error)
- func RegistryTarget(name string) (Target, string)
- func Seq(targets ...Target) Target
- func YAMLTarget(node *yaml.Node) (Target, error)
- type YAMLStringListFunc
- type YAMLTargetFunc
Constants ¶
const LoadMode = packages.NeedName | packages.NeedFiles | packages.NeedTypes | packages.NeedDeps
LoadMode is the minimal set of flags to enable for Config.Mode in a call to Packages.Load in order to produce a suitable package object for CompilePackage.
Variables ¶
var DefaultRunner = NewRunner()
DefaultRunner is a Runner used by default in Run.
Functions ¶
func Compile ¶ added in v0.8.0
Compile compiles a "driver" from a directory of user code (combined with a main function supplied by fab) and places the executable result in a given file. The driver converts command-line target names into the necessary Fab rule invocations.
The package of user code should contain one or more exported identifiers whose types satisfy the Target interface. These become the build rules that the driver can invoke.
When Compile runs the "go" program must exist in the user's PATH. It must be Go version 1.19 or later.
How it works:
- The user's code is loaded with packages.Load.
- The set of exported top-level identifiers is filtered to find those implementing the fab.Target interface.
- The user's code is then copied to a temp directory together with a main package (and main() function) that registers (with Register) that set of targets.
- The go compiler is invoked to produce an executable, which is renamed into place as binfile.
For the synthesized calls to Register on Target-valued variables, the driver uses the variable's name as the "name" argument and the variable's doc comment as the "doc" argument.
The user's code is able to make its own calls to Register during program initialization in order to augment the set of available targets.
func CompilePackage ¶ added in v0.28.0
CompilePackage compiles a driver from a package object already loaded with packages.Load. The call to packages.Load must use a value for Config.Mode that contains at least the bits in LoadMode. See Compile for further details.
func Describe ¶ added in v0.31.0
Describe describes a target. The description is the target's name in the registry, if it has one (i.e., if the target was registered with RegisterTarget), otherwise it's "unnamed X" where X is the result of calling the target's Desc method.
func GetArgs ¶ added in v0.29.0
GetArgs returns the list of arguments added to `ctx` with WithArgs. The default, if WithArgs was not used, is nil.
func GetForce ¶ added in v0.16.0
GetForce returns the value of the force boolean added to `ctx` with WithForce. The default, if WithForce was not used, is false.
func GetVerbose ¶
GetVerbose returns the value of the verbose boolean added to `ctx` with WithVerbose. The default, if WithVerbose was not used, is false.
func Indentf ¶ added in v0.9.0
Indentf calls Runner.Indent with the given format and args if a Runner can be found in the given context. If one cannot, then the formatted string is simply printed (with a trailing newline added if needed).
func IndentingCopier ¶ added in v0.34.0
IndentingCopier creates an io.Writer that copies its data to an underlying writer, indenting each line according to the indentation depth of the Runner in the given context. After indentation, each line additionally gets any prefix specified in `prefix`.
The wrapper converts \r\n to \n, and bare \r to \n.
func ListTargets ¶ added in v0.30.0
func ListTargets()
ListTargets outputs a formatted list of the targets in the registry and their docstrings.
func OpenHashDB ¶ added in v0.30.0
OpenHashDB ensures the given directory exists and opens (or creates) the hash DB there. Callers must make sure to call Close on the returned DB when finished with it.
func ReadYAML ¶ added in v0.30.0
ReadYAML reads a YAML document from the given source, registering Targets that it finds.
The top level of the YAML document should be a mapping from names to targets. Each target is either a target-typed node, selected by a !tag, or the name of some other target.
For example, the following creates a target named `Check`, which is an `All`-typed target referring to two other targets: `Vet` and `Test`. Each of those is a `Command`-typed target executing specific shell commands.
Check: !All - Vet - Test Vet: !Command - go vet ./... Test: !Command - go test ./...
func ReadYAMLFile ¶ added in v0.30.0
func ReadYAMLFile() error
ReadYAMLFile calls ReadYAML on the file `fab.yaml` in the current directory or, if that doesn't exist, `fab.yml`.
func RegisterYAMLStringList ¶ added in v0.30.0
func RegisterYAMLStringList(name string, fn YAMLStringListFunc)
RegisterYAMLStringList places a function in the YAML string-list registry with the given name. Use a YAML `!name` tag to introduce a node that should be parsed using this function.
func RegisterYAMLTarget ¶ added in v0.30.0
func RegisterYAMLTarget(name string, fn YAMLTargetFunc)
RegisterYAMLTarget places a function in the YAML target registry with the given name. Use a YAML `!name` tag to introduce a node that should be parsed using this function.
func RegistryNames ¶ added in v0.21.0
func RegistryNames() []string
RegistryNames returns the names in the target registry.
func Run ¶
Run runs the given targets with a Runner. If `ctx` contains a Runner (e.g., because this call is nested inside a pending call to Runner.Run and the context has been decorated using WithRunner) then it uses that Runner, otherwise it uses DefaultRunner.
A given Runner will not run the same target more than once. See Runner.Run.
func WithArgs ¶ added in v0.29.0
WithArgs decorates a context with a list of arguments as a slice of strings. Retrieve it with GetArgs.
func WithForce ¶ added in v0.16.0
WithForce decorates a context with the value of a "force" boolean. Retrieve it with GetForce.
func WithHashDB ¶
WithHashDB decorates a context with a HashDB. Retrieve it with GetHashDB.
func WithRunner ¶
WithRunner decorates a context with a Runner. Retrieve it with GetRunner.
func WithVerbose ¶
WithVerbose decorates a context with the value of a "verbose" boolean. Retrieve it with GetVerbose.
func YAMLStringList ¶ added in v0.30.0
YAMLStringList parses a []string from a YAML node. If the node has a tag `!foo`, then the YAMLStringListFunc in the YAML string-list registry named `foo` is used to parse the node. Otherwise, the node is expected to be a sequence, and YAMLStringListFromNodes is called on its children.
func YAMLStringListFromNodes ¶ added in v0.30.0
YAMLStringListFromNodes constructs a slice of strings from a slice of YAML nodes. Each node may be a plain scalar, in which case it is added to the result slice; or a tagged node, in which case it is parsed with the corresponding YAML string-list registry function and the output appended to the result slice.
Types ¶
type Command ¶
type Command struct {
// Shell is the command to run,
// as a single string with command name and arguments together.
// It is invoked with $SHELL -c,
// with $SHELL defaulting to /bin/sh.
//
// If you prefer to specify a command that is not executed by a shell,
// leave Shell blank and fill in Cmd and Args instead.
//
// To bypass this parsing behavior,
// you may specify Cmd and Args directly.
Shell string `json:"shell,omitempty"`
// Cmd is the command to invoke,
// either the path to a file,
// or an executable file found in some directory
// named in the PATH environment variable.
//
// If you need your command string to be parsed by a shell,
// leave Cmd and Args blank and specify Shell instead.
Cmd string `json:"cmd,omitempty"`
// Args is the list of command-line arguments
// to pass to the command named in Cmd.
Args []string `json:"args,omitempty"`
// Stdout tells where to send the command's output.
// When no output destination is specified,
// the default depends on whether Fab is running in verbose mode
// (i.e., if [GetVerbose] returns true).
// In verbose mode,
// the command's output is indented and copied to Fab's standard output
// (using [IndentingCopier]).
// Otherwise,
// the command's output is captured
// and bundled together with any error into a [CommandErr].
//
// Stdout, StdoutFile, and StdoutFn are all mutually exclusive.
Stdout io.Writer `json:"-"`
// Stderr tells where to send the command's error output.
// When no error-output destination is specified,
// the default depends on whether Fab is running in verbose mode
// (i.e., if [GetVerbose] returns true).
// In verbose mode,
// the command's error output is indented and copied to Fab's standard error
// (using [IndentingCopier]).
// Otherwise,
// the command's error output is captured
// and bundled together with any error into a [CommandErr].
//
// Stderr, StderrFile, and StderrFn are all mutually exclusive.
Stderr io.Writer `json:"-"`
// StdoutFn lets you defer assigning a value to Stdout
// until Execute is invoked,
// at which time its context object is passed to this function to produce the [io.Writer] to use.
// If the writer produced by this function is also an [io.Closer],
// its Close method will be called before Execute exits.
//
// Stdout, StdoutFile, and StdoutFn are all mutually exclusive.
StdoutFn func(context.Context) io.Writer `json:"-"`
// StderrFn lets you defer assigning a value to Stderr
// until Execute is invoked,
// at which time its context object is passed to this function to produce the [io.Writer] to use.
// If the writer produced by this function is also an [io.Closer],
// its Close method will be called before Execute exits.
//
// Stderr, StderrFile, and StderrFn are all mutually exclusive.
StderrFn func(context.Context) io.Writer `json:"-"`
// StdoutFile is the name of a file to which the command's standard output should go.
// When the command runs,
// the file is created or overwritten,
// unless this string has a >> prefix,
// which means "append."
// If StdoutFile and StderrFile name the same file,
// output from both streams is combined there.
//
// Stdout, StdoutFile, and StdoutFn are all mutually exclusive.
StdoutFile string `json:"stdout_file,omitempty"`
// StderrFile is the name of a file to which the command's standard error should go.
// When the command runs,
// the file is created or overwritten,
// unless this string has a >> prefix,
// which means "append."
// If StdoutFile and StderrFile name the same file,
// output from both streams is combined there.
//
// Stderr, StderrFile, and StderrFn are all mutually exclusive.
StderrFile string `json:"stderr_file,omitempty"`
// Stdin tells where to read the command's standard input.
Stdin io.Reader `json:"-"`
// StdinFile is the name of a file from which the command should read its standard input.
// It is mutually exclusive with Stdin.
// It is an error for the file not to exist when the command runs.
StdinFile string `json:"stdin_file,omitempty"`
// Dir is the directory in which to run the command.
// The default is the value of GetDir(ctx) when the Execute method is called.
Dir string `json:"dir,omitempty"`
// Env is a list of VAR=VALUE strings to add to the environment when the command runs.
Env []string `json:"env,omitempty"`
}
Command is a Target whose Execute function executes a command in a subprocess.
It is JSON-encodable (and therefore usable as the subtarget in Files).
A Command target may be specified in YAML using the !Command tag, which introduces a mapping with the following fields:
- Shell, the command string to execute with $SHELL, mutually exclusive with Cmd.
- Cmd, an executable command invoked with Args as its arguments, mutually exclusive with Shell.
- Args, list of arguments for Cmd.
- Stdin, the name of a file from which the command's standard input should be read, or the special string $stdin to mean read Fab's standard input.
- Stdout, the name of a file to which the command's standard output should be written. The file is overwritten unless this is prefixed with >> which means append. This may also be one of these special strings: $stdout (copy the command's output to Fab's standard output); $stderr (copy the command's output to Fab's standard error); $indent (indent the command's output with IndentingCopier and copy it to Fab's standard output); $discard (discard the command's output).
- Stderr, the name of a file to which the command's standard error should be written. The file is overwritten unless this is prefixed with >> which means append. This may also be one of these special strings: $stdout (copy the command's error output to Fab's standard error); $stderr (copy the command's error output to Fab's standard error); $indent (indent the command's error output with IndentingCopier and copy it to Fab's standard error); $discard (discard the command's error output).
- Dir, the directory in which the command should run.
- Env, a list of VAR=VALUE strings to add to the command's environment.
func Shellf ¶ added in v0.34.0
Shellf is a convenience routine that produces a *Command whose Shell field is initialized by processing `format` and `args` with fmt.Sprintf.
type CommandErr ¶
CommandErr is a type of error that may be returned from command.Execute. If the command's Stdout or Stderr field was nil, then that output from the subprocess is in CommandErr.Output and the underlying error is in CommandErr.Err.
type HashDB ¶
type HashDB interface {
// Has tells whether the database contains the given entry.
Has(context.Context, []byte) (bool, error)
// Add adds an entry to the database.
Add(context.Context, []byte) error
}
HashDB is the type of a database for storing hashes. It must permit concurrent operations safely. It may expire entries to save space.
type Main ¶ added in v0.11.0
type Main struct {
// Pkgdir is where to find the user's build-rules Go package, e.g. "_fab".
Pkgdir string
// Fabdir is where to find the user's hash DB and compiled binaries, e.g. $HOME/.cache/fab.
Fabdir string
// Verbose tells whether to run the driver in verbose mode
// (by supplying the -v command-line flag).
Verbose bool
// List tells whether to run the driver in list-targets mode
// (by supplying the -list command-line flag).
List bool
// Force tells whether to force recompilation of the driver before running it.
Force bool
// Args contains the additional command-line arguments to pass to the driver, e.g. target names.
Args []string
}
Main is the structure whose Run methods implements the main logic of the fab command.
func (Main) Run ¶ added in v0.11.0
Run executes the main logic of the fab command. A driver binary with a name matching m.Pkgdir is sought in m.Fabdir. If it does not exist, or if its corresponding dirhash is wrong (i.e., out of date with respect to the user's code), or if m.Force is true, it is created with Compile. It is then invoked with the command-line arguments indicated by the fields of m. Typically this will include one or more target names, in which case the driver will execute the associated rules as defined by the code in m.Pkgdir.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner is an object that knows how to run Targets without ever running the same Target twice.
A zero runner is not usable. Use NewRunner to obtain one instead.
func GetRunner ¶
GetRunner returns the value of the Runner added to `ctx` with WithRunner. The default, if WithRunner was not used, is nil.
func (*Runner) Indentf ¶ added in v0.8.0
Indentf formats and prints its arguments with leading indentation based on the nesting depth of the Runner. The nesting depth increases with each call to Runner.Run and decreases at the end of the call.
A newline is added to the end of the string if one is not already there.
func (*Runner) Run ¶
Run runs the given targets, skipping any that have already run.
A Runner remembers which targets it has already run (whether in this call or any previous call to Run).
The targets are executed concurrently. A separate goroutine is created for each one passed to Run. If the Runner has never yet run the target, it does so, and caches the result (error or no error). If the target did already run, the cached error value is used. If another goroutine concurrently requests the same target, it blocks until the first one completes, then uses the first one's result.
This function waits for all goroutines to complete. The return value may be an accumulation of multiple errors produced with errors.Join.
The runner is added to the context with WithRunner and can be retrieved with GetRunner. Calls to Run will use it instead of DefaultRunner by finding it in the context.
type Target ¶
type Target interface {
// Execute invokes the target's logic.
//
// Callers generally should not invoke a target's Execute method.
// Instead, pass the target to a [Runner]'s Run method,
// or to the global [Run] function.
// That will handle concurrency properly
// and make sure that the target is not rerun
// when it doesn't need to be.
Execute(context.Context) error
// Desc produces a short descriptive string for this target.
// It is used by [Describe] when the target is not found in the target registry.
Desc() string
}
Target is the interface that Fab targets must implement.
func All ¶ added in v0.3.0
All produces a target that runs a collection of targets in parallel.
It is JSON-encodable (and therefore usable as the subtarget in Files) if all of the targets in its collection are.
An All target may be specified in YAML using the tag !All, which introduces a sequence. The elements in the sequence are targets themselves, or target names.
func ArgTarget ¶ added in v0.29.0
ArgTarget produces a target with associated arguments as a list of strings, suitable for parsing with the flag package. When the target runs, its arguments are available from the context using GetArgs.
It is JSON-encodable (and therefore usable as the subtarget in Files) if its subtarget is.
An ArgTarget target may be specified in YAML using the tag !ArgTarget, which introduces a sequence. The first element of the sequence is a target or target name. The remaining elements of the sequence are interpreted byu YAMLStringListFromNodes to produce the arguments for the target.
func Clean ¶ added in v0.18.0
Clean is a Target that deletes the files named in Files when it runs. Files that don't exist are silently ignored.
A Clean target may be specified in YAML using the tag !Clean, which introduces a sequence. The elements of the sequence are interpreted by YAMLStringListFromNodes to produce the list of files for the target.
func Deps ¶ added in v0.3.0
Deps wraps a target with a set of dependencies, making sure those run first.
It is equivalent to Seq(All(depTargets...), target).
A Deps target may be specified in YAML using the !Deps tag. This may introduce a sequence or a mapping.
If a sequence, then the first element is the main subtarget (or target name), and the remaining elements are dependency targets (or names). Example:
Foo: !Deps - Main - Pre1 - Pre2
This creates target Foo, which runs target Main after running Pre1 and Pre2.
If a mapping, then the `Pre` field specifies a sequence of dependency targets, and the `Post` field specifies the main subtarget. Example:
Foo: !Deps
Pre:
- Pre1
- Pre2
Post: Main
This is equivalent to the first example above.
func F ¶
F produces a target whose Execute function invokes the given function. It is not JSON-encodable, so it should not be used as the subtarget in a Files rule.
func Files ¶ added in v0.25.0
Files creates a target that contains a list of input files and a list of expected output files. It also contains a nested subtarget whose Execute method should produce or update the expected output files.
When the Files target runs, a hash is computed from the nested subtarget and all the input and output files. If none of those has changed since the last time the output files were built, then the output files are up to date and running of this Files target can be skipped.
The nested subtarget must be of a type that can be JSON-marshaled. Note that this excludes F, among others.
When a Files target runs, it checks to see whether any of its input files are listed as output files in other Files targets. Other targets found in this way are Run first, as prerequisites.
The list of input files should mention every file where a change should cause a rebuild. Ideally this includes any files required by the nested subtarget plus any transitive dependencies. See the Deps function in the golang subpackage for an example of a function that can compute such a list for a Go package.
A Files target may be specified in YAML using the !Files tag, which introduces a mapping whose fields are:
- Target: the nested subtarget, or target name
- In: the list of input files, interpreted with YAMLStringList
- Out: the list of output files, interpreted with YAMLStringList
Example:
Foo: !Files
Target: !Command
- go build -o thingify ./cmd/thingify
In: !golang.Deps
Dir: cmd
Out:
- thingify
This creates target Foo, which runs the given `go build` command to update the output file `thingify` when any files depended on by the Go package in `cmd` change.
func ParseArgs ¶ added in v0.30.0
ParseArgs parses the remaining arguments on a fab command line, after option flags. They are either a list of target names in the registry, in which case those targets are returned; or a single registry target followed by option flags for that, in which case the target is wrapped up in an ArgTarget with its options. The two cases are distinguished by whether there is a second argument and whether it begins with a hyphen. (That's the ArgTarget case.)
func RegisterTarget ¶ added in v0.31.0
RegisterTarget places a target in the registry with a given name and doc string.
func RegistryTarget ¶ added in v0.21.0
RegistryTarget returns the target in the registry with the given name, and its doc string.
func Seq ¶ added in v0.4.0
Seq produces a target that runs a collection of targets in sequence. Its Execute method exits early when a target in the sequence fails.
It is JSON-encodable (and therefore usable as the subtarget in Files) if all of the targets in its collection are.
A Seq target may be specified in YAML using the tag !Seq, which introduces a sequence. The elements in the sequence are targets themselves, or target names.
func YAMLTarget ¶ added in v0.30.0
YAMLTarget parses a Target from a YAML node. If the node has a tag `!foo`, then the YAMLTargetFunc in the YAML target registry named `foo` is used to parse the node. Otherwise, if the node is a bare string `foo`, then it is presumed to refer to a target in the (non-YAML) target registry named `foo`.
type YAMLStringListFunc ¶ added in v0.30.0
YAMLStringListFunc is the type of a function in the YAML string-list registry.