Help us shape the future of Go! Take the 2026 Go Developer Survey

exec

package
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package exec is the single gateway through which flow invokes external processes. No other package may import os/exec: routing everything through Runner is what makes the rest of the tool testable without a real git repository, a real herdr server, or a real Kubernetes cluster.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Command

func Command(opts Opts) string

Command renders an invocation the way a shell would accept it, for display in --dry-run output and verbose logs.

func ShellJoin

func ShellJoin(args []string) string

ShellJoin renders an argv as a copy-pasteable shell command line.

func ShellQuote

func ShellQuote(s string) string

ShellQuote quotes a single argument for a POSIX shell.

Types

type Call

type Call struct {
	Name string
	Args []string
	Dir  string
}

Call is one recorded invocation.

func (Call) String

func (c Call) String() string

String renders the call as a shell command line, which is what argv assertions compare against.

type DryRun

type DryRun struct {
	Inner    Runner
	IsRead   ReadOnly
	Announce func(cmdline string)
}

DryRun wraps a Runner so that mutating commands are announced instead of executed. Read-only commands pass straight through, because a dry run that cannot inspect the repository cannot describe what it would do.

func (*DryRun) LookPath

func (d *DryRun) LookPath(name string) (string, error)

LookPath is read-only and always delegates.

func (*DryRun) Run

func (d *DryRun) Run(ctx context.Context, opts Opts) (Result, error)

Run executes read-only commands and announces mutating ones.

func (*DryRun) StartDetached

func (d *DryRun) StartDetached(_ context.Context, opts Opts) error

StartDetached announces the spawn without performing it.

type ExitError

type ExitError struct {
	Cmd    string
	Result Result
}

ExitError reports a command that ran but returned a non-zero status.

func (*ExitError) Error

func (e *ExitError) Error() string

type Fake

type Fake struct {

	// Responses maps a command-line prefix to its canned result.
	Responses map[string]Response
	// Missing lists binaries that LookPath should fail for.
	Missing map[string]bool
	// Default is returned when no prefix matches.
	Default Response

	Calls    []Call
	Detached []Call
	// contains filtered or unexported fields
}

Fake is a Runner that replays canned responses and records every call.

A response prefix is matched against the plain, space-joined command line ("git log --format=%h %s HEAD") as well as the shell-quoted rendering, so tests can stub a command by writing it the way it reads. The longest matching prefix wins, which lets a test stub "git rev-parse --git-common-dir" precisely while leaving a broad "git" entry as a catch-all.

func NewFake

func NewFake() *Fake

NewFake returns a Fake with empty response tables.

func (*Fake) CommandLines

func (f *Fake) CommandLines() []string

CommandLines returns every recorded call as a shell command line.

func (*Fake) LookPath

func (f *Fake) LookPath(name string) (string, error)

LookPath succeeds for every binary not listed in Missing.

func (*Fake) Ran

func (f *Fake) Ran(prefix string) bool

Ran reports whether any recorded call starts with prefix.

func (*Fake) Respond

func (f *Fake) Respond(prefix, stdout string) *Fake

Respond registers a canned stdout for commands matching prefix.

func (*Fake) RespondWith

func (f *Fake) RespondWith(prefix string, r Response) *Fake

RespondWith registers a full canned response for commands matching prefix.

func (*Fake) Run

func (f *Fake) Run(ctx context.Context, opts Opts) (Result, error)

Run records the call and returns its canned response.

func (*Fake) StartDetached

func (f *Fake) StartDetached(_ context.Context, opts Opts) error

StartDetached records the call without running anything.

type Logger

type Logger interface {
	Debug(msg any, keyvals ...any)
	Info(msg any, keyvals ...any)
}

Logger receives a line per command when verbose logging is enabled. The signature matches charmbracelet/log, whose message parameter is an any.

type Opts

type Opts struct {
	Name   string
	Args   []string
	Dir    string
	Env    []string // appended to os.Environ()
	Stdin  io.Reader
	Stream bool // when true, pipe stdout/stderr straight to the terminal
	// KeepStderr also captures a streamed command's stderr into Result, so
	// its failure can be inspected. It costs the command a terminal on
	// stderr, which is why it is not the default.
	KeepStderr bool

	// Secret suppresses verbose logging of this command's output. Set it for
	// anything that prints a credential (the keychain lookup, for example) so
	// that -vv can never leak a token into the log.
	Secret bool
}

Opts describes a single external command invocation.

type ReadOnly

type ReadOnly func(Opts) bool

ReadOnly reports whether an invocation only observes the world. Under --dry-run these still run; everything else is printed and skipped.

type Real

type Real struct {
	Log Logger
	// DebugOutput mirrors -vv: log the full stdout/stderr of every command.
	DebugOutput bool
	// Stdout and Stderr receive streamed output; nil means the process's own.
	Stdout io.Writer
	Stderr io.Writer
}

Real runs commands with os/exec. It is the only place in the tree that may import os/exec.

func (*Real) LookPath

func (r *Real) LookPath(name string) (string, error)

LookPath reports the absolute path of name on PATH.

func (*Real) Run

func (r *Real) Run(ctx context.Context, opts Opts) (Result, error)

Run executes opts to completion.

func (*Real) StartDetached

func (r *Real) StartDetached(_ context.Context, opts Opts) error

StartDetached spawns a process in its own session and does not wait for it.

type Response

type Response struct {
	Stdout   string
	Stderr   string
	ExitCode int
	Err      error
}

Response is a canned reply for a matched command.

type Result

type Result struct {
	Stdout   string
	Stderr   string
	ExitCode int

	// Skipped reports that --dry-run announced this command instead of
	// running it, so the zero Stdout means "nothing ran" rather than "the
	// command produced no output". Any caller that parses Stdout must check
	// it; a caller that needs real output under --dry-run is asking a
	// read-only question and belongs on the unwrapped runner (App.ReadGit,
	// App.ReadHelm, App.ReadHerdr).
	Skipped bool
}

Result is the outcome of a completed external command.

type Runner

type Runner interface {
	// Run executes a command to completion.
	Run(ctx context.Context, opts Opts) (Result, error)

	// StartDetached spawns a command in its own session and returns without
	// waiting for it. Used for the editor, which must outlive flow.
	StartDetached(ctx context.Context, opts Opts) error

	// LookPath reports the absolute path of an executable on PATH.
	LookPath(name string) (string, error)
}

Runner runs external commands.

Jump to

Keyboard shortcuts

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