A learning project demonstrating advanced Haskell concepts through a type-safe command execution abstraction layer for local and remote machines.
This repository contains four alternative implementations (cmd-exec-alt-1 through cmd-exec-alt-4) of a command execution framework that provides a unified interface for running shell commands on both local and remote machines via SSH. Each alternative explores different architectural patterns and design approaches in Haskell.
- Unified Interface: Execute commands on local or remote machines through a single
CommandExecutortypeclass - Type Safety: Strong typing with custom
ExitCode,Command,ExecuteCmd, andRunCmdtypes - Pluggable Executors: Support for custom command executors via
CustomExecutorwith fallback to default implementations - Machine Context: Encapsulates execution environment with
MachineContextdata type
- SSH Integration: Full SSH support with configurable credentials (username, hostname, port, private key)
- SCP File Transfer: Secure copy protocol implementation for file transfers between local and remote machines
- Rsync Support: Advanced synchronization with options for excludes, archive mode, and automatic port/key configuration
- Command Wrapping: Automatic SSH command wrapping with proper quote escaping
- Typeclass-based Design:
CommandExecutortypeclass provides polymorphic command execution - Smart Constructors: Type-safe construction of SSH credentials, SCP file paths, and Rsync operations
- Error Handling: Result types and error handling with
Common.ErrandCommon.Resultmodules - Local/Remote Abstraction: Transparent handling of local vs remote execution contexts
Each alternative implementation (cmd-exec-alt-1 through cmd-exec-alt-4) contains:
cmd-exec-alt-X/
├── app/
│ ├── Main.hs # CLI application entry point
│ ├── Machines.hs # Machine configuration
│ └── Common/ # Common utilities (Err, Result)
├── src/
│ ├── Executor.hs # Core command executor abstraction
│ ├── Machine.hs # Machine and context definitions
│ ├── Ssh.hs # SSH credential and command handling
│ ├── Scp.hs # Secure copy functionality
│ ├── Rsync.hs # Rsync synchronization
│ ├── Local/Executor.hs # Local command execution
│ ├── Remote/Executor.hs # Remote SSH command execution
│ └── Core/ # Core utilities and error types
└── test/unit/ # Unit tests (QuickCheck, Tasty)
Defines the core command execution types and typeclass:
CommandExecutortypeclass withexecuteCmdIOandrunCmdIOmethodsExecuteCmd: Command -> IO (ExitCode, String) - runs and captures outputRunCmd: Command -> IO ExitCode - runs and returns exit code onlyCustomExecutordata type for dependency injection
Machine abstraction with local and remote variants:
Machine:LocalMachine | RemoteMachine SshCredentialsMachineContext: Wraps machine with optional custom executor- Instance of
CommandExecutorfor transparent execution routing
Remote operations with full configuration support:
- SSH: Credentials with username, hostname, port, and private key file
- SCP: URI-based file path representation for local/remote files
- Rsync: Source/destination with options, automatic SSH parameter passing
- Record Syntax: Named fields with
NamedFieldPuns,DisambiguateRecordFields,DuplicateRecordFields - Type Classes: Polymorphic interfaces for command execution
- Phantom Types: Type-level safety for SSH credentials and file paths
- Pattern Matching: Exhaustive case analysis for machine types
- Show Instances: Custom string representations for commands and credentials
base: Core Haskell libraryprocess: System process executiondirectory,filepath: File system operationssplit: String splitting utilitiesmtl: Monad transformer library- Testing:
tasty,tasty-hunit,tasty-quickcheck, QuickCheck
DisambiguateRecordFields,DuplicateRecordFieldsRecordWildCardsGeneralizedNewtypeDerivingNoFieldSelectors
This project demonstrates:
- Type-driven Design: Using Haskell's type system to enforce correctness
- Abstraction Patterns: Typeclasses, data types, and smart constructors
- Error Handling: Result types and IO error management
- Module Organization: Clean separation of concerns across modules
- Testing: Property-based testing with QuickCheck and unit tests with Tasty
- Real-world Integration: SSH, SCP, and Rsync command-line tool wrappers
The four alternatives (cmd-exec-alt-1 through cmd-exec-alt-4) explore different:
- Error handling strategies
- Type abstraction levels
- Module organization patterns
- Executor customization approaches
- Testing methodologies
Each can be built and run independently to compare approaches.
- Configuration Management: Deploy and execute commands across multiple machines
- Build Automation: Run builds on remote servers
- File Synchronization: Sync files between local and remote environments
- Testing Infrastructure: Execute tests on different machine configurations
- DevOps Scripting: Type-safe deployment and management scripts
Tibor Fasanga (tibor@fasanga.com)
BSD-3-Clause (2024)