# -*- mode: python ; coding: utf-8 -*- """PyInstaller spec for CCMA. Packaged output: - Windows: dist/ccma.exe - Linux: dist/ccma Icon: - On Windows the spec auto-generates build/app.ico from the PNG icon if it does not already exist, so direct PyInstaller and scripted builds behave the same. """ import sys from pathlib import Path from PyInstaller.utils.hooks import collect_data_files block_cipher = None spec_dir = Path(globals().get("SPECPATH", Path.cwd())).resolve() project_root = spec_dir.parent entry_script = project_root / "main.py" package_src = project_root / "src" / "ccma" assets_src = package_src / "assets" app_name_slug = "ccma" win_icon_path = project_root / "build" / "app.ico" png_icon_path = assets_src / "icons" / "ccma.png" if sys.platform == "win32" and not win_icon_path.exists() and png_icon_path.exists(): try: from PIL import Image img = Image.open(png_icon_path).convert("RGBA") win_icon_path.parent.mkdir(parents=True, exist_ok=True) img.save( win_icon_path, format="ICO", sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)], ) print(f"[spec] Generated ICO: {win_icon_path}") except Exception as exc: print(f"[spec] WARNING: ICO generation failed: {exc}") win_icon = str(win_icon_path) if win_icon_path.exists() else None datas: list[tuple[str, str]] = [] if assets_src.exists(): datas.append((str(assets_src), "ccma/assets")) version_file = project_root / "VERSION" if version_file.exists(): datas.append((str(version_file), ".")) datas.append((str(version_file), "ccma")) for optional_pkg in ("ttkbootstrap_icons", "ttkbootstrap_icons_mat"): try: datas += collect_data_files(optional_pkg) except Exception: pass hiddenimports = ["ttkbootstrap_icons", "ttkbootstrap_icons_mat"] a = Analysis( [str(entry_script)], pathex=[str(project_root), str(project_root / "src")], binaries=[], datas=datas, hiddenimports=hiddenimports, hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], 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, a.binaries, a.zipfiles, a.datas, [], name=app_name_slug, debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, icon=win_icon, )