fix(ci): improve release build diagnostics and encoding
- run build.py with UTF-8 env in release workflow - capture full build output to dist/build.log and print it on failure - extend ISCC output decoding in build.py with UTF-16 fallbacks
This commit is contained in:
66
build.py
66
build.py
@@ -4,7 +4,7 @@ import subprocess
|
||||
import sys
|
||||
from app_version import APP_VERSION
|
||||
|
||||
# --- Конфигурация ---
|
||||
# --- Configuration ---
|
||||
APP_NAME = "AnabasisManager"
|
||||
UPDATER_NAME = "AnabasisUpdater"
|
||||
VERSION = APP_VERSION # Единая версия приложения
|
||||
@@ -32,38 +32,38 @@ def write_version_marker():
|
||||
os.makedirs(DIST_DIR, exist_ok=True)
|
||||
with open(marker_path, "w", encoding="utf-8") as f:
|
||||
f.write(str(VERSION).strip() + "\n")
|
||||
print(f"[OK] Обновлен маркер версии: {marker_path}")
|
||||
print(f"[OK] Version marker written: {marker_path}")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Не удалось записать version.txt: {e}")
|
||||
print(f"[ERROR] Failed to write version.txt: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def copy_icon_to_dist():
|
||||
icon_abs_path = os.path.abspath(ICON_PATH)
|
||||
if not os.path.exists(icon_abs_path):
|
||||
print("[WARN] icon.ico не найден, пропуск копирования иконки в dist.")
|
||||
print("[WARN] icon.ico not found, skipping icon copy into dist.")
|
||||
return
|
||||
try:
|
||||
os.makedirs("dist", exist_ok=True)
|
||||
os.makedirs(DIST_DIR, exist_ok=True)
|
||||
shutil.copy2(icon_abs_path, os.path.join("dist", "icon.ico"))
|
||||
shutil.copy2(icon_abs_path, os.path.join(DIST_DIR, "icon.ico"))
|
||||
print("[OK] Иконка скопирована в dist/icon.ico и dist/AnabasisManager/icon.ico")
|
||||
print("[OK] Icon copied to dist/icon.ico and dist/AnabasisManager/icon.ico")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Не удалось скопировать icon.ico в dist: {e}")
|
||||
print(f"[ERROR] Failed to copy icon.ico into dist: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def ensure_project_root():
|
||||
missing = [name for name in SAFE_CLEAN_ROOT_FILES if not os.path.exists(name)]
|
||||
if missing:
|
||||
print("[ERROR] Скрипт нужно запускать из корня проекта.")
|
||||
print(f"[ERROR] Не найдены: {', '.join(missing)}")
|
||||
print("[ERROR] Run this script from the project root.")
|
||||
print(f"[ERROR] Missing files: {', '.join(missing)}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_build():
|
||||
print(f"--- 1. Запуск PyInstaller для {APP_NAME} v{VERSION} ---")
|
||||
print(f"--- 1. Running PyInstaller for {APP_NAME} v{VERSION} ---")
|
||||
icon_abs_path = os.path.abspath(ICON_PATH)
|
||||
has_icon = os.path.exists(icon_abs_path)
|
||||
|
||||
@@ -86,14 +86,14 @@ def run_build():
|
||||
|
||||
try:
|
||||
subprocess.check_call(command)
|
||||
print("\n[OK] Сборка PyInstaller завершена.")
|
||||
print("\n[OK] PyInstaller build completed.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"\n[ERROR] Ошибка при сборке: {e}")
|
||||
print(f"\n[ERROR] Build failed: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_updater_build():
|
||||
print(f"\n--- 1.2 Сборка {UPDATER_NAME} ---")
|
||||
print(f"\n--- 1.2 Building {UPDATER_NAME} ---")
|
||||
icon_abs_path = os.path.abspath(ICON_PATH)
|
||||
has_icon = os.path.exists(icon_abs_path)
|
||||
updater_spec_dir = os.path.join("build", "updater_spec")
|
||||
@@ -116,14 +116,14 @@ def run_updater_build():
|
||||
command = [arg for arg in command if arg]
|
||||
try:
|
||||
subprocess.check_call(command)
|
||||
print(f"[OK] {UPDATER_NAME} собран.")
|
||||
print(f"[OK] {UPDATER_NAME} built.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"[ERROR] Ошибка при сборке {UPDATER_NAME}: {e}")
|
||||
print(f"[ERROR] Failed to build {UPDATER_NAME}: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def run_cleanup():
|
||||
print(f"\n--- 2. Оптимизация папки {APP_NAME} ---")
|
||||
print(f"\n--- 2. Optimizing {APP_NAME} folder ---")
|
||||
|
||||
# Пытаемся найти папку PySide6 внутри сборки
|
||||
pyside_path = os.path.join(DIST_DIR, "PySide6")
|
||||
@@ -138,21 +138,21 @@ def run_cleanup():
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.remove(path)
|
||||
print(f"Удалено: {item}")
|
||||
print(f"Removed: {item}")
|
||||
except Exception as e:
|
||||
print(f"Пропуск {item}: {e}")
|
||||
print(f"Skipped {item}: {e}")
|
||||
|
||||
|
||||
def create_archive():
|
||||
print(f"\n--- 3. Создание архива {ARCHIVE_NAME}.zip ---")
|
||||
print(f"\n--- 3. Creating archive {ARCHIVE_NAME}.zip ---")
|
||||
|
||||
try:
|
||||
# Создаем zip-архив из папки DIST_DIR
|
||||
# base_name - имя файла без расширения, format - 'zip', root_dir - что упаковываем
|
||||
shutil.make_archive(os.path.join("dist", ARCHIVE_NAME), 'zip', DIST_DIR)
|
||||
print(f"[OK] Архив создан: dist/{ARCHIVE_NAME}.zip")
|
||||
print(f"[OK] Archive created: dist/{ARCHIVE_NAME}.zip")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Не удалось создать архив: {e}")
|
||||
print(f"[ERROR] Failed to create archive: {e}")
|
||||
|
||||
|
||||
def _find_iscc():
|
||||
@@ -175,7 +175,7 @@ def _decode_process_output(raw_bytes):
|
||||
return ""
|
||||
if isinstance(raw_bytes, str):
|
||||
return raw_bytes
|
||||
for enc in ("utf-8", "cp1251", "cp866"):
|
||||
for enc in ("utf-8-sig", "utf-16", "utf-16-le", "cp1251", "cp866", "latin-1"):
|
||||
try:
|
||||
return raw_bytes.decode(enc)
|
||||
except Exception:
|
||||
@@ -184,20 +184,20 @@ def _decode_process_output(raw_bytes):
|
||||
|
||||
|
||||
def build_installer():
|
||||
print(f"\n--- 4. Создание установщика {INSTALLER_NAME} ---")
|
||||
print(f"\n--- 4. Building installer {INSTALLER_NAME} ---")
|
||||
if os.name != "nt":
|
||||
print("[INFO] Установщик Inno Setup создается только на Windows. Шаг пропущен.")
|
||||
print("[INFO] Inno Setup installer is built only on Windows. Step skipped.")
|
||||
return
|
||||
if not os.path.exists(INSTALLER_SCRIPT):
|
||||
print(f"[ERROR] Не найден скрипт установщика: {INSTALLER_SCRIPT}")
|
||||
print(f"[ERROR] Installer script not found: {INSTALLER_SCRIPT}")
|
||||
sys.exit(1)
|
||||
if not os.path.exists(DIST_DIR):
|
||||
print(f"[ERROR] Не найдена папка сборки приложения: {DIST_DIR}")
|
||||
print(f"[ERROR] Build output folder not found: {DIST_DIR}")
|
||||
sys.exit(1)
|
||||
iscc_path = _find_iscc()
|
||||
if not iscc_path:
|
||||
print("[ERROR] Не найден Inno Setup Compiler (ISCC.exe).")
|
||||
print("[ERROR] Установите Inno Setup 6 или задайте переменную окружения ISCC_PATH.")
|
||||
print("[ERROR] Inno Setup Compiler (ISCC.exe) not found.")
|
||||
print("[ERROR] Install Inno Setup 6 or set ISCC_PATH environment variable.")
|
||||
sys.exit(1)
|
||||
|
||||
icon_abs_path = os.path.abspath(ICON_PATH)
|
||||
@@ -224,11 +224,11 @@ def build_installer():
|
||||
raise RuntimeError(f"ISCC exited with code {completed.returncode}")
|
||||
installer_path = os.path.join("dist", INSTALLER_NAME)
|
||||
if not os.path.exists(installer_path):
|
||||
print(f"[ERROR] Установщик не создан: {installer_path}")
|
||||
print(f"[ERROR] Installer was not created: {installer_path}")
|
||||
sys.exit(1)
|
||||
print(f"[OK] Установщик создан: {installer_path}")
|
||||
print(f"[OK] Installer created: {installer_path}")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Ошибка при создании установщика: {e}")
|
||||
print(f"[ERROR] Failed to build installer: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ if __name__ == "__main__":
|
||||
build_installer()
|
||||
|
||||
print("\n" + "=" * 30)
|
||||
print("ПРОЦЕСС ЗАВЕРШЕН")
|
||||
print(f"Файл для отправки: dist/{ARCHIVE_NAME}.zip")
|
||||
print(f"Установщик: dist/{INSTALLER_NAME}")
|
||||
print("BUILD COMPLETED")
|
||||
print(f"Release archive: dist/{ARCHIVE_NAME}.zip")
|
||||
print(f"Installer: dist/{INSTALLER_NAME}")
|
||||
print("=" * 30)
|
||||
|
||||
Reference in New Issue
Block a user