Major feature additions and infrastructure improvements for the Prole Database Installer, enabling command-line operation and packaged binary distribution. ## Ncurses Terminal Interface - Add installer/ncurses_ui.py: UI primitives (CursesWindow, TerminalConsole, NavFooter, InputField, Checkbox) - Add installer/ncurses_installer.py: Complete terminal UI with all 11 screens - Implement same screen flow as GUI (welcome, deps, network scan, env setup, kerberos, password, build, cluster, scripts, deploy, installer creation) - Add keyboard navigation (arrows, hjkl, vim-style) - Support both GUI and ncurses modes in single binary ## Automatic Display Detection - Add has_display() function to detect GUI availability - Auto-select GUI if display available, ncurses otherwise - Add --gui and --no-gui command-line flags - Fallback to ncurses on GUI failure ## Build System and Packaging - Add Makefile with targets: build, package, clean, test, install - Add scripts/generate_spec.py: PyInstaller spec generator - Add installer.spec: PyInstaller configuration - Automatic PNG to ICNS icon conversion - Create self-contained macOS .app bundle with embedded icon - Support both Intel (x86_64) and Apple Silicon (arm64) ## Embedded Resources - Add get_resource_path() helper for PyInstaller compatibility - Embed all images (proleIcon.png, proleLogo.png, proleLogoSepia.png) - Embed prole-net/prole-scan binary (6.8 MB universal binary) - Embed prole-app/dist/Prole Tools.app (12 MB app bundle) - Embed prole-db/ Docker build context ## Writable Directory Fixes - Create ~/.prole/build/prole-db/ for Docker builds (fixes read-only _MEIPASS) - Create ~/.prole/scan/ for network scan output (fixes API call failures) - Copy build context to writable location before Docker operations - Run prole-scan from writable working directory ## Documentation - docs/build-system.md: Complete build system guide - docs/ncurses-installer.md: Ncurses interface documentation - docs/RELEASE-NOTES.md: Feature overview and release notes - docs/IMAGE-RESOURCES.md: Image resource management - docs/EMBEDDED-RESOURCES.md: Binary and app bundle embedding - docs/DOCKER-BUILD-FIX.md: Docker build hang solution - docs/PROLE-HOME-DIRECTORY.md: ~/.prole directory structure - BUILD.md: Quick build reference ## Key Changes install.py: - Add get_resource_path() for embedded resource resolution - Update image paths to use get_resource_path() - Update Docker build to use ~/.prole/build/prole-db/ - Update network scan to use ~/.prole/scan/ - Add display detection and mode selection - Add --gui and --no-gui argument parsing ## Testing All features tested and verified: - Ncurses interface navigation - Display auto-detection - Resource path resolution - Docker build from package - Network scan from package - Icon conversion and embedding Package size: ~50-100 MB (includes Python runtime, all resources) Disk usage: ~/.prole/ uses ~2-6 MB 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.7 KiB
Image Resource Management
Overview
The Prole Database Installer includes multiple image assets that need to work both when running from source and when packaged as a standalone binary. This document explains how image resources are managed.
Image Assets
The following images are included in the installer:
Primary Assets
- proleIcon.png (1,494,782 bytes) - Application icon
- proleLogo.png (2,190,703 bytes) - Main Prole logo
- proleLogoSepia.png (2,657,956 bytes) - Sepia-toned background logo
- proleLogoBlueprint.png (3,107,147 bytes) - Blueprint style logo
- proleIconblueprint.png (1,570,109 bytes) - Blueprint style icon
Supplementary Assets
- prole-type.gif (599 bytes) - Small typing animation
Resource Path Resolution
The Challenge
When packaging Python applications with PyInstaller, resource files need to be found in two different scenarios:
- Development: Running from source, files are in
PROJECT_ROOT/img/ - Production: Running from bundle, files are in PyInstaller's temporary extraction directory
The Solution
The get_resource_path() function automatically resolves paths correctly in both scenarios:
def get_resource_path(relative_path):
"""Get absolute path to resource, works for dev and for PyInstaller."""
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = Path(sys._MEIPASS)
except AttributeError:
# Running from source
base_path = PROJECT_ROOT
return base_path / relative_path
Usage
All image loading code uses this function:
# Instead of:
bg_path = Path('img/proleLogoSepia.png')
# Use:
bg_path = get_resource_path('img/proleLogoSepia.png')
Implementation Details
Modified Code Locations
The following locations in install.py were updated to use get_resource_path():
-
Background logo loading (line ~191)
bg_path = get_resource_path('img/proleLogoSepia.png') -
Application icon candidates (line ~406)
img_candidates = [ get_resource_path('img/proleIcon.png'), get_resource_path('img/prole-type.png'), get_resource_path('img/prole-type.gif'), get_resource_path('img/Prole.png'), get_resource_path('img/proleLogoSepia.png'), ] -
DMG background image (line ~3820)
bg_img = get_resource_path('img/proleLogoSepia.png')
PyInstaller Configuration
The installer.spec file includes the entire img/ directory in the bundle:
datas = [
('installer', 'installer'),
('conf', 'conf'),
('etc', 'etc'),
('img', 'img'), # All images included
('docs', 'docs'),
]
This ensures all images are:
- Copied into the PyInstaller bundle
- Extracted to the temporary directory at runtime
- Accessible via
sys._MEIPASS / 'img' / filename
Testing
Verify Resource Paths
Run the test script:
python3 test_resource_paths.py
This tests:
- Path resolution from source
- Path resolution simulating PyInstaller environment
- Existence of all image files
Expected output:
✓ App icon
✓ Background logo (sepia)
✓ Main logo
✓ Blueprint logo
✓ Blueprint icon
✓ All tests passed!
Images will be correctly included in PyInstaller build.
Manual Testing
From source:
python3 install.py --gui
# Check that logo appears in background
From built binary:
make package
./dist/Prole\ Installer.app/Contents/MacOS/prole-installer --gui
# Check that logo appears in background
Icon Formats
PNG (Source)
- Format: PNG with transparency
- Resolution: 1024x1024 recommended
- Location:
img/proleIcon.png
ICNS (macOS Bundle)
- Generated by build system from PNG
- Contains multiple resolutions (16x16 through 1024x1024)
- Location:
build/prole.icns(intermediate), embedded in.appbundle - Generated by:
make build/prole.icns
The build system automatically converts PNG to ICNS using macOS tools:
sips -z 512 512 img/proleIcon.png --out build/icon.iconset/icon_512x512.png
iconutil -c icns build/icon.iconset -o build/prole.icns
Background Image Usage
The GUI installer uses proleLogoSepia.png as a subtle background:
- Loading: Image loaded via PIL (Pillow)
- Processing:
- Converted to RGBA
- Blended with white background at 15% opacity
- Creates subtle watermark effect
- Rendering:
- Scaled to fill canvas
- Maintains aspect ratio
- Centered on canvas
Code snippet:
bg_path = get_resource_path('img/proleLogoSepia.png')
if bg_path.exists():
original = Image.open(str(bg_path)).convert('RGBA')
white_bg = Image.new('RGBA', original.size, (255, 255, 255, 255))
self._bg_pil = Image.blend(white_bg, original, 0.15)
Adding New Images
To add new image resources:
- Add image file to
img/directory - Update code to use
get_resource_path():new_img = get_resource_path('img/new_image.png') - No spec changes needed - entire
img/directory is already included - Test with
python3 test_resource_paths.py
Troubleshooting
Image Not Found in Built Binary
Symptom: Image loads from source but not from built .app
Cause: Path hardcoded instead of using get_resource_path()
Solution:
# Wrong:
img_path = PROJECT_ROOT / 'img' / 'logo.png'
# Correct:
img_path = get_resource_path('img/logo.png')
Image Not Showing in GUI
Cause: File doesn't exist or wrong path
Solution: Check with test script:
python3 test_resource_paths.py
Build Size Too Large
Cause: Large images included in bundle
Solution:
- Optimize PNG files:
pngcrush,optipng, etc. - Consider JPEG for photos (PNG for logos/icons)
- Remove unused images from
img/directory
Performance Considerations
Startup Time
PyInstaller extracts bundled resources to a temporary directory on each launch:
- Small images (< 100 KB): Negligible impact
- Large images (> 1 MB): 100-200ms extraction time
- Total time: ~1-2 seconds for all resources
Memory Usage
Images are loaded into memory when displayed:
- proleLogoSepia.png: ~2.6 MB on disk, ~10 MB in memory (RGBA)
- Scaled versions: Additional memory for display size
Optimization
For production, consider:
- Compress images before including
- Use lazy loading (load only when needed)
- Cache scaled versions instead of re-scaling