runner

package
v0.175.2 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package runner is spec/plans/coverage-to-100/README.md task-8's command runner: the one seam every caller uses to start an external program, built on internal/process rather than beside it (rule:reuse-existing-sneat-code). Production code depends on the Runner interface, never on os/exec directly, so a unit test substitutes runnertest's scriptable fake instead of starting a real process.

Runner has four operations, exactly as the plan defines them, plus two gaps the plan's own text names and invites filling when a real site needs them (see task-8's "If the runner cannot express something a site needs" note): RunWithInput and RunOpts.

  • Run captures stdout, stderr and the exit status -- most git and gh calls.
  • RunWithInput is Run with the child's stdin supplied by the caller, for the rare site that must pass a request body a remote or local child reads from stdin instead of argv (added for remotessh's SSH boundary).
  • RunOpts is Run with a RunOptions value -- a per-call environment and/or a WaitDelay -- for the several sites that build a filtered or augmented child environment (internal/console.Env()/CommandEnv(), a GOWORK=off override, an extra credential) or that must bound how long a child's inherited pipes are allowed to stay open after the child itself has exited (os/exec.Cmd.WaitDelay). RunOptions carries an optional Stdin too, so a caller needing both input and a custom environment does not have to choose between RunWithInput and RunOpts.
  • Start returns a Handle with Wait and Signal, for a long-running child wb supervises.
  • Detach starts a process that outlives wb -- daemon launch, browser.go, lifecycle hooks.
  • Interactive passes stdio through -- `wb run -- …`, tmux, agent harnesses.

The real implementation (Real) carries task-24's runtime guard: when WB_RUNNER_STRICT_UNIT_TIER=1, it refuses to start a process while testing.Testing() is true, unless the binary is built with the e2e tag, the calling test named itself on runnertest's allow/pending list by calling AllowRealProcess, or the process is the Go helper-process re-exec of the test binary itself. See guard.go.

Index

Constants

This section is empty.

Variables

View Source
var ErrOutputTooLarge = errors.New("runner: child output passed its limit")

ErrOutputTooLarge is what RunOpts returns when a child's standard output passed RunOptions.StdoutLimit.

View Source
var ErrRealProcessBlocked = errors.New("runner: refusing to start a real process during a unit test; call runnertest.AllowRealProcess(t) if this file is on the unit-tier pending or allow list")

ErrRealProcessBlocked is returned by every Runner operation when task-24's runtime guard refuses to start a real process during a unit test.

Functions

This section is empty.

Types

type Handle

type Handle interface {
	// Wait blocks until the process exits and returns its captured output.
	Wait() (Result, error)
	// Signal delivers signal to the process. Once the process has already
	// been waited on, it reports an error (never a panic) rather than
	// signalling an unrelated, possibly-reused pid.
	Signal(signal os.Signal) error
	// Pid reports the started process's process id.
	Pid() int
}

Handle is a process started by Start: callers wait for it or signal it without depending on os/exec directly.

type Real

type Real struct{}

Real is the production Runner, built on internal/process. Every operation checks guardRealProcess first.

func New

func New() Real

New returns the production Runner.

func (Real) Detach

func (Real) Detach(dir, name string, args ...string) (int, error)

Detach starts name with args in dir as a process that outlives the caller, and reports its process id.

func (Real) Interactive

func (Real) Interactive(ctx context.Context, dir, name string, args ...string) error

Interactive starts name with args in dir with stdio passed through to the caller's own, and waits for it to exit.

func (Real) Run

func (Real) Run(ctx context.Context, dir, name string, args ...string) (Result, error)

Run starts name with args in dir, waits for it to exit, and returns its captured stdout, stderr and exit status.

Run is documented as the operation "most git and gh calls" use, so its child always carries console.Env(): the non-interactive settings every direct exec.Command git/gh call site in this repository has set by hand (nonInteractiveChildEnv, GIT_SSH_COMMAND), so a consumer that migrates onto Run keeps the same "never hangs on a prompt" guarantee without reproducing that env-building itself.

func (Real) RunOpts

func (Real) RunOpts(ctx context.Context, dir string, opts RunOptions, name string, args ...string) (Result, error)

RunOpts is Run with a RunOptions value: a per-call environment, stdin, and/or WaitDelay.

