bluet / bluet/syspkg

Implement CommandRunner pattern for unified testable package manager operations

Open
#20 3 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Go
Stars
17
Forks
8
PR merge metrics
No merged PRs in 30d

Description

## Problem Statement

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

### Current State Analysis
- **YUM**: ✅ Uses CommandRunner (recently migrated, fully tested)
- **APT**: ~~Uses CommandBuilder~~ ✅ **MIGRATED** (Issue #27 - PR #26)
- **Snap**: Uses direct `exec.Command` calls (Issue #28)
- **Flatpak**: Uses direct `exec.Command` calls (Issue #29)

### 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:
```go
// 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**
```go
// 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
```go
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. **APT** ✅ **COMPLETED** (Issue #27 - PR #26) - Replace CommandBuilder with CommandRunner
2. **Snap** 🔄 **IN PROGRESS** (Issue #28) - Replace direct exec.Command with CommandRunner
3. **Flatpak** ⏳ **PLANNED** (Issue #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

- [x] **APT migrated from CommandBuilder to CommandRunner** ✅ (Issue #27 - PR #26)
- [ ] **Snap migrated from direct exec.Command to CommandRunner** (Issue #28)
- [ ] **Flatpak migrated from direct exec.Command to CommandRunner** (Issue #29)
- [x] **LC_ALL=C automatically handled across all package managers** ✅ (APT+YUM complete)
- [x] **Interactive mode works consistently across all package managers** ✅ (APT+YUM complete)
- [x] **Comprehensive test coverage maintained for all migrations** ✅ (APT complete)
- [x] **All existing functionality preserved** ✅ (APT verified)
- [x] **Documentation updated to reflect architectural consistency** ✅ (Updated for APT)

**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

- ✅ CommandRunner interface implemented and proven with YUM
- ✅ YUM migration completed successfully (100% test coverage)
- ✅ **APT migration completed successfully (Issue #27 - PR #26)**
- ✅ MockCommandRunner supports environment variable tracking
- ✅ Interactive mode support built-in and tested

## Sub-Issues

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

- **Issue #27**: ✅ **APT CommandRunner Migration** (COMPLETED by PR #26)
- **Issue #28**: 🔄 **Snap CommandRunner Migration** (In Progress)
- **Issue #29**: ⏳ **Flatpak CommandRunner Migration** (Planned)

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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.