last update
This commit is contained in:
172
scripts/build_executable.py
Normal file
172
scripts/build_executable.py
Normal file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Cross-platform build script for EBoek.info Scraper
|
||||
Creates a standalone executable using PyInstaller
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_command(command, description):
|
||||
"""Run a command and handle errors."""
|
||||
print(f"→ {description}...")
|
||||
try:
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"✗ Error: {result.stderr}")
|
||||
return False
|
||||
if result.stdout.strip():
|
||||
print(f" {result.stdout.strip()}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Exception: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""Main build process."""
|
||||
print("=" * 50)
|
||||
print("🚀 EBoek.info Scraper - Executable Builder")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
# Change to project root directory (parent of scripts/)
|
||||
script_dir = Path(__file__).parent
|
||||
project_root = script_dir.parent
|
||||
os.chdir(project_root)
|
||||
print(f"📂 Working from: {project_root}")
|
||||
print()
|
||||
|
||||
# Check Python version
|
||||
if sys.version_info < (3, 8):
|
||||
print("✗ Error: Python 3.8+ required")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if PyInstaller is installed
|
||||
try:
|
||||
import PyInstaller
|
||||
print(f"✓ PyInstaller {PyInstaller.__version__} found")
|
||||
except ImportError:
|
||||
print("→ Installing PyInstaller...")
|
||||
if not run_command(f"{sys.executable} -m pip install pyinstaller", "Installing PyInstaller"):
|
||||
print("✗ Failed to install PyInstaller")
|
||||
sys.exit(1)
|
||||
|
||||
# Clean previous builds
|
||||
print()
|
||||
for directory in ["dist", "build"]:
|
||||
if Path(directory).exists():
|
||||
shutil.rmtree(directory)
|
||||
print(f"✓ Cleaned {directory}/")
|
||||
|
||||
# Determine platform-specific settings
|
||||
is_windows = sys.platform.startswith('win')
|
||||
exe_name = "EBoek_Scraper.exe" if is_windows else "EBoek_Scraper"
|
||||
|
||||
# Build command
|
||||
build_cmd = [
|
||||
f"{sys.executable}", "-m", "PyInstaller",
|
||||
"--onefile",
|
||||
"--windowed",
|
||||
"--name", "EBoek_Scraper",
|
||||
# Hidden imports for PyQt5
|
||||
"--hidden-import", "PyQt5.QtCore",
|
||||
"--hidden-import", "PyQt5.QtGui",
|
||||
"--hidden-import", "PyQt5.QtWidgets",
|
||||
# Hidden imports for Selenium
|
||||
"--hidden-import", "selenium",
|
||||
"--hidden-import", "selenium.webdriver",
|
||||
"--hidden-import", "selenium.webdriver.chrome",
|
||||
"--hidden-import", "selenium.webdriver.chrome.options",
|
||||
"--hidden-import", "selenium.webdriver.common.by",
|
||||
# Hidden imports for our modules
|
||||
"--hidden-import", "core.scraper",
|
||||
"--hidden-import", "core.scraper_thread",
|
||||
"--hidden-import", "core.credentials",
|
||||
"--hidden-import", "gui.main_window",
|
||||
"--hidden-import", "gui.login_dialog",
|
||||
"--hidden-import", "gui.progress_dialog",
|
||||
"--hidden-import", "utils.validators",
|
||||
# Exclude unnecessary modules to reduce size
|
||||
"--exclude-module", "tkinter",
|
||||
"--exclude-module", "matplotlib",
|
||||
"--exclude-module", "numpy",
|
||||
"--exclude-module", "pandas",
|
||||
# Main script
|
||||
"gui_main.py"
|
||||
]
|
||||
|
||||
print()
|
||||
print("🔨 Building executable...")
|
||||
print("📝 This may take a few minutes...")
|
||||
print()
|
||||
|
||||
# Run PyInstaller
|
||||
try:
|
||||
result = subprocess.run(build_cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("✗ Build failed!")
|
||||
print("Error output:")
|
||||
print(result.stderr)
|
||||
|
||||
# Try fallback with spec file
|
||||
print()
|
||||
print("🔄 Trying alternative build with spec file...")
|
||||
spec_cmd = [f"{sys.executable}", "-m", "PyInstaller", "scripts/eboek_scraper.spec"]
|
||||
result = subprocess.run(spec_cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("✗ Alternative build also failed!")
|
||||
print(result.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("✓ Build completed successfully!")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Build failed with exception: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if executable was created
|
||||
exe_path = Path("dist") / exe_name
|
||||
if not exe_path.exists():
|
||||
print(f"✗ Error: Executable not found at {exe_path}")
|
||||
sys.exit(1)
|
||||
|
||||
# Display results
|
||||
file_size = exe_path.stat().st_size / (1024 * 1024) # MB
|
||||
print()
|
||||
print("=" * 50)
|
||||
print("🎉 BUILD SUCCESSFUL!")
|
||||
print("=" * 50)
|
||||
print(f"📂 Executable location: {exe_path}")
|
||||
print(f"📊 File size: {file_size:.1f} MB")
|
||||
print()
|
||||
|
||||
# Platform-specific instructions
|
||||
if is_windows:
|
||||
print("🪟 Windows Instructions:")
|
||||
print(f" • Run: {exe_path}")
|
||||
print(" • Windows may show security warning on first run")
|
||||
print(" • Click 'More Info' → 'Run Anyway' if prompted")
|
||||
else:
|
||||
print("🍎 macOS/Linux Instructions:")
|
||||
print(f" • Run: ./{exe_path}")
|
||||
print(" • macOS may show security warning on first run")
|
||||
print(" • Right-click and select 'Open' to bypass Gatekeeper")
|
||||
|
||||
print()
|
||||
print("📦 Distribution:")
|
||||
print(f" • Share this single file: {exe_name}")
|
||||
print(" • No Python installation required on target machine")
|
||||
print(" • Includes all dependencies (PyQt5, Selenium, etc.)")
|
||||
print()
|
||||
print("✨ Ready for distribution!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user