# -*- mode: python ; coding: utf-8 -*- import os import sys block_cipher = None a = 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', ], 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, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.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, ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, 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)