com

package
v0.0.0-...-55aee6b Latest Latest
Warning

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

Go to latest
Published: Apr 22, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package com is a lightweight wrapper around golang command execution. It provides a simplified API to create commands with baked-in: - timeout - pty - environment filtering - stdin manipulation - proper termination of the process group - wrapping commands and prepended args

Index

Examples

Constants

View Source
const LoggerKey = contextKey("logger")

LoggerKey defines the key to attach a logger to on the context.

Variables

View Source
var (
	// ErrTimeout is returned by Wait() in case a command fail to complete within allocated time.
	ErrTimeout = errors.New("command timed out")
	// ErrFailedStarting is returned by Run() and Wait() in case a command fails to start (eg:
	// binary missing).
	ErrFailedStarting = errors.New("command failed starting")
	// ErrSignaled is returned by Wait() if a signal was sent to the command while running.
	ErrSignaled = errors.New("command execution signaled")
	// ErrExecutionFailed is returned by Wait() when a command executes but returns a non-zero error code.
	ErrExecutionFailed = errors.New("command returned a non-zero exit code")
	// ErrFailedSendingSignal may happen if sending a signal to an already terminated process.
	ErrFailedSendingSignal = errors.New("failed sending signal")

	// ErrExecAlreadyStarted is a system error normally indicating a bogus double call to Run().
	ErrExecAlreadyStarted = errors.New("command has already been started (double `Run`)")
	// ErrExecNotStarted is a system error normally indicating that Wait() has been called without first calling Run().
	ErrExecNotStarted = errors.New("command has not been started (call `Run` first)")
	// ErrExecAlreadyFinished is a system error indicating a double call to Wait().
	ErrExecAlreadyFinished = errors.New("command is already finished")
)
View Source
var (
	// ErrFailedCreating could be returned by newStdPipes() on pty creation failure.
	ErrFailedCreating = errors.New("failed acquiring pipe")
	// ErrFailedReading could be returned by the ioGroup in case the go routines fails to read out of a pipe.
	ErrFailedReading = errors.New("failed reading")
	// ErrFailedWriting could be returned by the ioGroup in case the go routines fails to write on a pipe.
	ErrFailedWriting = errors.New("failed writing")
)

Functions

This section is empty.

Types

type Command

type Command struct {
	Binary      string
	PrependArgs []string
	Args        []string
	WrapBinary  string
	WrapArgs    []string
	Timeout     time.Duration

	WorkingDir   string
	Env          map[string]string
	EnvBlackList []string
	EnvWhiteList []string
	// contains filtered or unexported fields
}

Command is a thin wrapper on-top of golang exec.Command.

Example
package main

import (
	"context"
	"fmt"

	"github.com/containerd/nerdctl/mod/tigron/internal/com"
)

func main() {
	cmd := com.Command{
		Binary: "printf",
		Args:   []string{"hello world"},
	}

	err := cmd.Run(context.Background())
	if err != nil {
		fmt.Println("Run err:", err)

		return
	}

	exec, err := cmd.Wait()
	if err != nil {
		fmt.Println("Wait err:", err)

		return
	}

	fmt.Println("Exit code:", exec.ExitCode)
	fmt.Println("Stdout:")
	fmt.Println(exec.Stdout)
	fmt.Println("Stderr:")
	fmt.Println(exec.Stderr)

}
Output:
Exit code: 0
Stdout:
hello world
Stderr:

func (*Command) Clone

func (gc *Command) Clone() *Command

Clone does just duplicate a command, resetting its execution.

func (*Command) Feed

func (gc *Command) Feed(reader io.Reader)

Feed ensures that the provider reader will be copied on the command stdin. Feed, like WithFeeder, can be used multiple times, and writes will be performed in sequentially, in order. This command has no effect if Run has already been called.

Example
package main

import (
	"context"
	"fmt"
	"io"
	"strings"
	"time"

	"github.com/containerd/nerdctl/mod/tigron/internal/com"
)

