Documentation
¶
Overview ¶
Package commands provides the stable command authoring and registry API for gbash.
Most embedders should construct and run sandboxes through the root `github.com/ewhauser/gbash` package and only import commands when they need to:
- implement custom commands
- customize a command registry
- reuse gbash's command-spec parsing, bounded-read helpers, and invocation helpers
gbash's shipped command implementations live under internal/ and are not part of this package's public API.
The usual extension flow is:
- define a command with DefineCommand or a type that implements Command
- read stdin or files with ReadAll, ReadAllStdin, or CommandFS.ReadFile
- access the sandboxed filesystem through [Invocation.FS]
- use [Invocation.Fetch] and [Invocation.Exec] instead of host networking or subprocess APIs
- register commands with NewRegistry and pass that registry to the root gbash runtime
A minimal custom command looks like:
registry := commands.NewRegistry(
commands.DefineCommand("upper", func(ctx context.Context, inv *commands.Invocation) error {
data, err := commands.ReadAllStdin(ctx, inv)
if err != nil {
return err
}
_, err = inv.Stdout.Write(bytes.ToUpper(data))
return err
}),
)
The package is intentionally capability-oriented. Custom commands should prefer Invocation, CommandFS, and the shared helpers in this package over direct use of host APIs so policy enforcement, tracing, and size limits stay consistent with built-in commands.
Index ¶
- func DiagnosticMessage(err error) (string, bool)
- func Diagnosticf(format string, args ...any) error
- func ExitCode(err error) (int, bool)
- func Exitf(inv *Invocation, code int, format string, args ...any) error
- func ReadAll(ctx context.Context, inv *Invocation, reader io.Reader) ([]byte, error)
- func ReadAllStdin(ctx context.Context, inv *Invocation) ([]byte, error)
- func RenderCommandHelp(w io.Writer, spec *CommandSpec) error
- func RenderCommandVersion(w io.Writer, spec *CommandSpec) error
- func RenderDetailedVersion(w io.Writer, info *VersionInfo) error
- func RenderSimpleVersion(w io.Writer, name string) error
- func RunCommand(ctx context.Context, cmd Command, inv *Invocation) error
- type ArgSpec
- type Command
- type CommandFS
- func (fs *CommandFS) Chdir(name string) error
- func (fs *CommandFS) Chmod(ctx context.Context, name string, mode stdfs.FileMode) error
- func (fs *CommandFS) Chown(ctx context.Context, name string, uid, gid uint32, follow bool) error
- func (fs *CommandFS) Chtimes(ctx context.Context, name string, atime, mtime time.Time) error
- func (fs *CommandFS) Getwd() string
- func (fs *CommandFS) Link(ctx context.Context, oldName, newName string) error
- func (fs *CommandFS) Lstat(ctx context.Context, name string) (stdfs.FileInfo, error)
- func (fs *CommandFS) MkdirAll(ctx context.Context, name string, perm stdfs.FileMode) error
- func (fs *CommandFS) Open(ctx context.Context, name string) (gbfs.File, error)
- func (fs *CommandFS) OpenFile(ctx context.Context, name string, flag int, perm stdfs.FileMode) (gbfs.File, error)
- func (fs *CommandFS) ReadDir(ctx context.Context, name string) ([]stdfs.DirEntry, error)
- func (fs *CommandFS) ReadFile(ctx context.Context, name string) ([]byte, error)
- func (fs *CommandFS) Readlink(ctx context.Context, name string) (string, error)
- func (fs *CommandFS) Realpath(ctx context.Context, name string) (string, error)
- func (fs *CommandFS) Remove(ctx context.Context, name string, recursive bool) error
- func (fs *CommandFS) Rename(ctx context.Context, oldName, newName string) error
- func (fs *CommandFS) Resolve(name string) string
- func (fs *CommandFS) Stat(ctx context.Context, name string) (stdfs.FileInfo, error)
- func (fs *CommandFS) Symlink(ctx context.Context, target, linkName string) error
- type CommandFunc
- type CommandRegistry
- type CommandSpec
- type ExecutionRequest
- type ExecutionResult
- type ExitError
- type FetchFunc
- type InteractiveRequest
- type InteractiveResult
- type Invocation
- type InvocationOptions
- type LazyCommandLoader
- type LegacySpecProvider
- type OptionArity
- type OptionSpec
- type ParseConfig
- type ParseErrorNormalizer
- type ParseInvocationNormalizer
- type ParsedCommand
- func (m *ParsedCommand) Arg(name string) string
- func (m *ParsedCommand) Args(name string) []string
- func (m *ParsedCommand) Count(name string) int
- func (m *ParsedCommand) Has(name string) bool
- func (m *ParsedCommand) OptionOrder() []string
- func (m *ParsedCommand) Positionals() []string
- func (m *ParsedCommand) Value(name string) string
- func (m *ParsedCommand) Values(name string) []string
- type ParsedRunner
- type Registry
- type SpecProvider
- type VersionInfo
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DiagnosticMessage ¶
DiagnosticMessage extracts a stderr-oriented diagnostic string from err.
func Diagnosticf ¶
Diagnosticf builds an error whose message is intended for stderr output.
Wrap the returned error in an ExitError when you want the shell layer to surface the diagnostic while preserving an explicit exit status.
func ExitCode ¶
ExitCode extracts the exit status from err when err or one of its wrapped errors is an ExitError.
func Exitf ¶
func Exitf(inv *Invocation, code int, format string, args ...any) error
Exitf writes a formatted message to inv.Stderr and returns an ExitError carrying code.
func ReadAll ¶
ReadAll reads reader into memory while honoring ctx cancellation and inv.Limits.MaxFileBytes.
Command authors should prefer this over io.ReadAll so large inputs fail consistently with built-in commands and produce shell-facing diagnostics.
func ReadAllStdin ¶
func ReadAllStdin(ctx context.Context, inv *Invocation) ([]byte, error)
ReadAllStdin reads inv.Stdin with the same limit and diagnostic behavior as ReadAll. A nil stdin is treated as an empty reader.
func RenderCommandHelp ¶
func RenderCommandHelp(w io.Writer, spec *CommandSpec) error
RenderCommandHelp writes help text for spec using either the command-specific renderer or the shared default renderer.
func RenderCommandVersion ¶
func RenderCommandVersion(w io.Writer, spec *CommandSpec) error
RenderCommandVersion writes version output for spec using either the command-specific renderer or the shared default renderer.
func RenderDetailedVersion ¶
func RenderDetailedVersion(w io.Writer, info *VersionInfo) error
RenderDetailedVersion writes a multiline version report from info.
func RenderSimpleVersion ¶
RenderSimpleVersion writes a short "<name> (gbash)" version line.
func RunCommand ¶
func RunCommand(ctx context.Context, cmd Command, inv *Invocation) error
RunCommand executes cmd through the shared spec layer when it implements SpecProvider and ParsedRunner, otherwise it falls back to [Command.Run].
Types ¶
type ArgSpec ¶
type ArgSpec struct {
Name string
ValueName string
Help string
Required bool
Repeatable bool
Default []string
}
ArgSpec describes one positional argument in a CommandSpec.
type Command ¶
type Command interface {
Name() string
Run(ctx context.Context, inv *Invocation) error
}
Command is the runtime contract for a custom gbash command.
Implementations should use the capabilities exposed by Invocation instead of reaching out to host-global APIs directly.
func DefineCommand ¶
func DefineCommand(name string, fn CommandFunc) Command
DefineCommand wraps fn as a named Command.
type CommandFS ¶
type CommandFS struct {
// contains filtered or unexported fields
}
CommandFS exposes filesystem operations with gbash policy checks and file access tracing applied automatically.
func (*CommandFS) Link ¶
Link creates a hard link from oldName to newName after enforcing the relevant read and write policy checks.
func (*CommandFS) Lstat ¶
Lstat returns file info for name without following the final path element.
func (*CommandFS) MkdirAll ¶
MkdirAll creates name and any missing parents after enforcing mkdir policy.
func (*CommandFS) OpenFile ¶
func (fs *CommandFS) OpenFile(ctx context.Context, name string, flag int, perm stdfs.FileMode) (gbfs.File, error)
OpenFile opens name with the supplied flags after enforcing the necessary read and write policy checks.
func (*CommandFS) ReadDir ¶
ReadDir reads directory entries for name after enforcing readdir policy.
func (*CommandFS) ReadFile ¶
ReadFile reads the entire file contents of name while enforcing read policy and MaxFileBytes.
func (*CommandFS) Readlink ¶
Readlink reads the target of the symlink at name after enforcing readlink policy.
func (*CommandFS) Realpath ¶
Realpath resolves name to its canonical path after enforcing stat policy.
func (*CommandFS) Rename ¶
Rename renames oldName to newName after enforcing rename policy for both paths.
func (*CommandFS) Resolve ¶
Resolve resolves name against the invocation's virtual working directory.
type CommandFunc ¶
type CommandFunc func(ctx context.Context, inv *Invocation) error
CommandFunc adapts a function into a Command.
type CommandRegistry ¶
type CommandRegistry interface {
Register(cmd Command) error
RegisterLazy(name string, loader LazyCommandLoader) error
Lookup(name string) (Command, bool)
Names() []string
}
CommandRegistry is the interface expected by gbash runtimes and embedders that need command lookup and registration.
type CommandSpec ¶
type CommandSpec struct {
Name string
About string
Usage string
AfterHelp string
Options []OptionSpec
Args []ArgSpec
Parse ParseConfig
HelpRenderer func(io.Writer, CommandSpec) error
VersionRenderer func(io.Writer, CommandSpec) error
}
CommandSpec describes a command's help text, arguments, options, and parser behavior.
type ExecutionRequest ¶
type ExecutionRequest struct {
Name string
Interpreter string
PassthroughArgs []string
ScriptPath string
Script string
// Command runs an already-tokenized command argv without shell parsing.
// Script and Command are mutually exclusive.
Command []string
Args []string
StartupOptions []string
Env map[string]string
WorkDir string
Timeout time.Duration
ReplaceEnv bool
Interactive bool
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
ExecutionRequest describes a non-interactive nested shell or command execution launched through [Invocation.Exec].
type ExecutionResult ¶
type ExecutionResult struct {
ExitCode int
ShellExited bool
Stdout string
Stderr string
ControlStderr string
FinalEnv map[string]string
StartedAt time.Time
FinishedAt time.Time
Duration time.Duration
// Events contains structured execution events when tracing is enabled on the
// parent runtime. It is empty by default.
Events []trace.Event
StdoutTruncated bool
StderrTruncated bool
}
ExecutionResult reports the outcome of an ExecutionRequest.
type ExitError ¶
ExitError reports a command exit status.
Return one of these when a command needs to control its shell-visible exit code without panicking or mutating process-global state.
type InteractiveRequest ¶
type InteractiveRequest struct {
Name string
Args []string
StartupOptions []string
Env map[string]string
WorkDir string
ReplaceEnv bool
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
}
InteractiveRequest describes an interactive nested shell launched through [Invocation.Interact].
type InteractiveResult ¶
type InteractiveResult struct {
ExitCode int
}
InteractiveResult reports the outcome of an InteractiveRequest.
type Invocation ¶
type Invocation struct {
Args []string
Env map[string]string
Cwd string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
FS *CommandFS
Fetch FetchFunc
Exec func(context.Context, *ExecutionRequest) (*ExecutionResult, error)
Interact func(context.Context, *InteractiveRequest) (*InteractiveResult, error)
Limits policy.Limits
GetRegisteredCommands func() []string
// contains filtered or unexported fields
}
Invocation describes the capabilities available to a single command run.
Commands should treat it as the boundary of what they are allowed to do: filesystem access goes through [Invocation.FS], network access through [Invocation.Fetch], nested execution through [Invocation.Exec], and whole-input reads through ReadAll or ReadAllStdin.
func NewInvocation ¶
func NewInvocation(opts *InvocationOptions) *Invocation
NewInvocation constructs an Invocation from explicit capabilities.
func (*Invocation) TraceRecorder ¶
func (inv *Invocation) TraceRecorder() trace.Recorder
TraceRecorder returns the runtime-owned trace recorder when tracing is enabled.
Most command authors should not need this; prefer the higher-level capabilities on Invocation unless you are extending tracing itself.
type InvocationOptions ¶
type InvocationOptions struct {
Args []string
Env map[string]string
Cwd string
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
FileSystem gbfs.FileSystem
Network network.Client
Policy policy.Policy
Trace trace.Recorder
Exec func(context.Context, *ExecutionRequest) (*ExecutionResult, error)
Interact func(context.Context, *InteractiveRequest) (*InteractiveResult, error)
GetRegisteredCommands func() []string
}
InvocationOptions describes the capability set used to build an Invocation.
Most embedders will not construct these directly in production code; they are mainly useful for tests, integration helpers, and custom runtime wiring.
type LazyCommandLoader ¶
LazyCommandLoader constructs a command on first use.
type LegacySpecProvider ¶
type LegacySpecProvider interface {
LegacyReason() string
}
LegacySpecProvider marks commands that intentionally keep legacy parsing behavior instead of the shared spec layer.
type OptionArity ¶
type OptionArity int
OptionArity describes whether an option accepts a value.
const ( // OptionNoValue declares a flag that does not accept a value. OptionNoValue OptionArity = iota // OptionRequiredValue declares an option that must be followed by a value. OptionRequiredValue // OptionOptionalValue declares an option that may carry a value. OptionOptionalValue )
type OptionSpec ¶
type OptionSpec struct {
Name string
Short rune
ShortAliases []rune
Long string
Aliases []string
HelpAliases []string
Help string
ValueName string
Arity OptionArity
Repeatable bool
Hidden bool
Overrides []string
OptionalValueEqualsOnly bool
}
OptionSpec describes one named option in a CommandSpec.
type ParseConfig ¶
type ParseConfig struct {
InferLongOptions bool
GroupShortOptions bool
ContinueShortGroupValues bool
ShortOptionValueAttached bool
LongOptionValueEquals bool
StopAtFirstPositional bool
NegativeNumberPositional bool
AutoHelp bool
AutoVersion bool
}
ParseConfig controls which command-line forms ParseCommandSpec accepts.
type ParseErrorNormalizer ¶
type ParseErrorNormalizer interface {
NormalizeParseError(*Invocation, error) error
}
ParseErrorNormalizer lets a command rewrite parse failures from the shared parser into command-specific errors.
type ParseInvocationNormalizer ¶
type ParseInvocationNormalizer interface {
NormalizeInvocation(*Invocation) *Invocation
}
ParseInvocationNormalizer lets a command adjust the invocation used for parsing without affecting the execution invocation.
type ParsedCommand ¶
type ParsedCommand struct {
Spec CommandSpec
// contains filtered or unexported fields
}
ParsedCommand contains the parsed values for one CommandSpec invocation.
func ParseCommandSpec ¶
func ParseCommandSpec(inv *Invocation, spec *CommandSpec) (*ParsedCommand, string, error)
ParseCommandSpec parses inv.Args against spec and returns the parsed matches.
The returned action is "help" or "version" when automatic help/version handling should take over.
func (*ParsedCommand) Arg ¶
func (m *ParsedCommand) Arg(name string) string
Arg returns the first parsed value for positional argument name.
func (*ParsedCommand) Args ¶
func (m *ParsedCommand) Args(name string) []string
Args returns all parsed values for positional argument name.
func (*ParsedCommand) Count ¶
func (m *ParsedCommand) Count(name string) int
Count reports how many times option name was seen.
func (*ParsedCommand) Has ¶
func (m *ParsedCommand) Has(name string) bool
Has reports whether option name was seen.
func (*ParsedCommand) OptionOrder ¶
func (m *ParsedCommand) OptionOrder() []string
func (*ParsedCommand) Positionals ¶
func (m *ParsedCommand) Positionals() []string
Positionals returns the raw positional arguments in parse order.
func (*ParsedCommand) Value ¶
func (m *ParsedCommand) Value(name string) string
Value returns the last parsed value for option name.
func (*ParsedCommand) Values ¶
func (m *ParsedCommand) Values(name string) []string
Values returns all parsed values for option name.
type ParsedRunner ¶
type ParsedRunner interface {
RunParsed(context.Context, *Invocation, *ParsedCommand) error
}
ParsedRunner executes a command after ParseCommandSpec has matched its arguments to a CommandSpec.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the default in-memory CommandRegistry implementation.
func NewRegistry ¶
NewRegistry constructs a registry and eagerly registers cmds.
func (*Registry) Register ¶
Register stores cmd by name, replacing any existing command with the same name.
func (*Registry) RegisterLazy ¶
func (r *Registry) RegisterLazy(name string, loader LazyCommandLoader) error
RegisterLazy registers a name that will be materialized by loader on first execution.
type SpecProvider ¶
type SpecProvider interface {
Spec() CommandSpec
}
SpecProvider exposes declarative command metadata for shared parsing, help, and version rendering.
type VersionInfo ¶
VersionInfo contains the metadata rendered by RenderDetailedVersion.