Commander: Bcuz Go’s os/exec Made Me Want to Shart on My Laptop’s Screen

Let’s be fucking honest here – if you’ve ever tried to do anything serious with Go’s os/exec package, you know it’s about as user-friendly as a cactus suppository. Want to stream output in real-time? Good luck with that bullshit. Need to handle timeouts properly? Hope you enjoy writing the same boilerplate garbage over and over. Want to test your command execution? Get ready to mock the entire fucking universe.

After years of dealing with this nonsense, I finally said “fuck it” and built something that actually works. Meet Commander – a Go package that transforms os/exec from a painful, error-prone disaster into a robust, production-ready foundation for sophisticated process management systems.

What’s Wrong with os/exec?

Oh boy, where do I even fucking start:

  1. Streaming Output is a Clusterfuck: Want real-time output from a long-running command? Time to write scanner loops, manage goroutines, and deal with pipe cleanup. It’s like they designed it specifically to make you want to punch your monitor.
  2. Context Timeout Handling is Ass: Sure, Go has contexts, but using exec.CommandContext properly and handling all the edge cases without losing your shit? That’s a whole different story.
  3. Process Termination is a Nightmare: Try gracefully stopping a process with SIGTERM and fallback to SIGKILL. You’ll be writing more boilerplate than actual business logic, and you’ll probably fuck it up anyway.
  4. Testing is Hell on Earth: Mocking command execution for tests? Hope you enjoy dependency injection hell and questioning your life choices.
  5. Error Handling is a Joke: Did the command timeout? Was it killed? Did it exit with an error? Figure it out yourself from cryptic exit codes and signal bullshit.
  6. Concurrent Command Hell: Run 1000+ commands concurrently? Prepare for race conditions, resource leaks, and debugging nightmares.

Enter Commander

Commander wraps Go’s os/exec with an API that doesn’t make you want to throw your laptop out the window. It provides:

  • Simple command execution that just fucking works
  • Real-time broadcast streaming – multiple listeners on the same process output
  • Context-based timeout handling that actually respects your deadlines
  • Intelligent process termination with SIGTERM → SIGKILL progression
  • Proper error types so you know what the fuck happened
  • Advanced mocking system with sophisticated argument matching
  • Thread-safe concurrent execution – proper goroutine management
  • Resource leak prevention and proper cleanup

Installation

go get github.com/psyb0t/commander

Real-World Use Cases That’ll Blow Your Mind

1. CI/CD Pipeline Orchestration

Stop writing fragile shell scripts. Build robust CI/CD pipelines that handle failures gracefully:

