run

package module
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Feb 21, 2024 License: MPL-2.0 Imports: 7 Imported by: 4

README

= Run

image:https://pkg.go.dev/badge/github.com/DavidGamba/dgtools/run.svg[Go Reference, link="https://pkg.go.dev/github.com/DavidGamba/dgtools/run"]

Provides a wrapper around os/exec with method chaining for modifying behaviour.

Import: `github.com/DavidGamba/dgtools/run`

== Examples

.Run command and only return Stdout
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").STDOutOutput()
----

.Run command and combine Stderr and Stdout
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").CombinedOutput()
----

.Run command and change Working Directory
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").Dir("..").CombinedOutput()
----

.Run command and set environment variables
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").CombinedOutput()
----

.Run command and log the command that is going to be executed to os.Stderr
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").Log().CombinedOutput()
----

.Run command and override the default Logger
[source, go]
----
	run.Logger = log.New(os.Stderr, "", log.LstdFlags)
	out, err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").Log().CombinedOutput()
----

.Run command without trapping its output
[source, go]
----
	err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").Log().Run()
----

.Run command interactively by tying Stdin
[source, go]
----
	err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").Log().Stdin().Run()
----

.Pass data ([]byte) directly to the Stdin of the command
[source, go]
----
	err := run.CMD("./command", "arg1", "arg2").Dir("..").Env("DEBUG=true").Log().In(data).CombinedOutput()
----

.Run a command with a cancelation context
[source, go]
----
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
	defer cancel()
	out, err := run.CMD("./command", "arg1", "arg2").Ctx(ctx).CombinedOutput()
----
+
Or:
+
[source, go]
----
	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
	defer cancel()
	out, err := run.CMDCtx(ctx, "./command", "arg1", "arg2").CombinedOutput()
----

.Run a command and pass a custom io.Writer to run:
[source, go]
----
	// Defaults to os.Stdout and os.Stderr
	err := run.CMD("./command", "arg1", "arg2").Run()

	// Combined output to myCombinedWriter
	err := run.CMD("./command", "arg1", "arg2").Run(myCombinedWriter)

	// Separate streams
	err := run.CMD("./command", "arg1", "arg2").Run(myStdoutWriter, myStderrWriter)
----

.Run command and only return Stdout but print Stderr to os.Stderr as it happends
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").STDOutOutput()
----

.Run command and only return Stdout but discard Stderr for quiet mode.
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").DiscardErr().STDOutOutput()
----