func (Real) RunWithInput

func (Real) RunWithInput(ctx context.Context, dir string, input []byte, name string, args ...string) (Result, error)

RunWithInput writes input to the child's stdin and inherits the parent environment. Use RunOpts to supply both input and a custom environment.

func (Real) Start

func (Real) Start(ctx context.Context, dir, name string, args ...string) (Handle, error)

Start begins name with args in dir and returns a Handle without waiting for it to exit.

type Result

type Result struct {
	Stdout string
	Stderr string
	// CombinedOutput is populated only when RunOptions.CaptureCombined is set.
	CombinedOutput string
	ExitCode       int
}

Result is one Run or Start/Wait call's captured output.

type RunOptions

type RunOptions struct {
	// CaptureCombined sends stdout and stderr to one pipe and preserves their
	// observed order, as exec.Cmd.CombinedOutput does. When set, the capture
	// is returned in Result.CombinedOutput instead of Stdout and Stderr.
	CaptureCombined bool
	// Env overrides the child's environment. Nil inherits the calling
	// process's own environment, matching os/exec.Cmd's own default when
	// Env is left nil. RunWithInput does the same; Real.Run supplies
	// console.Env() instead.
	Env []string
	// Stdin is written to the child's stdin before its output is read, like
	// RunWithInput's input. Nil/empty gives the child no stdin (the same as
	// Run).
	Stdin []byte
	// WaitDelay bounds how long RunOpts waits for the child's I/O pipes to
	// drain after the process itself has exited (os/exec.Cmd.WaitDelay).
	// Zero uses the underlying implementation's own default -- Real inherits
	// internal/process's, not zero/unbounded -- so a caller that genuinely
	// needs a specific bound (a package-manager launcher that hands off to a
	// grandchild and exits early) sets one explicitly rather than relying on
	// whatever internal/process happens to default to today.
	WaitDelay time.Duration
	// StdoutLimit, when positive, caps the standard output RunOpts buffers:
	// the first write that would pass it is refused, nothing beyond the cap
	// is ever held, the child is stopped by its closed pipe or by ctx, and
	// RunOpts returns ErrOutputTooLarge with Result.Stdout holding only what
	// fitted. It does not apply with CaptureCombined.
	StdoutLimit int
	// DiscardStderr sends the child's standard error to the null device
	// instead of buffering it: Result.Stderr stays empty. For a caller that
	// runs a child it does not trust and must neither hold nor surface what
	// that child prints there.
	DiscardStderr bool
}

RunOptions customizes a RunOpts call beyond dir/argv.

type Runner

type Runner interface {
	// Run starts name with args in dir, waits for it to exit, and returns
	// its captured stdout, stderr and exit status.
	Run(ctx context.Context, dir, name string, args ...string) (Result, error)
	// RunWithInput is Run with input written to the child's stdin before its
	// output is read. See the package doc's note on why this exists
	// alongside Run rather than folding input into it.
	RunWithInput(ctx context.Context, dir string, input []byte, name string, args ...string) (Result, error)
	// RunOpts is Run with a RunOptions value: a per-call environment,
	// stdin, and/or WaitDelay. See the package doc's note on RunOpts.
	RunOpts(ctx context.Context, dir string, opts RunOptions, name string, args ...string) (Result, error)
	// Start begins name with args in dir and returns a Handle without
	// waiting for it to exit.
	Start(ctx context.Context, dir, name string, args ...string) (Handle, error)
	// Detach starts name with args in dir as a process that outlives the
	// caller, and reports its process id.
	Detach(dir, name string, args ...string) (pid int, err error)
	// Interactive starts name with args in dir with stdio passed through to
	// the caller's own, and waits for it to exit.
	Interactive(ctx context.Context, dir, name string, args ...string) error
}

Runner is task-8's command-runner port.

Directories

Path Synopsis
Package runnertest is task-8's test double for internal/runner.Runner: a scriptable Fake that matches an expected argv and returns canned output or an injected error, plus AllowRealProcess for the small number of tests that must start a real process.
Package runnertest is task-8's test double for internal/runner.Runner: a scriptable Fake that matches an expected argv and returns canned output or an injected error, plus AllowRealProcess for the small number of tests that must start a real process.

Jump to

Keyboard shortcuts

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