Skip to content

Implement CommandRunner pattern for unified testable package manager operations #20

@bluet

Description

@bluet

Problem Statement

Currently, package managers use inconsistent command execution patterns, creating architectural and testing issues:

Current State Analysis

Issues with Mixed Approaches

  1. Architectural inconsistency - Different patterns across package managers
  2. Complex testing - CommandBuilder requires shell script mocking vs simple map-based mocking
  3. Manual LC_ALL=C setup - Repetitive environment configuration in APT/Snap/Flatpak
  4. Inconsistent interactive mode - Manual stdin/stdout/stderr handling
  5. New developer complexity - CommandBuilder requires deep exec.Cmd knowledge

Decision: Standardize on CommandRunner

Based on comprehensive analysis, CommandRunner is superior to CommandBuilder for this project:

Why CommandRunner Wins

1. Automatic LC_ALL=C Handling

CommandRunner automatically prepends LC_ALL=C for consistent English output across all package managers, with user override capability:

// CommandRunner: Automatic
output, err := runner.RunContext(ctx, "yum", []string{"info", "vim"})

// CommandBuilder: Manual setup required everywhere
cmd := builder.CommandContext(ctx, "yum", "info", "vim")
cmd.Env = append(os.Environ(), "LC_ALL=C", "DEBIAN_FRONTEND=noninteractive")

2. Simplified Testing

// CommandRunner: Simple map-based mocking
mock.AddCommand("yum", []string{"info", "vim"}, []byte("output"), nil)

// CommandBuilder: Complex shell script generation
mock.AddMockResult("yum", []string{"info", "vim"}, &MockResult{
    Stdout: []byte("output"), ExitCode: 0,
})

3. Built-in Interactive Support

CommandRunner has dedicated RunInteractive() method that properly handles stdin/stdout/stderr without LC_ALL=C interference.

4. Consistency with Project Goals

From CLAUDE.md: "Use KISS (Keep It Simple and Stupid) and DRY (Don't Repeat Yourself)"

CommandRunner eliminates repetitive LC_ALL=C setup and interactive mode handling across all package managers.

5. Proven Success

YUM's recent migration to CommandRunner shows:

  • 100% test coverage maintained
  • Cleaner, more readable code
  • Robust environment variable handling
  • Successful interactive mode support

Solution: Migrate All Package Managers to CommandRunner

CommandRunner Interface

type CommandRunner interface {
    // Run executes a command with LC_ALL=C for consistent English output
    Run(name string, args ...string) ([]byte, error)
    
    // RunContext executes with context support and LC_ALL=C, plus optional extra env
    RunContext(ctx context.Context, name string, args []string, env ...string) ([]byte, error)
    
    // RunInteractive executes in interactive mode with stdin/stdout/stderr passthrough
    RunInteractive(ctx context.Context, name string, args []string, env ...string) error
}

Implementation Plan - UPDATED

Migration Progress:

  1. APTCOMPLETED (Issue APT CommandRunner Migration (Issue #20 Part 1) #27 - PR feat: implement CommandRunner architecture for APT and YUM package managers (Issue #20) #26) - Replace CommandBuilder with CommandRunner
  2. Snap 🔄 IN PROGRESS (Issue Snap CommandRunner Migration (Issue #20 Part 2) #28) - Replace direct exec.Command with CommandRunner
  3. FlatpakPLANNED (Issue Flatpak CommandRunner Migration (Issue #20 Part 3) #29) - Replace direct exec.Command with CommandRunner

Benefits

Testing Benefits

  • Simple mocking - Map-based command mocking vs complex shell scripts
  • Environment testing - Built-in environment variable tracking
  • Interactive testing - Dedicated test methods for interactive mode
  • 100% test coverage - All commands can be easily mocked

Architecture Benefits

  • Consistent interface - Same pattern across all package managers
  • Automatic LC_ALL=C - No manual environment setup needed
  • Built-in interactive support - Proper stdin/stdout/stderr handling
  • Simple for new developers - Easy to understand and implement

Code Quality Benefits

  • DRY principle - Eliminates repetitive environment setup
  • KISS principle - Simple interface vs complex CommandBuilder
  • Maintainability - Consistent patterns across codebase

Acceptance Criteria - UPDATED

Completion Status: ✅ 1/3 package managers completed (APT ✅, Snap ⏳, Flatpak ⏳)

Priority

High Priority - This achieves architectural consistency and leverages the proven CommandRunner interface that's already successful with YUM.

Related Work

Sub-Issues

This large architectural change has been broken down into manageable sub-issues:

Progress: 1/3 package managers completed. APT migration successful with full test coverage and architectural improvements.

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions