Documentation
¶
Overview ¶
Package rake is a pure-Go (no cgo), MRI-faithful port of the task-graph core of Ruby's Rake (the rake-13.x gem): Rake::Task / Rake::FileTask, the Rake::TaskManager registry and namespace/scope resolution, Rake::FileList filtering, and Rake::InvocationChain circular-dependency detection.
What it is — and isn't. The *pure-compute* half of Rake — the task DAG, the depth-first prerequisite-first invoke order, the invoke-once guard, circular detection, FileTask out-of-date timestamp logic, namespace/scope lookup, rule synthesis, and FileList pattern/exclude filtering — is fully deterministic and needs no interpreter, so it lives here as plain Go. The *effectful* half — the action bodies (the `do ... end` blocks), `sh`/FileUtils, real Dir.glob, and file mtimes — are SEAMS the host injects: an Action is a Go func the host (rbgo) wires to a Ruby block; FileList.Glob and FileTask timestamps are function fields the host wires to the real filesystem. Tests inject deterministic seams, so the whole suite is Ruby-free and reproducible across arches.
Index ¶
- type Action
- type Application
- func (a *Application) Clear()
- func (a *Application) CreateRule(pattern string, argNames, deps, orderOnly []string, action Action)
- func (a *Application) CurrentScope() *Scope
- func (a *Application) DefineTask(kind TaskKind, name string, argNames, deps, orderOnly []string, action Action) TaskItem
- func (a *Application) Desc(description string)
- func (a *Application) Get(taskName string) (TaskItem, error)
- func (a *Application) InNamespace(name string, body func(ns *NameSpace)) *NameSpace
- func (a *Application) Lookup(taskName string, initialScope *Scope) TaskItem
- func (a *Application) TaskDefined(taskName string) bool
- func (a *Application) Tasks() []TaskItem
- func (a *Application) TasksInScope(scope *Scope) []TaskItem
- type Args
- type CircularDependencyError
- type FileList
- func (fl *FileList) ClearExclude() *FileList
- func (fl *FileList) Exclude(patterns ...string) *FileList
- func (fl *FileList) ExcludeFunc(fn func(string) bool) *FileList
- func (fl *FileList) ExcludeRegexp(res ...*regexp.Regexp) *FileList
- func (fl *FileList) Existing(exists func(string) bool) *FileList
- func (fl *FileList) Ext(newExt string) *FileList
- func (fl *FileList) Include(filenames ...string) *FileList
- func (fl *FileList) Resolve() *FileList
- func (fl *FileList) String() string
- func (fl *FileList) Sub(re *regexp.Regexp, rep string) *FileList
- func (fl *FileList) To() []string
- type FileTask
- type InvocationChain
- type NameSpace
- type RuleRecursionOverflowError
- type Scope
- type Task
- func (t *Task) Actions() []Action
- func (t *Task) AddOrderOnly(deps []string) *Task
- func (t *Task) AlreadyInvoked() bool
- func (t *Task) ArgNames() []string
- func (t *Task) Clear() *Task
- func (t *Task) Comment() string
- func (t *Task) Enhance(deps []string, action Action) *Task
- func (t *Task) Execute(args Args) error
- func (t *Task) FullComment() string
- func (t *Task) Invoke(args ...string) error
- func (t *Task) Name() string
- func (t *Task) Needed() bool
- func (t *Task) OrderOnlyPrerequisites() []string
- func (t *Task) PrerequisiteTasks() ([]TaskItem, error)
- func (t *Task) Prerequisites() []string
- func (t *Task) Reenable()
- func (t *Task) Scope() *Scope
- func (t *Task) Source() string
- func (t *Task) Sources() []string
- func (t *Task) Timestamp() time.Time
- type TaskItem
- type TaskKind
- type UndefinedTaskError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Action ¶
Action is a task's action body — the seam for a Ruby `do ... end` block. rbgo wires each Action to invoke the corresponding Ruby block (passing the task and its arguments); tests pass plain Go closures. An Action may return an error to abort the invocation (mirroring an exception escaping the block).
type Application ¶
type Application struct {
// RecordTaskMetadata mirrors TaskManager.record_task_metadata: when true,
// define_task attaches the pending description to the task. MRI defaults it
// off; the DSL turns it on. We default it on so desc/Comment round-trips.
RecordTaskMetadata bool
// BuildAll forces every FileTask to be considered out of date
// (Rake's --build-all / options.build_all).
BuildAll bool
// Stat is the file-mtime seam (Rake::FileTask via File.mtime). It returns
// the file's modification time and whether it exists. nil → always absent.
Stat func(name string) (time.Time, bool)
// Glob is the directory-glob seam (Rake::FileList.glob via Dir.glob). It
// returns the names matching pattern. Results are sorted by FileList, as
// MRI sorts Dir.glob output. nil → empty.
Glob func(pattern string) []string
// contains filtered or unexported fields
}
Application is the task registry and namespace resolver — the port of Rake::Application together with the Rake::TaskManager mixin. It owns the task table, the rule list, the live namespace scope, and the pending description.
Two seams hang off it: Stat resolves a file name to its mtime (for FileTask timestamps; rbgo wires File.mtime), and Glob lists files matching a pattern (for FileList; rbgo wires Dir.glob). Both are nil by default, which makes every file "absent" and every glob empty — fine for the pure task-graph tests.
func NewApplication ¶
func NewApplication() *Application
NewApplication returns an empty task manager with the top-level scope active and metadata recording on (Rake::Application.new + TaskManager#initialize).
func (*Application) Clear ¶
func (a *Application) Clear()
Clear forgets every task and rule (Rake::TaskManager#clear).
func (*Application) CreateRule ¶
func (a *Application) CreateRule(pattern string, argNames, deps, orderOnly []string, action Action)
CreateRule registers a synthesis rule (Rake::TaskManager#create_rule). The string pattern is regexp-quoted and anchored at end-of-name (MRI quotes it and appends "$"), so it always compiles. deps are the source extensions/names, action the rule body.
func (*Application) CurrentScope ¶
func (a *Application) CurrentScope() *Scope
CurrentScope returns the live namespace scope (Rake::TaskManager#current_scope).
func (*Application) DefineTask ¶
func (a *Application) DefineTask(kind TaskKind, name string, argNames, deps, orderOnly []string, action Action) TaskItem
DefineTask defines (or, when one already exists, enhances) a task — the port of Rake::TaskManager#define_task. For a PlainTask whose name embeds namespace segments ("a:b:c"), the leading segments extend the scope used to key the task (MRI splits on ":" and folds the outer segments into the scope); a FileTask ignores the scope entirely (its name is the file path).
deps are the prerequisites, orderOnly the order-only prerequisites, argNames the declared argument names, and action an optional body. It returns the defined task.
func (*Application) Desc ¶
func (a *Application) Desc(description string)
Desc records the description applied to the next defined task (Rake's `desc` DSL → last_description). It is consumed by the following DefineTask, then cleared.
func (*Application) Get ¶
func (a *Application) Get(taskName string) (TaskItem, error)
Get resolves a task by name (Rake::TaskManager#[]): a straight lookup, else rule synthesis, else a file-task synthesized from an existing file, else the "Don't know how to build task" error.
func (*Application) InNamespace ¶
func (a *Application) InNamespace(name string, body func(ns *NameSpace)) *NameSpace
InNamespace evaluates body with name pushed onto the scope, returning a NameSpace over the nested scope (Rake::TaskManager#in_namespace). A nil/empty name yields an anonymous "_anon_N" namespace.
func (*Application) Lookup ¶
func (a *Application) Lookup(taskName string, initialScope *Scope) TaskItem
Lookup performs a straight scoped lookup with no rule/file synthesis (Rake::TaskManager#lookup). It honours the scope hints in the name: "rake:NAME" resolves at top level, "^…" trims that many scope levels. A nil scope means the current scope.
func (*Application) TaskDefined ¶
func (a *Application) TaskDefined(taskName string) bool
TaskDefined reports whether a task with the name is already registered (Rake::Task.task_defined? → lookup != nil).
func (*Application) Tasks ¶
func (a *Application) Tasks() []TaskItem
Tasks returns every defined task sorted by name (Rake::TaskManager#tasks).
func (*Application) TasksInScope ¶
func (a *Application) TasksInScope(scope *Scope) []TaskItem
TasksInScope returns the tasks defined in scope and its sub-scopes (Rake::TaskManager#tasks_in_scope — names prefixed by "scope:").
type Args ¶
type Args struct {
// contains filtered or unexported fields
}
Args carries a task's invocation arguments by name — the pure-compute slice of Rake::TaskArguments (the bookkeeping; value coercion stays in the host).
func NewArgs ¶
NewArgs pairs argument names with the values passed to invoke (Rake::TaskArguments.new). Extra values past the named slots are ignored for lookup but preserved; missing values yield "".
type CircularDependencyError ¶
type CircularDependencyError struct {
Message string
}
CircularDependencyError is the RuntimeError Rake raises when a task's prerequisite graph contains a cycle. Message is byte-for-byte MRI's "Circular dependency detected: TOP => x => y => x".
func (*CircularDependencyError) Error ¶
func (e *CircularDependencyError) Error() string
type FileList ¶
type FileList struct {
// contains filtered or unexported fields
}
FileList is a lazily-resolved list of file names — the port of Rake::FileList. Include records glob patterns and literal names; Exclude records patterns (regexp, glob, literal, or predicate) to filter out. Resolution is deferred: the patterns are expanded (via the Glob seam) and the excludes applied only when the list is observed (To / Resolve). The actual Dir.glob is the seam — a func(pattern) []string injected at construction; everything else (literal adds, default ignores, exclude filtering) is pure.
func NewFileList ¶
NewFileList creates a FileList over the given include patterns, expanding globs through glob (the Dir.glob seam; nil → no expansion). It seeds the default ignore patterns, exactly as Rake::FileList#initialize does.
func (*FileList) ClearExclude ¶
ClearExclude drops every exclude pattern and predicate, including the default ignores (Rake::FileList#clear_exclude). Returns fl.
func (*FileList) Exclude ¶
Exclude records patterns to remove (Rake::FileList#exclude). A pattern with glob metacharacters is matched as a glob, otherwise as a literal name; use ExcludeRegexp for a regexp and ExcludeFunc for a predicate. When nothing is pending, the exclusion is applied immediately (MRI's resolve_exclude unless @pending). Returns fl.
func (*FileList) ExcludeFunc ¶
ExcludeFunc records a predicate exclude — entries for which fn returns true are removed (the block form of Rake::FileList#exclude). Returns fl.
func (*FileList) ExcludeRegexp ¶
ExcludeRegexp records a regexp exclude (the Regexp branch of Rake::FileList#exclude). Returns fl.
func (*FileList) Existing ¶
Existing returns a new list of the entries that exist on the filesystem (Rake::FileList#existing → File.exist?), via the Stat-like exists predicate. exists is the filesystem seam (rbgo wires File.exist?); nil → nothing exists.
func (*FileList) Ext ¶
Ext returns a new list with each entry's file extension swapped to newExt (Rake::FileList#ext → String#ext).
func (*FileList) Include ¶
Include records file names / glob patterns to add (Rake::FileList#include). Resolution is deferred until the list is observed. Returns fl.
func (*FileList) Resolve ¶
Resolve expands pending includes (globs via the seam, literals verbatim) and applies the excludes (Rake::FileList#resolve). Idempotent until the next Include. Returns fl.
type FileTask ¶
type FileTask struct {
*Task
}
FileTask is a task with time-based dependencies — the port of Rake::FileTask. It rebuilds (its actions run) when its target file is missing or older than any prerequisite. The file system is a SEAM: the owning Application's Stat function maps a name to (mtime, exists); rbgo wires it to File.mtime, tests inject a deterministic map.
type InvocationChain ¶
type InvocationChain struct {
// contains filtered or unexported fields
}
InvocationChain tracks the chain of task invocations to detect circular dependencies — the port of Rake::InvocationChain (itself a LinkedList subclass). It is an immutable cons-list of task names; the empty chain (nil) renders as "TOP" (Rake::InvocationChain::EMPTY).
var EmptyChain *InvocationChain
EmptyChain is the Null Object for an empty chain (Rake::InvocationChain::EMPTY).
func (*InvocationChain) Append ¶
func (c *InvocationChain) Append(invocation string) (*InvocationChain, error)
Append returns a new chain with invocation appended, or an error if invocation already appears — Rake's "Circular dependency detected" guard (Rake::InvocationChain#append, which fails with RuntimeError). The returned error is a *CircularDependencyError carrying the exact MRI message.
func (*InvocationChain) Member ¶
func (c *InvocationChain) Member(invocation string) bool
Member reports whether invocation is already somewhere in the chain (Rake::InvocationChain#member?). The empty chain contains nothing.
func (*InvocationChain) String ¶
func (c *InvocationChain) String() string
String renders the chain TOP => a => b (Rake::InvocationChain#to_s). The empty chain is "TOP".
type NameSpace ¶
type NameSpace struct {
// contains filtered or unexported fields
}
NameSpace is the lookup object returned by InNamespace (Rake::NameSpace): it resolves names within, and lists the tasks of, a captured scope.
type RuleRecursionOverflowError ¶
type RuleRecursionOverflowError struct{ Target string }
RuleRecursionOverflowError is Rake::RuleRecursionOverflowError — raised when rule synthesis recurses past 16 levels.
func (*RuleRecursionOverflowError) Error ¶
func (e *RuleRecursionOverflowError) Error() string
type Scope ¶
type Scope struct {
// contains filtered or unexported fields
}
Scope is Rake's namespace stack — the port of Rake::Scope, which in MRI is a LinkedList subclass used as an immutable cons-list of namespace names. The head is the innermost namespace; the empty scope (Scope == nil) is the top-level / Null Object (Rake::Scope::EMPTY).
Like MRI it is a persistent (immutable) singly-linked list: Cons returns a fresh head sharing the same tail, so a saved Scope is never mutated by a later namespace push/pop.
func ScopeMake ¶
ScopeMake builds a scope from names given outermost-first (Rake::Scope.make is called innermost-first; the manager builds it from a reversed split, so this helper takes the natural outer→inner order the caller already has).
func (*Scope) Cons ¶
Cons returns a new scope with name pushed onto s (MRI Scope#conj / cons). Calling on a nil (empty) scope starts a one-element scope.
func (*Scope) Path ¶
Path is Rake::Scope#path — the namespace names joined outer:inner by ":". The empty scope's path is "".
func (*Scope) PathWithTaskName ¶
PathWithTaskName is Rake::Scope#path_with_task_name — the scope path prefixed onto taskName. The empty scope returns taskName unchanged (EmptyScope).
type Task ¶
type Task struct {
// contains filtered or unexported fields
}
Task is the basic unit of work — the port of Rake::Task. It carries a name, prerequisites (ordinary and order-only), action bodies, the already-invoked guard, and the owning application for prerequisite lookup.
func (*Task) AddOrderOnly ¶
AddOrderOnly adds order-only prerequisites — the union minus any already an ordinary prerequisite (Rake::Task#| ). Returns t.
func (*Task) AlreadyInvoked ¶
AlreadyInvoked reports whether invoke has already run (Rake::Task#already_invoked).
func (*Task) Clear ¶
Clear empties prerequisites, actions, comments, and arguments (Rake::Task#clear).
func (*Task) Comment ¶
Comment is the first sentence of each comment joined by " / " (Rake::Task#comment).
func (*Task) Enhance ¶
Enhance adds prerequisites (union, preserving order) and an optional action, returning t — Rake::Task#enhance.
func (*Task) Execute ¶
Execute runs the task's actions unconditionally (Rake::Task#execute), in the order they were added. With no actions it is a no-op (after rule enhancement, handled by the manager). args are passed to each action.
func (*Task) FullComment ¶
FullComment joins all comments with newlines, or "" when there are none (Rake::Task#full_comment).
func (*Task) Invoke ¶
Invoke runs the task, prerequisites first, under a fresh invocation chain — Rake::Task#invoke. args are the positional argument values bound to the task's declared arg names.
func (*Task) Needed ¶
Needed reports whether a basic task's actions must run — always true (Rake::Task#needed?). FileTask overrides this.
func (*Task) OrderOnlyPrerequisites ¶
OrderOnlyPrerequisites returns the order-only prerequisite names (Rake::Task#order_only_prerequisites).
func (*Task) PrerequisiteTasks ¶
PrerequisiteTasks resolves every prerequisite (ordinary then order-only) to its task via the application — Rake::Task#prerequisite_tasks. A prerequisite is looked up scoped first; if that resolves to t itself, the unscoped lookup is preferred (MRI's lookup_prerequisite, which lets a task depend on a same-named task in an outer scope).
func (*Task) Prerequisites ¶
Prerequisites returns the ordinary prerequisite names (Rake::Task#prerequisites).
func (*Task) Reenable ¶
func (t *Task) Reenable()
Reenable clears the already-invoked guard so the task runs again on the next invoke (Rake::Task#reenable).
type TaskItem ¶
type TaskItem interface {
// Name is the fully-qualified task name (namespace-prefixed).
Name() string
// Needed reports whether the task's actions must run (Task#needed?:
// always true; FileTask#needed?: out-of-date timestamp logic).
Needed() bool
// Timestamp is the task's time stamp (Task#timestamp: now; FileTask: the
// file mtime, or the distant-future LATE sentinel when absent).
Timestamp() time.Time
// contains filtered or unexported methods
}
TaskItem is the behaviour every task kind exposes — Rake::Task and its subclass Rake::FileTask. It is the interface a prerequisite is resolved to, so the manager and the invoke walk treat plain tasks and file tasks uniformly.
type TaskKind ¶
type TaskKind int
TaskKind selects which Task subclass define_task creates — a plain task (`task`) or a file task (`file`). It is the Go stand-in for the task_class argument MRI's TaskManager#define_task receives.
type UndefinedTaskError ¶
type UndefinedTaskError struct{ Name string }
UndefinedTaskError is the error Get raises for an unknown task. Message mirrors MRI's "Don't know how to build task '…'".
func (*UndefinedTaskError) Error ¶
func (e *UndefinedTaskError) Error() string