package main
import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"
    "github.com/psyb0t/commander"
    commonerrors "github.com/psyb0t/common-go/errors"
)
func main() {
    cmd := commander.New()
    ctx := context.Background()
    fmt.Println("🚀 Starting CI/CD Pipeline...")
    // Stage 1: Build
    fmt.Println("📦 Building application...")
    if err := runStage(ctx, cmd, "go", []string{"build", "./..."}); err != nil {
        log.Fatalf("Build failed: %v", err)
    }
    // Stage 2: Run tests concurrently
    fmt.Println("🧪 Running test suites...")
    var wg sync.WaitGroup
    errors := make(chan error, 3)
    tests := [][]string{
        {"go", "test", "./internal/..."},
        {"go", "test", "./pkg/..."},
        {"go", "test", "-race", "./..."},
    }
    for _, test := range tests {
        wg.Add(1)
        go func(testCmd []string) {
            defer wg.Done()
            if err := runStage(ctx, cmd, testCmd[0], testCmd[1:]); err != nil {
                errors <- fmt.Errorf("%s failed: %v", testCmd[1], err)
            }
        }(test)
    }
    wg.Wait()
    close(errors)
    for err := range errors {
        log.Printf("Test failure: %v", err)
        return
    }
    // Stage 3: Docker build and push
    fmt.Println("🐳 Building and pushing Docker image...")
    if err := runStage(ctx, cmd, "docker", []string{"build", "-t", "myapp:latest", "."}); err != nil {
        log.Fatalf("Docker build failed: %v", err)
    }
    if err := runStage(ctx, cmd, "docker", []string{"push", "myapp:latest"}); err != nil {
        log.Fatalf("Docker push failed: %v", err)
    }
    fmt.Println("✅ Pipeline completed successfully!")
}
func runStage(ctx context.Context, cmd commander.Commander, name string, args []string) error {
    timeout := 5 * time.Minute
    stageCtx, cancel := context.WithTimeout(ctx, timeout)
    defer cancel()
    stdout, stderr, err := cmd.Output(stageCtx, name, args)
    if err != nil {
        if commonerrors.ErrTimeout == err {
            return fmt.Errorf("stage timed out after %v", timeout)
        }
        return fmt.Errorf("command failed: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
    }
    fmt.Printf("✓ %s completed\n", name)
    return nil
}

2. Real-Time Log Aggregation System

Build a log monitoring system that simultaneously displays, analyzes, and alerts on log data:

package main
import (
    "context"
    "fmt"
    "log"
    "regexp"
    "strings"
    "sync"
    "github.com/psyb0t/commander"
)
func main() {
    cmd := commander.New()
    ctx := context.Background()
    fmt.Println("📊 Starting Log Aggregation System...")
    // Start multiple log sources
    logSources := []string{
        "tail -f /var/log/nginx/access.log",
        "tail -f /var/log/app/application.log",
        "tail -f /var/log/system.log",
    }
    var wg sync.WaitGroup
    for i, source := range logSources {
        wg.Add(1)
        go func(sourceCmd string, sourceID int) {
            defer wg.Done()
            monitorLogSource(ctx, cmd, sourceCmd, sourceID)
        }(source, i)
    }
    wg.Wait()
}
func monitorLogSource(ctx context.Context, cmd commander.Commander, logCmd string, sourceID int) {
    parts := strings.Fields(logCmd)
    process, err := cmd.Start(ctx, parts[0], parts[1:])
    if err != nil {
        log.Printf("Failed to start log source %d: %v", sourceID, err)
        return
    }
    // Create multiple channels for different purposes
    displayChan := make(chan string, 1000)
    analyticsChan := make(chan string, 1000)
    alertChan := make(chan string, 100)
    // Start streaming to all channels (broadcast - non-blocking)
    process.Stream(displayChan, nil)
    process.Stream(analyticsChan, nil)
    process.Stream(alertChan, nil)
    var wg sync.WaitGroup
    // Real-time display
    wg.Add(1)
    go func() {
        defer wg.Done()
        for line := range displayChan {
            fmt.Printf("[LOG-%d] %s", sourceID, line)
        }
    }()
    // Analytics processing
    wg.Add(1)
    go func() {
        defer wg.Done()
        errorCount := 0
        for line := range analyticsChan {
            if strings.Contains(strings.ToLower(line), "error") {
                errorCount++
                if errorCount%10 == 0 {
                    fmt.Printf("🔥 Source %d: %d errors detected\n", sourceID, errorCount)
                }
            }
        }
    }()
    // Alert system
    wg.Add(1)
    go func() {
        defer wg.Done()
        criticalPattern := regexp.MustCompile(`(?i)(fatal|critical|emergency)`)
        for line := range alertChan {
            if criticalPattern.MatchString(line) {
                fmt.Printf("🚨 CRITICAL ALERT [Source %d]: %s", sourceID, line)
                // Send to alerting system, Slack, PagerDuty, etc.
            }
        }
    }()
    // Wait for process to complete
    if err := process.Wait(); err != nil {
        log.Printf("Log source %d terminated: %v", sourceID, err)
    }
    // Close channels and wait for processors
    close(displayChan)
    close(analyticsChan)
    close(alertChan)
    wg.Wait()
}

3. Distributed System Health Monitor

Monitor multiple services concurrently with intelligent failure handling:

package main
import (
    "context"
    "fmt"
    "sync"
    "time"
    "github.com/psyb0t/commander"
    commonerrors "github.com/psyb0t/common-go/errors"
)
type ServiceCheck struct {
    Name    string
    Command []string
    Timeout time.Duration
}
func main() {
    cmd := commander.New()
    services := []ServiceCheck{
        {"Database", []string{"pg_isready", "-h", "db.example.com"}, 5 * time.Second},
        {"Redis", []string{"redis-cli", "-h", "redis.example.com", "ping"}, 3 * time.Second},
        {"API Gateway", []string{"curl", "-f", "https://api.example.com/health"}, 10 * time.Second},
        {"Message Queue", []string{"rabbitmq-diagnostics", "status"}, 5 * time.Second},
        {"Elasticsearch", []string{"curl", "-f", "http://es.example.com:9200/_cluster/health"}, 5 * time.Second},
    }
    fmt.Println("🏥 Starting Distributed Health Monitor...")
    for {
        fmt.Printf("\n📋 Health Check - %s\n", time.Now().Format("15:04:05"))
        var wg sync.WaitGroup
        results := make(chan string, len(services))
        for _, service := range services {
            wg.Add(1)
            go func(svc ServiceCheck) {
                defer wg.Done()
                checkService(cmd, svc, results)
            }(service)
        }
        wg.Wait()
        close(results)
        // Display results
        healthyCount := 0
        for result := range results {
            fmt.Print(result)
            if strings.Contains(result, "✅") {
                healthyCount++
            }
        }
        fmt.Printf("\n🎯 System Health: %d/%d services healthy\n", healthyCount, len(services))
        if healthyCount == len(services) {
            fmt.Println("🚀 All systems operational!")
        } else {
            fmt.Printf("⚠️  %d services need attention\n", len(services)-healthyCount)
        }
        time.Sleep(30 * time.Second)
    }
}
func checkService(cmd commander.Commander, service ServiceCheck, results chan<- string) {
    ctx, cancel := context.WithTimeout(context.Background(), service.Timeout)
    defer cancel()
    start := time.Now()
    stdout, stderr, err := cmd.Output(ctx, service.Command[0], service.Command[1:])
    duration := time.Since(start)
    var status string
    if err != nil {
        switch err {
        case commonerrors.ErrTimeout:
            status = fmt.Sprintf("❌ %s: TIMEOUT (>%v)", service.Name, service.Timeout)
        case commonerrors.ErrTerminated, commonerrors.ErrKilled:
            status = fmt.Sprintf("💀 %s: KILLED", service.Name)
        default:
            status = fmt.Sprintf("❌ %s: FAILED - %v", service.Name, err)
        }
        if len(stderr) > 0 {
            status += fmt.Sprintf(" [%s]", strings.TrimSpace(string(stderr)))
        }
    } else {
        status = fmt.Sprintf("✅ %s: OK (%v)", service.Name, duration.Round(time.Millisecond))
        if len(stdout) > 0 && len(stdout) < 100 {
            status += fmt.Sprintf(" [%s]", strings.TrimSpace(string(stdout)))
        }
    }
    results <- status + "\n"
}

4. Interactive Command Session Manager

Build interactive tools that need bidirectional communication:

package main
import (
    "bufio"
    "context"
    "fmt"
    "log"
    "os"
    "strings"
    "github.com/psyb0t/commander"
)
func main() {
    cmd := commander.New()
    ctx := context.Background()
    fmt.Println("🔧 Interactive Database Shell")
    fmt.Println("Connecting to PostgreSQL...")
    // Start interactive psql session
    process, err := cmd.Start(ctx, "psql", []string{
        "-h", "localhost",
        "-U", "postgres",
        "-d", "mydb",
    })
    if err != nil {
        log.Fatalf("Failed to start psql: %v", err)
    }
    // Get stdin pipe for sending commands
    stdin, err := process.StdinPipe()
    if err != nil {
        log.Fatalf("Failed to get stdin pipe: %v", err)
    }
    // Set up output streaming
    outputChan := make(chan string, 100)
    process.Stream(outputChan, outputChan) // Both stdout and stderr to same channel
    // Display output
    go func() {
        for line := range outputChan {
            fmt.Print(line)
        }
    }()
    // Interactive input loop
    fmt.Println("🎯 Ready for SQL commands (type 'quit' to exit):")
    scanner := bufio.NewScanner(os.Stdin)
    for {
        fmt.Print("sql> ")
        if !scanner.Scan() {
            break
        }
        input := strings.TrimSpace(scanner.Text())
        if input == "quit" || input == "exit" {
            break
        }
        // Send command to psql
        if _, err := stdin.Write([]byte(input + "\n")); err != nil {
            log.Printf("Failed to send command: %v", err)
            break
        }
    }
    // Graceful shutdown
    stdin.Close()
    stopCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := process.Stop(stopCtx); err != nil {
        fmt.Printf("Process stopped with: %v\n", err)
    } else {
        fmt.Println("✅ Session ended gracefully")
    }
}

Advanced Features That Set It Apart

Intelligent Process Termination

Commander handles the complex SIGTERM → SIGKILL dance automatically:

// Graceful shutdown with fallback
stopCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := process.Stop(stopCtx)
switch err {
case commonerrors.ErrTerminated:
    fmt.Println("Process stopped gracefully with SIGTERM")
case commonerrors.ErrKilled:
    fmt.Println("Process had to be force killed with SIGKILL")
case commonerrors.ErrTimeout:
    fmt.Println("Stop operation timed out")
}

Real-Time Broadcast Streaming

Multiple listeners can simultaneously monitor the same process output:

// Multiple channels listening to the same process
logChannel := make(chan string, 1000)
alertChannel := make(chan string, 100)
metricsChannel := make(chan string, 500)
// All channels get the same data (broadcast)
process.Stream(logChannel, nil)
process.Stream(alertChannel, nil)
process.Stream(metricsChannel, nil)
// Each channel can process independently
go logProcessor(logChannel)
go alertProcessor(alertChannel)
go metricsProcessor(metricsChannel)

Production-Ready Error Handling

Proper error classification for different failure modes:

err := cmd.Run(ctx, "risky-command", args)
switch err {
case commonerrors.ErrTimeout:
    // Context deadline exceeded - retry with longer timeout
    retryWithLongerTimeout()
case commonerrors.ErrTerminated:
    // Process received SIGTERM - graceful shutdown
    handleGracefulShutdown()
case commonerrors.ErrKilled:
    // Process was force killed - investigate resources
    investigateResourceIssues()
default:
    if err != nil {
        // Command execution failed - check command/args
        handleCommandFailure(err)
    }
}

Testing Like a Boss

Commander includes sophisticated mocking that doesn’t suck ass:

func TestDeploymentPipeline(t *testing.T) {
    mockCmd := &MockCommander{}
    // Set up expectations with argument matching
    mockCmd.On("Run", mock.Anything, "docker",
        []string{"build", "-t", "myapp:v1.0.0", "."}).Return(nil)
    mockCmd.On("Run", mock.Anything, "docker",
        mock.MatchedBy(func(args []string) bool {
            return len(args) >= 2 && args[0] == "push"
        })).Return(nil)
    // Test your pipeline
    pipeline := NewDeploymentPipeline(mockCmd)
    err := pipeline.Deploy("v1.0.0")
    assert.NoError(t, err)
    mockCmd.AssertExpectations(t)
}

The Core Interfaces

The power is in the simplicity:

type Commander interface {
    Run(ctx context.Context, name string, args []string, opts ...Option) error
    Output(ctx context.Context, name string, args []string, opts ...Option) ([]byte, []byte, error)
    CombinedOutput(ctx context.Context, name string, args []string, opts ...Option) ([]byte, error)
    Start(ctx context.Context, name string, args []string, opts ...Option) (Process, error)
}
type Process interface {
    Start() error
    Wait() error
    StdinPipe() (io.WriteCloser, error)
    Stream(stdout, stderr chan<- string)
    Stop(ctx context.Context) error
    Kill(ctx context.Context) error
    PID() int
}

Configuration options that actually matter:

func WithStdin(stdin io.Reader) Option        // Feed data to process
func WithEnv(env []string) Option            // Set environment variables
func WithDir(dir string) Option              // Set working directory

Why It Doesn’t Suck

  1. It’s Just Go: Uses standard contexts, follows Go idioms, no magic bullshit
  2. Thread-Safe: Proper concurrent execution with resource management
  3. Resource Safe: No leaked goroutines, file descriptors, or zombie processes
  4. Proper Error Handling: You know what happened and why
  5. Advanced Streaming: Real-time, broadcast, join-on-demand streaming
  6. Testing Excellence: Sophisticated mocking with argument matching
  7. Battle Tested: Used in production CI/CD systems, monitoring tools, and DevOps platforms

Conclusion

os/exec is fine for running echo "hello", but when you need to build real systems – CI/CD pipelines, monitoring tools, interactive applications, or distributed system orchestration – Commander provides the robust, production-ready foundation you fucking deserve.

Stop fighting with pipes and goroutines. Stop writing the same boilerplate garbage over and over. Stop debugging race conditions and resource leaks at 3 AM. Use Commander and focus on building badass systems instead of wrestling with Go’s process execution bullshit.

Your laptop screen will thank you for not sharting on it.

License

MIT – Because sharing is caring, and code should be free.