ShellForge now uses a modular build system that maintains the key benefit of producing a single, self-contained shell script while making development much more manageable.
shellforge/
├── src/ # Source modules
│ ├── core/ # Core functionality
│ │ ├── constants.sh # Global constants and arrays
│ │ ├── variables.sh # Global variables
│ │ ├── utils.sh # Utility functions
│ │ └── display.sh # UI and display functions
│ ├── lib/ # Shared libraries
│ │ ├── file-operations.sh # File/directory operations
│ │ ├── metadata.sh # Metadata handling
│ │ └── backup-filters.sh # Backup filtering logic
│ ├── modules/ # Feature modules
│ │ ├── backup.sh # Save functionality
│ │ ├── restore.sh # Restore functionality
│ │ ├── list.sh # List backups
│ │ └── smart-config.sh # Smart config enhancements
│ ├── header.sh # Script header (shebang, metadata)
│ └── main.sh # Main entry point
├── build/ # Build system
│ └── build.sh # Build script
├── dist/ # Built artifacts (created by build)
├── tests/ # Test files
├── Makefile # Convenient build targets
├── VERSION # Version number
└── shellforge # Final built script
- Release (default): Standard build with production optimizations
- Debug: Includes source file markers and all comments for debugging
- Minimal: Strips all comments for smallest file size
The build script (build/build.sh) performs the following:
- Validates syntax of all source files
- Concatenates files in dependency order
- Strips duplicate shebangs
- Adds build metadata (version, timestamp, git hash)
- Applies mode-specific transformations
- Creates executable output
- Validates final script syntax
# Build release version
make
# Build debug version
make debug
# Build minimal version
make minimal
# Install to ~/bin
make install
# Clean build artifacts
make clean
# Run tests
make test
# Create a tagged release
make release
# Bump version interactively
make bump-version
# Watch for changes and auto-rebuild (requires inotify-tools)
make watch# Build release version
./build/build.sh release
# Build debug version
./build/build.sh debug
# Build minimal version
./build/build.sh minimal
# Clean artifacts
./build/build.sh clean- Create new module in
src/modules/ - Add any shared functions to
src/lib/ - Update build script if needed (usually not required)
- Run
maketo build - Test the built script
- Edit the relevant module file
- Run
make debugfor testing with source markers - Run
makefor final build - Test thoroughly
- Module Independence: Each module should be as independent as possible
- Clear Dependencies: If a module needs functions from lib/, that's fine
- Constants First: All constants go in
core/constants.sh - Variables Second: All global variables go in
core/variables.sh - No Circular Dependencies: Modules shouldn't depend on each other
- Document Functions: Add comments explaining what functions do
constants.sh: Readonly arrays and constantsvariables.sh: Global variables and their initializationutils.sh: Basic utility functions used everywheredisplay.sh: All UI-related functions
- Shared functions used by multiple feature modules
- Should be pure functions without side effects when possible
- Named by their primary purpose
- Implement major features (save, restore, list)
- Can use functions from core/ and lib/
- Should not depend on other feature modules
The modular structure enables future enhancements like:
- Feature Flags: Include/exclude modules at build time
- Platform-Specific Builds: Create macOS-only or Linux-only versions
- Module Metadata: Declare dependencies and requirements
- Tree Shaking: Remove unused functions automatically
- Compression: Create self-extracting versions for very large scripts
- Multiple Targets: Build bash-only or zsh-only versions
To add a new build profile, edit build/build.sh and add a case in the process_build_mode() function.
- Easier Maintenance: Find and fix issues quickly
- Better Organization: Related code is grouped together
- Cleaner Git History: Changes are isolated to specific modules
- Easier Testing: Test individual modules
- Simpler Contributions: New contributors can focus on one module
- Flexible Builds: Different builds for different needs
- Development Features: Debug builds help troubleshooting
The functionality remains identical - the modular system just reorganizes the code for better development experience. The final built script is still a single, self-contained shell script that works anywhere bash/zsh is available.