func main() {
	cmd := &com.Command{
		Binary: "bash",
		Args: []string{
			"-c", "--",
			"read line1; read line2; printf 'from stdin%s%s%s' \"$line1\" \"$line2\";",
		},
	}

	// Use WithFeeder if you do want to perform additional tasks before feeding to stdin
	cmd.WithFeeder(func() io.Reader {
		time.Sleep(100 * time.Millisecond)

		return strings.NewReader("hello world\n")
	})

	// Or use the simpler Feed if you just want to pass along content to stdin
	// Note that successive calls to WithFeeder / Feed will be written to stdin in order.
	cmd.Feed(strings.NewReader("hello again\n"))

	err := cmd.Run(context.Background())
	if err != nil {
		fmt.Println("Run err:", err)

		return
	}

	exec, err := cmd.Wait()
	if err != nil {
		fmt.Println("Wait err:", err)

		return
	}

	fmt.Println("Exit code:", exec.ExitCode)
	fmt.Println("Stdout:")
	fmt.Println(exec.Stdout)
	fmt.Println("Stderr:")
	fmt.Println(exec.Stderr)

}
Output:
Exit code: 0
Stdout:
from stdinhello worldhello again
Stderr:

func (*Command) Run

func (gc *Command) Run(parentCtx context.Context) error

Run starts the command in the background. It may error out immediately if the command fails to start (ErrFailedStarting).

func (*Command) Signal

func (gc *Command) Signal(sig os.Signal) error

Signal sends a signal to the command. It should be called after Run() but before Wait().

Example
package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/containerd/nerdctl/mod/tigron/internal/com"
)

func main() {
	cmd := com.Command{
		Binary:  "sleep",
		Args:    []string{"3600"},
		Timeout: time.Second,
	}

	err := cmd.Run(context.Background())
	if err != nil {
		fmt.Println("Run err:", err)

		return
	}

	err = cmd.Signal(os.Interrupt)
	if err != nil {
		fmt.Println("Signal err:", err)

		return
	}

	exec, err := cmd.Wait()
	fmt.Println("Wait err:", err)
	fmt.Println("Exit code:", exec.ExitCode)
	fmt.Println("Stdout:")
	fmt.Println(exec.Stdout)
	fmt.Println("Stderr:")
	fmt.Println(exec.Stderr)
	fmt.Println("Signal:", exec.Signal)

}
Output:
Wait err: command execution signaled
Exit code: -1
Stdout:

Stderr:

Signal: interrupt

func (*Command) Wait

func (gc *Command) Wait() (*Result, error)

Wait should be called after Run(), and will return the outcome of the command execution.

func (*Command) WithFeeder

func (gc *Command) WithFeeder(writers ...func() io.Reader)

WithFeeder ensures that the provider function will be executed and its output fed to the command stdin. WithFeeder, like Feed, can be used multiple times, and writes will be performed sequentially, in order. This command has no effect if Run has already been called. Note that if the `writer` function runs a forever loop, we will deadlock and just Wait() forever on the errgroup.

func (*Command) WithPTY

func (gc *Command) WithPTY(stdin, stdout, stderr bool)

WithPTY requests that the command be executed with a pty for std streams. Parameters allow showing which streams are to be tied to the pty. This command has no effect if Run has already been called.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/containerd/nerdctl/mod/tigron/internal/com"
)

func main() {
	cmd := &com.Command{
		Binary: "bash",
		Args: []string{
			"-c",
			"--",
			"[ -t 1 ] || { echo not a pty; exit 41; }; printf onstdout; >&2 printf onstderr;",
		},
		Timeout: 1 * time.Second,
	}

	// The PTY can be set to any of stdin, stdout, stderr
	// Note that PTY are supported only on Linux, Darwin and FreeBSD
	cmd.WithPTY(false, true, false)

	err := cmd.Run(context.Background())
	if err != nil {
		fmt.Println("Run err:", err)

		return
	}

	exec, err := cmd.Wait()
	if err != nil {
		fmt.Println("Wait err:", err)

		return
	}

	fmt.Println("Exit code:", exec.ExitCode)
	fmt.Println("Stdout:")
	fmt.Println(exec.Stdout)
	fmt.Println("Stderr:")
	fmt.Println(exec.Stderr)

}
Output:
Exit code: 0
Stdout:
onstdout
Stderr:
onstderr

type Result

type Result struct {
	Environ  []string
	Stdout   string
	Stderr   string
	ExitCode int
	Signal   os.Signal
	Duration time.Duration
}

Result carries the resulting output of a command once it has finished.

Jump to

Keyboard shortcuts

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