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.

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