pexec

package
v0.4.188 Latest Latest
Warning

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

Go to latest
Published: Jun 24, 2024 License: ISC Imports: 16 Imported by: 0

Documentation

Overview

Package pexec provides streaming, context-cancelable system command execution

Index

Constants

View Source
const (
	// [ExitErrorData.ExitErrorString] should include standard error output
	ExitErrorIncludeStderr = true
	// status code 1, which in POSIX means a general error
	StatusCode1 = 1
)
View Source
const (
	// the status code of a process terminated by signal
	TerminatedBySignal = -1
)

Variables

View Source
var (
	// [ExecStreamFull] env: use the environment of the parent process
	DefaulEnv []string
	// [ExecStreamFull] startCallback: no startCallback
	NoStartCallback StartCallback
	// [ExecStreamFull] stdin: no stdin
	NoStdin io.Reader
	// [ExecStreamFull] stdout: no stdout
	NoStdout io.Writer
	// [ExecStreamFull] stderr: no stderr
	NoStderr io.Writer
	// [ExecStreamFull] extraFiles: no extraFiles
	NoExtraFiles []*os.File
)
View Source
var ErrArgsListEmpty = errors.New("args list empty")

ErrArgsListEmpty is returned when args doe not contain a command

View Source
var ExecBlockingClosedStdin = []byte{}

ExecBlocking the system command receives a closed standard input

View Source
var ExecBlockingEmptyStdin = []byte{}

ExecBlocking the system command receives an open but empty standard input

View Source
var NoExecBlockingStdin []byte

ExecBlocking the system command receives a closed standard input

Functions

func ExecBlocking added in v0.4.87

func ExecBlocking(stdin []byte, wantStdout Stdouts, wantStderr Stderrs, ctx context.Context, args ...string) (stdout, stderr *bytes.Buffer, err error)

ExecBlocking provides a simple way to quietly execute a system command

  • blocking, control over standard i/o, ability to cancel
  • stdin: a byte sequence used as input to the system command
  • stdin ExecBlockingClosedStdin nil: the command receives a closed standard input
  • stdin ExecBlockingEmptyStdin: the system command receives an open but empty standard input
  • wantStdout WantStdout: the command’s standard poutput is returned in stdout
  • wantStdout NoExecBlockingStdout: the command’s standard output is discarded
  • wantStderr WantStderr: the command’s standard error output is returned in stderr
  • wantStderr StderrIsError: if the command outputs to standard error, the output is returned as an error
  • wantStderr NoExecBlockingStderr: the command’s standard error output is discarded. standard error output may still be provided in err
  • ctx: termianes the commad usinng SIGKILL on context cancel. Cannot be nil
  • args: args[0] is non-empty command. args[1…] holds command-line arguments

func ExecStream

func ExecStream(
	stdin io.Reader, stdout io.WriteCloser, stderr io.WriteCloser,
	ctx context.Context, args ...string,
) (statusCode int, isCancel bool, err error)

ExecStream executes a system command using the exec.Cmd type with flexible streaming

  • blocking, flexible streaming, ability to cancel
  • — like ExecStreamFull but with fewer arguments
  • — single-statement version of exec.Cmd with flexible streaming
  • args: the command and its arguments. args[0] empty is error. If args[0] does not contain path, the command is resolved using the parent process’ env.PATH
  • stdin: an io.Reader producing the new process’ standard input.
  • — stdin be os.Stdin if the parent process does not use its standard input
  • — stdin can be [pio.EofReader] which is a standard input that is open but does not provide any input
  • — If stdin is nil, stdin is /dev/null meaning the sub-process’ standard input is closed which for some commands cause immediate process termination
  • —ExecStreamFull does not close a non-nil stdin but its use has ceased upon return
  • stdout: an io.Writer receiving the process’ standard output
  • — stdout can be os.Stdout causing the sub-process’ output to appear on the terminal
  • — If stdout is nil, the sub-process’ output is discarded
  • — ExecStreamFull does not close stdout but its use has ceased upon return
  • stderr: an io.Writer receiving the process’ standard error
  • — stderr can be os.Stderr causing the sub-process’ output to appear on the terminal
  • — If stderr is nil, the new process’ error output is discarded.
  • ctx: a context that can be used to terminate the process using SIGKILL. ctx nil is panic
  • statusCode: the process’ exit code:
  • — 0 on successful process termination
  • TerminatedBySignal -1 on process terminated by signal such as ^C SIGINT or SIGTERM
  • — otherwise, a command-specific exit value
  • isCancel: true if context cancel terminated the process with SIGKILL or a stream-copying error occurred
  • err: any occurring error
  • upon return from ExecStream there are 5 outcomes:
  • — successful exit: statusCode == 0, err == nil
  • — failure exit: statusCode != 0, isCancel == false. statusCode is the command-specific value provided by sub-process exit. err is the value returned by exec.Cmd.Wait upon process exit. If statusCode is pexec.TerminatedBySignal -1, the process was terminated by signal. The signal value can be obtained from err using pexec.ExitError
  • — context cancel: isCancel == true, err == nil. statusCode is pexec.TerminatedBySignal -1
  • — stream copying error: isCancel == true, err != nil statusCode is pexec.TerminatedBySignal -1
  • — other error condition: err != nil, statusCode == 0
  • for stdout and stderr pio has usable types:
  • — pio.NewWriteCloserToString
  • — pio.NewWriteCloserToChan
  • — pio.NewWriteCloserToChanLine
  • — pio.NewReadWriteCloserSlice
  • parl.EchoModerator can be used with ExecStream:
  • — if system commands slow down or lock-up, too many (dozens) invoking goroutines may cause increased memory consumption, thrashing or exhaust of file handles, ie. an uncontrollable host state
  • — EchoModerator notifies of slow or hung commands and limits parallelism

func ExecStreamFull added in v0.4.38

func ExecStreamFull(
	stdin io.Reader, stdout io.Writer, stderr io.Writer,
	env []string, ctx context.Context, startCallback StartCallback, extraFiles []*os.File,
	args ...string,
) (statusCode int, isCancel bool, err error)