.Run command and only return Stdout but save Stderr output to the error object if there was an error
[source, go]
----
	out, err := run.CMD("./command", "arg1", "arg2").SaveErr().STDOutOutput()
	if err != nil {
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			errOutput := exitErr.Stderr
			log.Printf("Failed with exit code: %d, full error output: %s\n", exitErr.ExitCode(), string(errOutput))
----

== Testing

A mocking function can be stored in the context and retrieved automatically:

. Store the mock function in the context:
+
[source, go]
----
		ctx := context.Background()
		mockR := run.CMD().Mock(func(r *run.RunInfo) error {
			r.Stdout.Write([]byte("hello world\n"))
			r.Stderr.Write([]byte("hola mundo\n"))
			return nil
		})
		ctx = run.ContextWithRunInfo(ctx, mockR)
----

. Automatically run the mock function if it exists in the context:
+
[source, go]
----
		r := run.CMDCtx(ctx, "ls", "./run")
		out, err := r.CombinedOutput()
		if err != nil {
			t.Errorf("unexpected error")
		}
		if string(out) != "hello world\nhola mundo\n" {
			t.Errorf("wrong output: %s\n", out)
		}
----

NOTE: Must use `run.CMDCtx` to automatically run the mock function if it exists in the context.
If the function doesn't exist it runs the command as usual.

== LICENSE

This file is part of run.

Copyright (C) 2020-2024  David Gamba Rios

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Documentation

Overview

Package run provides a wrapper around os/exec with method chaining for modifying behaviour.

Index

Constants

This section is empty.

Variables

View Source
var Logger = log.New(os.Stderr, "", log.LstdFlags)

Functions

func ContextWithRunInfo added in v0.8.0

func ContextWithRunInfo(ctx context.Context, value *RunInfo) context.Context

Types

type MockFn added in v0.8.0

type MockFn func(*RunInfo) error

type RunInfo

type RunInfo struct {
	Cmd []string // exposed for mocking purposes only

	Stdout io.Writer // exposed for mocking purposes only
	Stderr io.Writer // exposed for mocking purposes only
	// contains filtered or unexported fields
}

func CMD

func CMD(cmd ...string) *RunInfo

CMD - Normal constructor.

func CMDCtx added in v0.8.0

func CMDCtx(ctx context.Context, cmd ...string) *RunInfo

CMD - Pulls RunInfo from context if it exists and if not it initializes a new one. Useful when loading a RunInfo from context to ease testing.

func (*RunInfo) CombinedOutput

func (r *RunInfo) CombinedOutput() ([]byte, error)

CombinedOutput - Runs given CMD and returns STDOut and STDErr combined.

func (*RunInfo) Ctx added in v0.5.0

func (r *RunInfo) Ctx(ctx context.Context) *RunInfo

Ctx - specifies the context of the command to allow for timeouts.

func (*RunInfo) Dir

func (r *RunInfo) Dir(dir string) *RunInfo

Dir - specifies the working directory of the command.

func (*RunInfo) DiscardErr added in v0.7.0

func (r *RunInfo) DiscardErr() *RunInfo

DiscardErr - Don't print command error to stderr by default.

func (*RunInfo) DryRun added in v0.9.0

func (r *RunInfo) DryRun(b bool) *RunInfo

func (*RunInfo) Env

func (r *RunInfo) Env(env ...string) *RunInfo

Env - Add key=value pairs to the environment of the process.

func (*RunInfo) GetDir added in v0.9.0

func (r *RunInfo) GetDir() string

GetDir - used for testing

func (*RunInfo) GetEnv added in v0.9.0

func (r *RunInfo) GetEnv() []string

GetEnv - used for testing

func (*RunInfo) In

func (r *RunInfo) In(input []byte) *RunInfo

In - Pass input to stdin.

func (*RunInfo) Log

func (r *RunInfo) Log() *RunInfo

func (*RunInfo) Mock added in v0.8.0

func (r *RunInfo) Mock(fn MockFn) *RunInfo

func (*RunInfo) PrintErr deprecated added in v0.6.0

func (r *RunInfo) PrintErr() *RunInfo

PrintErr - Regardless of operation mode, print errors to os.Stderr as they occur.

Deprecated: This is the default behaviour, setting this is unnecessary and will be removed in the future.

func (*RunInfo) Run

func (r *RunInfo) Run(w ...io.Writer) error

Run - wrapper around os/exec CMD.Run()

Run starts the specified command and waits for it to complete.

The returned error is nil if the command runs, has no problems copying stdin, stdout, and stderr, and exits with a zero exit status.

If the command starts but does not complete successfully, the error is of type *ExitError. Other error types may be returned for other situations.

Examples:

Run()            // Output goes to os.Stdout and os.Stderr
Run(out)         // Sets the command's os.Stdout and os.Stderr to out.
Run(out, outErr) // Sets the command's os.Stdout to out and os.Stderr to outErr.

func (*RunInfo) STDOutOutput

func (r *RunInfo) STDOutOutput() ([]byte, error)

STDOutOutput - Runs given CMD and returns STDOut only.

Stderr output is discarded unless a call to SaveErr() or PrintErr() was made.

func (*RunInfo) SaveErr added in v0.6.0

func (r *RunInfo) SaveErr() *RunInfo

SaveErr - If the command starts but does not complete successfully, the error is of type *ExitError. In this case, save the error output into *ExitError.Stderr for retrieval.

Retrieval can be done as shown below:

err := run.CMD("./command", "arg").SaveErr().Run() // or .STDOutOutput() or .CombinedOutput()
if err != nil {
  var exitErr *exec.ExitError
  if errors.As(err, &exitErr) {
    errOutput := exitErr.Stderr

func (*RunInfo) Stdin

func (r *RunInfo) Stdin() *RunInfo

Stdin - connect caller's os.Stdin to command stdin.

Jump to

Keyboard shortcuts

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