# -*- mode: python ; coding: utf-8 -*- import os import sys block_cipher = None # Analysis for main application (backend) a_main = Analysis( ['main.py'], pathex=[], binaries=[ # Include snap7.dll - now confirmed to be in project root ('snap7.dll', '.'), ], datas=[ # Include the entire frontend build ('frontend/dist', 'frontend/dist'), # Include configuration directories and schemas ('config', 'config'), # Include core modules ('core', 'core'), # Include utils ('utils', 'utils'), # Include translation files ('translation.json', '.'), ('i18n.js', '.'), ], hiddenimports=[ # Flask and web dependencies 'jinja2.ext', 'flask', 'flask_cors', 'flask_socketio', 'socketio', 'werkzeug', # JSON Schema validation 'jsonschema', 'jsonschema.validators', 'jsonschema._format', 'jsonschema._types', # PLC and system dependencies 'snap7', 'psutil._pswindows', 'psutil._psutil_windows', # Data processing 'pandas', 'numpy', # Threading and networking 'threading', 'socket', 'json', 'csv', 'datetime', 'pathlib', # Core modules (explicit imports) 'core.config_manager', 'core.plc_client', 'core.plc_data_streamer', 'core.event_logger', 'core.instance_manager', 'core.schema_manager', 'core.streamer', 'core.plot_manager', 'core.historical_cache', 'core.performance_monitor', 'core.priority_manager', 'core.rotating_logger', # Utils modules 'utils.csv_validator', 'utils.json_manager', 'utils.symbol_loader', 'utils.symbol_processor', 'utils.instance_manager', ], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[ # Exclude unnecessary packages to reduce size 'matplotlib', 'scipy', 'IPython', 'notebook', 'jupyter', 'tests', 'unittest', 'pydoc', 'doctest', ], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) # Analysis for backend manager (watchdog) a_manager = Analysis( ['backmanager.py'], pathex=[], binaries=[], datas=[ # Include utils for instance management ('utils', 'utils'), ], hiddenimports=[ # System and monitoring dependencies 'psutil', 'psutil._pswindows', 'psutil._psutil_windows', 'requests', 'subprocess', 'logging', 'json', # Utils modules needed by manager 'utils.instance_manager', ], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[ # Exclude heavy packages not needed by manager 'matplotlib', 'scipy', 'IPython', 'notebook', 'jupyter', 'flask', 'snap7', 'pandas', 'numpy', ], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) # Build PYZ files pyz_main = PYZ(a_main.pure, a_main.zipped_data, cipher=block_cipher) pyz_manager = PYZ(a_manager.pure, a_manager.zipped_data, cipher=block_cipher) # Build main backend executable exe_main = EXE( pyz_main, a_main.scripts, [], exclude_binaries=True, name='S7_Streamer_Logger', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, # True para ver los logs del servidor en una consola. disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) # Build backend manager executable exe_manager = EXE( pyz_manager, a_manager.scripts, [], exclude_binaries=True, name='Backend_Manager', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) # Collect all files together - Only include executables and shared dependencies coll = COLLECT( exe_main, exe_manager, a_main.binaries, a_main.zipfiles, a_main.datas, # Don't duplicate manager dependencies since they're minimal strip=False, upx=True, upx_exclude=[], name='main' ) # Post-build: Copy config directory to the same level as the executable import shutil import os def copy_config_external(): """Copy config directory to external location for runtime access""" try: # Get absolute paths current_dir = os.path.abspath('.') source_config = os.path.join(current_dir, 'config') dist_main_dir = os.path.join(current_dir, 'dist', 'main') dest_config = os.path.join(dist_main_dir, 'config') print(f"Current directory: {current_dir}") print(f"Source config: {source_config}") print(f"Destination config: {dest_config}") # Ensure dist/main directory exists os.makedirs(dist_main_dir, exist_ok=True) # Remove existing config if present if os.path.exists(dest_config): shutil.rmtree(dest_config) print(f"Removed existing config at: {dest_config}") # Copy config directory to dist/main/config if os.path.exists(source_config): shutil.copytree(source_config, dest_config) print(f"✓ Config directory copied to: {dest_config}") return True else: print(f"✗ Source config directory not found: {source_config}") return False except Exception as e: print(f"✗ Error copying config directory: {e}") return False # Execute the copy operation copy_config_external() def config_path(relative_path): """Get path to config file, checking external location first when running as executable""" if getattr(sys, 'frozen', False): # Running as executable - config should be at same level as executable executable_dir = os.path.dirname(sys.executable) external_config = os.path.join(executable_dir, 'config', relative_path) if os.path.exists(external_config): return external_config # Fallback to internal config within _internal internal_config = os.path.join(executable_dir, '_internal', 'config', relative_path) if os.path.exists(internal_config): return internal_config raise FileNotFoundError(f"Configuration file not found: {relative_path}") else: # Running as script - use standard path base_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.dirname(base_dir) return os.path.join(project_root, 'config', relative_path)