ExecStreamFull executes a system command using the exec.Cmd type and flexible streaming

  • ExecStreamFull makes streaming exec.Cmd easy to use
  • args: the command and its arguments. args[0] empty is error. If args[0] does not contain path, the command is resolved using the parent process’ env.PATH
  • stdin: an io.Reader producing the new process’ standard input.
  • — stdin be os.Stdin if the parent process does not use its standard input
  • — stdin can be [pio.EofReader] which is a standard input that is open but does not provide any input
  • — If stdin is nil, stdin is /dev/null meaning the sub-process’ standard input is closed which for some commands cause immediate process termination
  • —ExecStreamFull does not close a non-nil stdin but its use has ceased upon return
  • stdout: an io.Writer receiving the process’ standard output
  • — stdout can be os.Stdout causing the sub-process’ output to appear on the terminal
  • — If stdout is nil, the sub-process’ output is discarded
  • — ExecStreamFull does not close stdout but its use has ceased upon return
  • stderr: an io.Writer receiving the process’ standard error
  • — stderr can be os.Stderr causing the sub-process’ output to appear on the terminal
  • — If stderr is nil, the new process’ error output is discarded. However, on process error exit, stderr output is available in the returned error value
  • — ExecStreamFull does not close stderr but its use has ceased upon return
  • env: an environment for the process. If env is nil, the new process uses the current process’ environment
  • ctx: a context that can be used to terminate the process using SIGKILL. ctx nil is panic
  • startCallback: an optional callback invoked immediately after process start exec.Cmd.Start
  • extraFiles: an optional list of streams for the process’ file descriptors 3…
  • statusCode: the process’ exit code:
  • — 0 on successful process termination
  • TerminatedBySignal -1 on process terminated by signal such as ^C SIGINT or SIGTERM
  • — otherwise, a command-specific exit value
  • isCancel: true if context cancel terminated the process with SIGKILL or a stream-copying error occurred
  • err: any occurring error
  • upon return from ExecStreamFull there are 5 outcomes:
  • — successful exit: statusCode == 0, err == nil
  • — failure exit: statusCode != 0, isCancel == false. statusCode is the command-specific value provided by sub-process exit. err is the value returned by exec.Cmd.Wait upon process exit. If statusCode is pexec.TerminatedBySignal -1, the process was terminated by signal. The signal value can be obtained from err using pexec.ExitError
  • — context cancel: isCancel == true, err == nil. statusCode is pexec.TerminatedBySignal -1
  • — stream copying error: isCancel == true, err != nil statusCode is pexec.TerminatedBySignal -1
  • — other error condition: err != nil, statusCode == 0
  • ExecStreamFull blocks during command execution until:
  • — the started sub-process terminates
  • — ctx context is canceled causing the process to be terminated by signal unix.SIGKILL
  • — the process’ context is canceled due to an error ocurring in stream-copying threads
  • ExecStreamFull may fail prior to exec.Cmd.Wait command-execution:
  • — args does not contain a valid command
  • — an error occured during stream-copying thread creation
  • exec.Cmd.Start returned an error occuring prior to process start
  • Up to 3 stream-copying threads are used to copy data when stdin, stdout or stderr are non-nil and not os.Stdin, os.Stdout or os.Stderr respectively
  • for stdout and stderr, the [pio] package has usable types:
  • — [pio.NewWriteCloserToString]
  • — [pio.NewWriteCloserToChan]
  • — [pio.NewWriteCloserToChanLine]
  • — [pio.NewReadWriteCloserSlice]
  • parl.EchoModerator can be used with ExecStreamFull:
  • — if system commands slow down or lock-up, too many (dozens) invoking goroutines may cause increased memory consumption, thrashing or exhaust of file handles, ie. an uncontrollable host state
  • — EchoModerator notifies of slow or hung commands and limits parallelism

func ExitError added in v0.4.40

func ExitError(err error) (hasStatusCode bool, statusCode int, signal unix.Signal, stderr []byte)

ExitError returns information on why the exec.Cmd.Start process terminated

  • if hasStatusCode is true, the process terminated with a status code
  • if hasStatusCode is false, exec.Cmd.Start failed prior to launch
  • if StatusCode has value -1 or pexec.TerminatedBySignal, the process terminated due to the signal signal. Common signals are:
  • — unix.SIGINT from ^C
  • — unix.SIGKILL from context termination
  • — unix.SIGTERM from operating-system process-termination

func NewCmdContainer added in v0.4.179

func NewCmdContainer() (cmd *CmdContainer, startCallback StartCallback)

NewCmdContainer returns a thread-safe container for the exec.Cmd value

Types

type CmdContainer added in v0.4.179

type CmdContainer struct {
	// contains filtered or unexported fields
}

CmdContainer is a thread-safe container for the exec.Cmd value

func (*CmdContainer) Ch added in v0.4.179

func (c *CmdContainer) Ch() (ch parl.AwaitableCh)

Ch awaits process start when the Cmd value is available

func (*CmdContainer) Cmd added in v0.4.179

func (c *CmdContainer) Cmd() (execCmd *exec.Cmd)

Cmd returns the exec.Cmd value, available after process start

func (*CmdContainer) Err added in v0.4.179

func (c *CmdContainer) Err() (err error)

Cmd returns any error from exec.Cmd.Start

type ExitErrorData added in v0.4.106

type ExitErrorData struct {
	// the original error
	Err error
	// Err interpreted as ExitError, possibly nil
	ExitErr *exec.ExitError
	// status code in ExitError, possibly 0
	StatusCode int
	// signal in ExitError, possibly 0
	Signal unix.Signal
	// stderr in ExitError or from argument, possibly nil
	Stderr []byte
}

ExitErrorData provides additional detail on pexec.ExitError values

func NewExitErrorData added in v0.4.106

func NewExitErrorData(err error, stderr ...[]byte) (exitErrorData *ExitErrorData)

NewExitErrorData returns parse-once data on a possible ExitError

  • if ExitErr field is nil or IsExitError method returns false, err does not contain an ExitError
  • the returned value is an error implementation

func (*ExitErrorData) AddStderr added in v0.4.111

func (e *ExitErrorData) AddStderr(err error) (err2 error)

AddStderr adds standard error output at the end of the error message for err. Also ensures stack trace.

  • ExitError has standard error if the Output method was used
  • NewExitErrorData can also have been provided stderr

func (*ExitErrorData) Error added in v0.4.106

func (e *ExitErrorData) Error() (exitErrorMessage string)

the Error method returns the message from any ExitError, otherwise empty string

  • Error also makes ExitErrorData implementing the error interface

func (*ExitErrorData) ExitErrorString added in v0.4.106

func (e *ExitErrorData) ExitErrorString(includeStderr ...bool) (errS string)

ExitErrorString returns the ExitError error message and data from Err and stderr, not an error value

  • for non-signal: “status code: 1 ‘read error’”
  • for signal: “signal: "abort trap" ‘signal: abort trap’”
  • the error message for err: “message: ‘failure’”
  • stderr if non-empty from ExitErr or stderr argument and includeStderr is ExitErrorIncludeStderr:
  • “stderr: ‘I/O error’”
  • returned value is never empty

func (*ExitErrorData) IsExitError added in v0.4.106

func (e *ExitErrorData) IsExitError() (isExitError bool)

IsExitError returns true if an pexec.ExitError is present

  • false if Err was nil or some other type of error

func (*ExitErrorData) IsSignalKill added in v0.4.106

func (e *ExitErrorData) IsSignalKill() (isSignalKill bool)

IsSignalKill returns true if the err error chain contains an ExitError with signal kill

  • signal kill is the response to a command’s context being canceled. This should be checked together with context.Context.Err
  • SIGKILL can also be sent to the process by the operating system trying to reclaim memory or by other processes

func (*ExitErrorData) IsStatusCode1 added in v0.4.106

func (e *ExitErrorData) IsStatusCode1() (is1 bool)

IsStatusCode1 returns if the err error chain contains an ExitError that indicates status code 1

  • Status code 1 indicates an unspecified failure of a process
  • Success has no ExitError and status code 0
  • Terminated by signal is status code -1
  • Input syntax error is status code 2

type StartCallback added in v0.4.104

type StartCallback interface {
	// StartResult is invoked by [ExecStreamFull] unless it fails
	// prior to Start
	//	- StartResult receives the command-description and
	//		process data along with any error occurring during Start
	//	- if err is nil, the command sub-process did start
	//	- StartResult must be thread-safe
	StartResult(execCmd *exec.Cmd, err error)
}

ExecStreamFull startCallback: the signature of startCallback

type Stderrs added in v0.4.87

type Stderrs uint8

Stderrs are the possible values for ExecBlocking stderr

  • NoExecBlockingStderr WantStderr StderrIsError
const (
	// [ExecBlocking] system command’s standard error is discarded
	NoExecBlockingStderr Stderrs = iota + 1
	// [ExecBlocking] system command’s standard error is captured
	WantStderr
	// [ExecBlocking] any system command output to standard error is returned as an error
	StderrIsError
)

type Stdouts added in v0.4.87

type Stdouts bool

Stdouts are the possible values for ExecBlocking stdout

  • NoExecBlockingStdout WantStdout
const (
	// [ExecBlocking] system command’s standard output is discarded
	NoExecBlockingStdout Stdouts = false
	// [ExecBlocking] system command’s standard output is be captured
	WantStdout Stdouts = true
)

Jump to

Keyboard shortcuts

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