exec

package
v2.1.21 Latest Latest
Warning

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

Go to latest
Published: Jan 23, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package exec provides utilities for executing system commands with IOResult-based error handling.

This package wraps system command execution in the IOResult monad, which represents IO operations that can fail with errors using Go's idiomatic (value, error) tuple pattern. Unlike the result/exec package, these operations explicitly acknowledge their side-effectful nature by returning IOResult instead of plain Result.

Overview

The exec package is designed for executing system commands as IO operations that may fail. Since command execution is inherently side-effectful (it interacts with the operating system, may produce different results over time, and has observable effects), IOResult is the appropriate abstraction.

Basic Usage

The primary function is Command, which executes a system command:

import (
    "github.com/IBM/fp-go/v2/bytes"
    "github.com/IBM/fp-go/v2/exec"
    "github.com/IBM/fp-go/v2/function"
    "github.com/IBM/fp-go/v2/idiomatic/ioresult"
    ioexec "github.com/IBM/fp-go/v2/idiomatic/ioresult/exec"
)

// Execute a command and get the output
version := F.Pipe1(
    ioexec.Command("openssl")([]string{"version"})([]byte{}),
    ioresult.Map(F.Flow2(
        exec.StdOut,
        bytes.ToString,
    )),
)

// Run the IO operation
result, err := version()
if err != nil {
    log.Fatal(err)
}
fmt.Println(result)

Command Output

Commands return exec.CommandOutput, which contains both stdout and stderr as byte slices. Use exec.StdOut and exec.StdErr to extract the respective streams:

output := ioexec.Command("ls")([]string{"-la"})([]byte{})
result := ioresult.Map(func(out exec.CommandOutput) string {
    stdout := exec.StdOut(out)
    stderr := exec.StdErr(out)
    return bytes.ToString(stdout)
})(output)

Composing Commands

Commands can be composed using IOResult combinators:

// Chain multiple commands together
pipeline := F.Pipe2(
    ioexec.Command("echo")([]string{"hello world"})([]byte{}),
    ioresult.Chain(func(out exec.CommandOutput) ioexec.IOResult[exec.CommandOutput] {
        input := exec.StdOut(out)
        return ioexec.Command("tr")([]string{"a-z", "A-Z"})(input)
    }),
    ioresult.Map(F.Flow2(exec.StdOut, bytes.ToString)),
)

Error Handling

Commands return errors for various failure conditions:

  • Command not found
  • Non-zero exit status
  • Permission errors
  • System resource errors

Handle errors using IOResult's error handling combinators:

safeCommand := F.Pipe1(
    ioexec.Command("risky-command")([]string{})([]byte{}),
    ioresult.Alt(func() (exec.CommandOutput, error) {
        // Fallback on error
        return exec.CommandOutput{}, nil
    }),
)

Index

Constants

This section is empty.

Variables

View Source
var (
	// Command executes a system command with side effects and returns an IOResult.
	//
	// This function is curried to allow partial application. It takes three parameters:
	//   - name: The command name or path to execute
	//   - args: Command-line arguments as a slice of strings
	//   - in: Input bytes to send to the command's stdin
	//
	// Returns IOResult[exec.CommandOutput] which, when executed, will run the command
	// and return either the command output or an error.
	//
	// The command is executed using the system's default shell context. The output
	// contains both stdout and stderr as byte slices, accessible via exec.StdOut
	// and exec.StdErr respectively.
	//
	// Example:
	//
	//	// Simple command execution
	//	version := Command("node")([]string{"--version"})([]byte{})
	//	result, err := version()
	//
	//	// With input piped to stdin
	//	echo := Command("cat")([]string{})([]byte("hello world"))
	//
	//	// Partial application for reuse
	//	git := Command("git")
	//	status := git([]string{"status"})([]byte{})
	//	log := git([]string{"log", "--oneline"})([]byte{})
	//
	//	// Composed with IOResult combinators
	//	result := F.Pipe1(
	//	    Command("openssl")([]string{"version"})([]byte{}),
	//	    ioresult.Map(F.Flow2(exec.StdOut, bytes.ToString)),
	//	)
	Command = function.Curry3(command)
)

Functions

This section is empty.

Types

type IOResult

type IOResult[T any] = ioresult.IOResult[T]

IOResult represents an IO operation that may fail with an error. It is defined as func() (T, error), following Go's idiomatic error handling pattern.

This type is re-exported from the ioresult package for convenience when working with command execution, allowing users to reference exec.IOResult instead of importing the ioresult package separately.

type Kleisli

type Kleisli[A, B any] = ioresult.Kleisli[A, B]

Kleisli represents a function from A to IOResult[B]. Named after Heinrich Kleisli, it represents a monadic arrow in the IOResult monad.

Kleisli functions are useful for chaining operations where each step may perform IO and may fail. They can be composed using IOResult's Chain function.

Example:

type Kleisli[A, B any] func(A) IOResult[B]

parseConfig := func(path string) IOResult[Config] { ... }
validateConfig := func(cfg Config) IOResult[Config] { ... }

// Compose Kleisli functions
loadAndValidate := Chain(validateConfig)(parseConfig("/config.yml"))

type Operator

type Operator[A, B any] = ioresult.Operator[A, B]

Operator represents a function that transforms one IOResult into another. It maps IOResult[A] to IOResult[B], useful for defining reusable transformations.

Example:

type Operator[A, B any] func(IOResult[A]) IOResult[B]

addLogging := func(io IOResult[string]) IOResult[string] {
    return func() (string, error) {
        result, err := io()
        log.Printf("Result: %v, Error: %v", result, err)
        return result, err
    }
}

Jump to

Keyboard shortcuts

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