commands

package
v0.0.22 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 20, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func DiagnosticMessage

func DiagnosticMessage(err error) (string, bool)

DiagnosticMessage extracts a stderr-oriented diagnostic string from err.

func Diagnosticf

func Diagnosticf(format string, args ...any) error

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

func ExitCode(err error) (int, bool)

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

func ReadAll(ctx context.Context, inv *Invocation, reader io.Reader) ([]byte, error)

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

func RenderSimpleVersion(w io.Writer, name string) error

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

func (fs *CommandFS) Chdir(name string) error

Chdir updates the invocation's virtual working directory.

func (*CommandFS) Chmod

func (fs *CommandFS) Chmod(ctx context.Context, name string, mode stdfs.FileMode) error

Chmod changes file mode bits after enforcing write policy.

func (*CommandFS) Chown

func (fs *CommandFS) Chown(ctx context.Context, name string, uid, gid uint32, follow bool) error

Chown changes file ownership after enforcing write policy.

func (*CommandFS) Chtimes

func (fs *CommandFS) Chtimes(ctx context.Context, name string, atime, mtime time.Time) error

Chtimes updates file timestamps after enforcing write policy.

func (*CommandFS) Getwd

func (fs *CommandFS) Getwd() string

Getwd returns the invocation's virtual working directory.

func (fs *CommandFS) Link(ctx context.Context, oldName, newName string) error

Link creates a hard link from oldName to newName after enforcing the relevant read and write policy checks.

func (*CommandFS) Lstat

func (fs *CommandFS) Lstat(ctx context.Context, name string) (stdfs.FileInfo, error)

Lstat returns file info for name without following the final path element.

func (*CommandFS) MkdirAll

func (fs *CommandFS) MkdirAll(ctx context.Context, name string, perm stdfs.FileMode) error

MkdirAll creates name and any missing parents after enforcing mkdir policy.

func (*CommandFS) Open

func (fs *CommandFS) Open(ctx context.Context, name string) (gbfs.File, error)

Open opens name for reading after enforcing read 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

func (fs *CommandFS) ReadDir(ctx context.Context, name string) ([]stdfs.DirEntry, error)

ReadDir reads directory entries for name after enforcing readdir policy.

func (*CommandFS) ReadFile

func (fs *CommandFS) ReadFile(ctx context.Context, name string) ([]byte, error)

ReadFile reads the entire file contents of name while enforcing read policy and MaxFileBytes.

func (fs *CommandFS) Readlink(ctx context.Context, name string) (string, error)

Readlink reads the target of the symlink at name after enforcing readlink policy.

func (*CommandFS) Realpath

func (fs *CommandFS) Realpath(ctx context.Context, name string) (string, error)

Realpath resolves name to its canonical path after enforcing stat policy.

func (*CommandFS) Remove

func (fs *CommandFS) Remove(ctx context.Context, name string, recursive bool) error

Remove removes name after enforcing remove policy.

func (*CommandFS) Rename

func (fs *CommandFS) Rename(ctx context.Context, oldName, newName string) error

Rename renames oldName to newName after enforcing rename policy for both paths.

func (*CommandFS) Resolve

func (fs *CommandFS) Resolve(name string) string

Resolve resolves name against the invocation's virtual working directory.

func (*CommandFS) Stat

func (fs *CommandFS) Stat(ctx context.Context, name string) (stdfs.FileInfo, error)

Stat returns file info for name after enforcing stat policy.

func (fs *CommandFS) Symlink(ctx context.Context, target, linkName string) error

Symlink creates linkName pointing at target after enforcing write policy for the new link path.

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

type ExitError struct {
	Code int
	Err  error
}

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.

func (*ExitError) Error

func (e *ExitError) Error() string

func (*ExitError) Unwrap

func (e *ExitError) Unwrap() error

type FetchFunc

type FetchFunc func(context.Context, *network.Request) (*network.Response, error)

FetchFunc performs a network request through the runtime-owned network capability.

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

type LazyCommandLoader func() (Command, error)

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

func NewRegistry(cmds ...Command) *Registry

NewRegistry constructs a registry and eagerly registers cmds.

func (*Registry) Lookup

func (r *Registry) Lookup(name string) (Command, bool)

Lookup returns the registered command for name.

func (*Registry) Names

func (r *Registry) Names() []string

Names returns the sorted list of registered command names.

func (*Registry) Register

func (r *Registry) Register(cmd Command) error

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

type VersionInfo struct {
	Name    string
	Version string
	Commit  string
	Date    string
	BuiltBy string
}

VersionInfo contains the metadata rendered by RenderDetailedVersion.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL