exec

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 15, 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

	// 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