mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 16:44:33 +00:00
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>
233 lines
5.7 KiB
Markdown
233 lines
5.7 KiB
Markdown
# Docker Build Fix for PyInstaller Bundle
|
|
|
|
## Problem
|
|
|
|
When the Prole Installer is packaged with PyInstaller and run as a standalone binary, Docker builds fail with the error:
|
|
|
|
```
|
|
Building prole-db:17.7-037 in /var/folders/rt/pywlnmxj3dn7t5552vwdcpp80000gn/T/_MEIGozuj4/prole-db...
|
|
```
|
|
|
|
The build hangs or fails because:
|
|
|
|
1. PyInstaller extracts resources to a temporary read-only directory (`/tmp/_MEIxxxxxx/`)
|
|
2. Docker build requires a writable context directory
|
|
3. The temporary directory has restrictive permissions
|
|
4. Docker cannot create the build context properly
|
|
|
|
## Solution
|
|
|
|
Copy the Docker build context to a writable user directory before building.
|
|
|
|
### Implementation
|
|
|
|
**Location:** `install.py`, `run_db_build()` method (line ~1791)
|
|
|
|
**Before:**
|
|
```python
|
|
def worker():
|
|
tag = self.get_prole_db_version()
|
|
cwd = PROJECT_ROOT / "prole-db" # ✗ Points to read-only _MEIPASS
|
|
|
|
cmd = ['docker', 'build', '-t', f"prole-db:{tag}", '.']
|
|
proc = subprocess.Popen(cmd, cwd=cwd, ...)
|
|
```
|
|
|
|
**After:**
|
|
```python
|
|
def worker():
|
|
tag = self.get_prole_db_version()
|
|
|
|
# Use $HOME/.prole/build for Docker build context
|
|
prole_home = Path.home() / ".prole"
|
|
build_dir = prole_home / "build" / "prole-db"
|
|
build_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Copy prole-db directory to writable location
|
|
source_dir = get_resource_path("prole-db")
|
|
if source_dir.exists():
|
|
import shutil
|
|
if build_dir.exists():
|
|
shutil.rmtree(build_dir)
|
|
shutil.copytree(source_dir, build_dir)
|
|
|
|
cwd = build_dir # ✓ Writable user directory
|
|
|
|
cmd = ['docker', 'build', '-t', f"prole-db:{tag}", '.']
|
|
proc = subprocess.Popen(cmd, cwd=cwd, ...)
|
|
```
|
|
|
|
## Directory Structure
|
|
|
|
The installer now creates and uses:
|
|
|
|
```
|
|
$HOME/.prole/
|
|
└── build/
|
|
└── prole-db/ # Docker build context
|
|
├── Dockerfile
|
|
├── conf/
|
|
├── scripts/
|
|
└── ...
|
|
```
|
|
|
|
## Why This Works
|
|
|
|
1. **Writable Location:** `$HOME/.prole/` is user-writable
|
|
2. **Persistent:** Files remain between runs (can be cached)
|
|
3. **Clean State:** Each build starts fresh (old dir removed)
|
|
4. **Docker Compatible:** Standard directory Docker can access
|
|
|
|
## Resource Path Resolution
|
|
|
|
The `prole-db` directory is:
|
|
- **Included in spec:** `('prole-db', 'prole-db')`
|
|
- **Extracted by PyInstaller:** To `_MEIPASS/prole-db/`
|
|
- **Copied to writable location:** `$HOME/.prole/build/prole-db/`
|
|
- **Used for build:** Docker builds from writable copy
|
|
|
|
## Performance
|
|
|
|
**First Build:**
|
|
- Copy prole-db (~1-5 MB): < 1 second
|
|
- Docker build: 30-60 seconds (varies)
|
|
|
|
**Subsequent Builds:**
|
|
- Directory recreation: < 1 second
|
|
- Docker build: May use layer cache
|
|
|
|
## Testing
|
|
|
|
### Test from Source
|
|
```bash
|
|
python3 install.py --gui
|
|
# Navigate to "Build Container" screen
|
|
# Click "Build Database Image"
|
|
# Should succeed without hanging
|
|
```
|
|
|
|
### Test from Package
|
|
```bash
|
|
make package
|
|
./dist/Prole\ Installer.app/Contents/MacOS/prole-installer --gui
|
|
# Navigate to "Build Container" screen
|
|
# Click "Build Database Image"
|
|
# Should create ~/.prole/build/prole-db and succeed
|
|
```
|
|
|
|
### Verify Directory Creation
|
|
```bash
|
|
# After build starts
|
|
ls -la ~/.prole/build/prole-db/
|
|
# Should show Dockerfile and other files
|
|
```
|
|
|
|
## Cleanup
|
|
|
|
The build directory persists after the installer exits. To clean up:
|
|
|
|
```bash
|
|
rm -rf ~/.prole/build
|
|
```
|
|
|
|
Or include in the installer:
|
|
|
|
```python
|
|
def cleanup_build_dirs():
|
|
"""Clean up temporary build directories."""
|
|
build_dir = Path.home() / ".prole" / "build"
|
|
if build_dir.exists():
|
|
shutil.rmtree(build_dir)
|
|
```
|
|
|
|
## Other Potential Issues
|
|
|
|
If Docker build still hangs, check:
|
|
|
|
1. **Docker daemon running:**
|
|
```bash
|
|
docker info
|
|
```
|
|
|
|
2. **Docker context accessible:**
|
|
```bash
|
|
ls -la ~/.prole/build/prole-db/Dockerfile
|
|
```
|
|
|
|
3. **Disk space:**
|
|
```bash
|
|
df -h ~
|
|
```
|
|
|
|
4. **Docker permissions:**
|
|
```bash
|
|
docker ps
|
|
# Should not require sudo
|
|
```
|
|
|
|
## Alternative Solutions Considered
|
|
|
|
### 1. Use /tmp with Unique Names
|
|
```python
|
|
import tempfile
|
|
build_dir = Path(tempfile.mkdtemp(prefix="prole-build-"))
|
|
```
|
|
**Pros:** Automatic cleanup
|
|
**Cons:** Lost between runs, no caching
|
|
|
|
### 2. Build in Place (_MEIPASS)
|
|
```python
|
|
cwd = get_resource_path("prole-db")
|
|
```
|
|
**Pros:** No copying needed
|
|
**Cons:** ✗ Fails due to read-only permissions
|
|
|
|
### 3. Use PROJECT_ROOT for Both
|
|
```python
|
|
cwd = PROJECT_ROOT / "prole-db"
|
|
```
|
|
**Pros:** Works from source
|
|
**Cons:** ✗ Fails from package (_MEIPASS is read-only)
|
|
|
|
### 4. **Chosen: Copy to ~/.prole/build** ✓
|
|
**Pros:** Works from both source and package, writable, persistent
|
|
**Cons:** Requires disk space, manual cleanup
|
|
|
|
## Related Changes
|
|
|
|
- **Spec file updated:** Added `('prole-db', 'prole-db')` to data files
|
|
- **Resource path:** Uses `get_resource_path("prole-db")` for source
|
|
- **Build output:** Console shows build directory location
|
|
|
|
## Future Enhancements
|
|
|
|
1. **Add cleanup option:**
|
|
```python
|
|
# In exit handler or menu
|
|
if messagebox.askyesno("Cleanup", "Remove build directories?"):
|
|
cleanup_build_dirs()
|
|
```
|
|
|
|
2. **Progress indication:**
|
|
```python
|
|
self._db_build_console.write("Copying build context...\n")
|
|
shutil.copytree(source_dir, build_dir)
|
|
self._db_build_console.write("Build context ready.\n")
|
|
```
|
|
|
|
3. **Cache detection:**
|
|
```python
|
|
if build_dir.exists() and not force_clean:
|
|
self._db_build_console.write("Using cached build context...\n")
|
|
else:
|
|
shutil.copytree(source_dir, build_dir)
|
|
```
|
|
|
|
## Summary
|
|
|
|
The Docker build now works correctly from both source and packaged binary by:
|
|
1. Creating `~/.prole/build/prole-db/` directory
|
|
2. Copying build context from embedded resources
|
|
3. Running `docker build` in the writable directory
|
|
4. Avoiding PyInstaller's read-only temporary extraction directory
|