Embed updater.exe into main.exe (single-file deployment)

- main.spec: include dist/updater.exe in datas (when present)
- main.py: extract embedded updater.exe next to main.exe on launch
- updater_client.py: _MEIPASS fallback to TEMP if extraction fails
- release.ps1: build updater FIRST so main.spec can embed it

Now users can deploy main.exe alone; auto-update still works because
main.exe self-extracts updater.exe on first launch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
KINDNICK
2026-04-30 13:53:31 +09:00
co-authored by Claude Opus 4.7
parent 63c4c955c8
commit d1f6791b96
6 changed files with 86 additions and 12 deletions
+22 -1
View File
@@ -200,8 +200,29 @@ def _current_exe() -> Optional[Path]:
def _find_updater() -> Optional[Path]:
"""updater.exe 찾기. 메인 .exe와 같은 폴더에 있어야 함."""
"""updater.exe 찾기.
1) 메인 .exe와 같은 폴더 (정상 배포 상태)
2) PyInstaller _MEIPASS — main.exe에 내장된 fallback
(main.py 시작 시 _ensure_updater_extracted()가 #1로 복사하므로 평소엔 미사용)
"""
candidate = _exe_dir() / 'updater.exe'
if candidate.exists():
return candidate
# _MEIPASS fallback — main.py 시작 추출이 권한 부족 등으로 실패한 경우
if getattr(sys, 'frozen', False):
meipass = getattr(sys, '_MEIPASS', None)
if meipass:
bundled = Path(meipass) / 'updater.exe'
if bundled.exists():
# 사용자 TEMP 폴더에 복사 (메인 종료 후에도 살아남도록)
import tempfile, shutil
tmp = Path(tempfile.gettempdir()) / 'clockout_updater.exe'
try:
shutil.copy2(str(bundled), str(tmp))
return tmp
except OSError:
pass
return None