#!/bin/bash # ============================================================ # build_installer.sh — Prepare le staging et invoque ISCC # ------------------------------------------------------------ # # Ce script : # 1. Invoque build_package.sh pour generer le package classique # 2. Copie le package dans deploy/build/installer_staging/ # 3. Copie les helpers de l'installeur (uninstall, licence) # 4. Appelle Inno Setup (ISCC.exe) si disponible # (sinon, affiche les instructions pour compiler sous Windows) # # Usage : # ./deploy/installer/build_installer.sh # Build complet # ./deploy/installer/build_installer.sh --stage-only # Prepare le staging uniquement # ./deploy/installer/build_installer.sh --clean # Nettoyer avant # # Pre-requis : # - bash, rsync, zip (pour le package de base) # - Inno Setup 6.2+ installe (Windows ou Wine) pour compiler # # Sur Linux, ISCC.exe peut etre execute via Wine : # wine "/home/dom/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe" Lea.iss # ============================================================ set -euo pipefail # Couleurs GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEPLOY_DIR="$(dirname "$SCRIPT_DIR")" PROJECT_ROOT="$(dirname "$DEPLOY_DIR")" STAGING_DIR="$DEPLOY_DIR/build/installer_staging" RELEASES_DIR="$DEPLOY_DIR/releases" BASE_BUILD_DIR="$DEPLOY_DIR/build/Lea" # Recupere la version depuis config.py VERSION=$(grep -oP 'AGENT_VERSION\s*=\s*"([^"]+)"' "$PROJECT_ROOT/agent_v0/agent_v1/config.py" | grep -oP '"[^"]+"' | tr -d '"' || echo "1.0.0") echo -e "${GREEN}============================================================${NC}" echo -e "${GREEN} Build installeur Inno Setup Lea v${VERSION}${NC}" echo -e "${GREEN}============================================================${NC}" echo "" # --------------------------------------------------------------- # Parsing des arguments # --------------------------------------------------------------- STAGE_ONLY=0 CLEAN=0 for arg in "$@"; do case "$arg" in --stage-only) STAGE_ONLY=1 ;; --clean) CLEAN=1 ;; *) echo "Argument inconnu : $arg" ;; esac done # --------------------------------------------------------------- # 1. Clean optionnel # --------------------------------------------------------------- if [[ $CLEAN -eq 1 ]]; then echo -e "${YELLOW}[0/5] Nettoyage des anciens builds...${NC}" rm -rf "$STAGING_DIR" rm -rf "$BASE_BUILD_DIR" rm -f "$RELEASES_DIR"/Lea-Setup-*.exe echo " OK" echo "" fi mkdir -p "$RELEASES_DIR" # --------------------------------------------------------------- # 2. Build du package de base (reutilise build_package.sh) # --------------------------------------------------------------- echo "[1/5] Build du package de base..." if [[ ! -d "$BASE_BUILD_DIR" ]] || [[ $CLEAN -eq 1 ]]; then bash "$DEPLOY_DIR/build_package.sh" >/dev/null fi if [[ ! -d "$BASE_BUILD_DIR" ]]; then echo -e "${RED} Erreur : $BASE_BUILD_DIR n'a pas ete cree par build_package.sh${NC}" exit 1 fi echo " Package de base pret : $BASE_BUILD_DIR" echo "" # --------------------------------------------------------------- # 3. Copie vers staging # --------------------------------------------------------------- echo "[2/5] Preparation du staging installeur..." rm -rf "$STAGING_DIR" mkdir -p "$STAGING_DIR" # Copie tout sauf config.txt (genere par l'installeur) et install.bat # install.bat est conserve mais sera appele en mode silencieux par ISS rsync -a \ --exclude='__pycache__' \ --exclude='*.pyc' \ --exclude='.venv' \ --exclude='sessions/' \ --exclude='logs/' \ --exclude='test_lea_*' \ --exclude='_test_paused_toast.py' \ --exclude='tools/test_*' \ --exclude='install.bat' \ --exclude='*.bak' \ --exclude='config.txt.bak*' \ "$BASE_BUILD_DIR/" \ "$STAGING_DIR/" # On supprime le config.txt du staging : c'est l'installeur qui le generera rm -f "$STAGING_DIR/config.txt" echo " Staging : $STAGING_DIR" echo " Fichiers : $(find "$STAGING_DIR" -type f | wc -l)" echo "" # --------------------------------------------------------------- # 4. Copie des helpers installeur (uninstall, licence, etc.) # --------------------------------------------------------------- echo "[3/5] Copie des helpers installeur..." cp "$SCRIPT_DIR/uninstall_lea.ps1" "$STAGING_DIR/" 2>/dev/null || true cp "$SCRIPT_DIR/configure_embed.ps1" "$STAGING_DIR/" 2>/dev/null || true cp "$SCRIPT_DIR/LICENSE.txt" "$STAGING_DIR/" 2>/dev/null || true cp "$SCRIPT_DIR/config_template.txt" "$STAGING_DIR/config_template.txt" 2>/dev/null || true echo " Helpers copies" echo "" # --------------------------------------------------------------- # 5. Python embedded (optionnel) # --------------------------------------------------------------- PYTHON_EMBED_SRC="${PYTHON_EMBED_DIR:-$SCRIPT_DIR/python-3.12-embed}" if [[ ! -d "$PYTHON_EMBED_SRC" ]]; then echo -e "${RED}[4/5] ERREUR : Python 3.12 embedded introuvable dans $PYTHON_EMBED_SRC${NC}" echo " L'embed est OBLIGATOIRE (runtime 100% autonome, aucune dependance Python systeme)." echo " Build interrompu." exit 1 fi echo "[4/5] Copie de Python 3.12 embedded..." rsync -a "$PYTHON_EMBED_SRC/" "$STAGING_DIR/python-3.12-embed/" # Validation de la completude de l'embed : un embed incomplet = install cassee chez le client. # La liste doit rester alignee avec configure_embed.ps1 (verification runtime des imports). EMBED="$STAGING_DIR/python-3.12-embed" REQUIRED_EMBED=( "python.exe" "pythonw.exe" "python312._pth" "_tkinter.pyd" "tcl86t.dll" "tk86t.dll" "zlib1.dll" "Lib/site-packages/socketio" "Lib/site-packages/tkinter" "Lib/site-packages/mss" "Lib/site-packages/pynput" "Lib/site-packages/pystray" "Lib/site-packages/plyer" "Lib/site-packages/requests" "Lib/site-packages/PIL" "Lib/site-packages/win32" "Lib/site-packages/httpx" "Lib/site-packages/httpcore" "Lib/site-packages/h11" "Lib/site-packages/anyio" "Lib/site-packages/typing_extensions.py" ) MISSING_EMBED=() for f in "${REQUIRED_EMBED[@]}"; do [[ -e "$EMBED/$f" ]] || MISSING_EMBED+=("$f") done if [[ ${#MISSING_EMBED[@]} -gt 0 ]]; then echo -e "${RED} ERREUR : embed incomplet. Elements manquants :${NC}" printf ' - %s\n' "${MISSING_EMBED[@]}" echo " Build interrompu (le runtime doit etre complet et autonome)." exit 1 fi echo " Python embedded complet inclus (${#REQUIRED_EMBED[@]} elements verifies)" echo "" # --------------------------------------------------------------- # 6. Stage-only : on s'arrete ici # --------------------------------------------------------------- if [[ $STAGE_ONLY -eq 1 ]]; then echo -e "${GREEN} Staging pret. Utiliser ISCC pour compiler :${NC}" echo " ISCC.exe \"$SCRIPT_DIR/Lea.iss\"" echo "" exit 0 fi # --------------------------------------------------------------- # 7. Compilation avec ISCC (si disponible) # --------------------------------------------------------------- echo "[5/5] Compilation Inno Setup..." # Chercher ISCC : natif Linux (rare), Wine, ou WSL ISCC_BIN="" if command -v iscc >/dev/null 2>&1; then ISCC_BIN="iscc" elif command -v ISCC.exe >/dev/null 2>&1; then ISCC_BIN="ISCC.exe" elif command -v wine >/dev/null 2>&1; then # Chemins Wine courants for path in \ "$HOME/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe" \ "$HOME/.wine/drive_c/Program Files/Inno Setup 6/ISCC.exe"; do if [[ -f "$path" ]]; then ISCC_BIN="wine \"$path\"" break fi done fi if [[ -z "$ISCC_BIN" ]]; then echo "" echo -e "${YELLOW} ISCC (Inno Setup Compiler) introuvable.${NC}" echo "" echo " Le staging est pret dans : $STAGING_DIR" echo "" echo " Pour compiler l'installeur, deux options :" echo "" echo " 1) Sur un PC Windows avec Inno Setup 6 installe :" echo " - Copier le dossier deploy/ sur le PC" echo " - Ouvrir deploy/installer/Lea.iss dans Inno Setup" echo " - Cliquer 'Compile' (F9)" echo " - Recuperer deploy/releases/Lea-Setup-v${VERSION}.exe" echo "" echo " 2) Sur Linux avec Wine :" echo " - winetricks innosetup (ou installer le .exe manuellement)" echo " - wine \"\$HOME/.wine/drive_c/Program Files (x86)/Inno Setup 6/ISCC.exe\" \\" echo " \"$SCRIPT_DIR/Lea.iss\"" echo "" exit 0 fi echo " ISCC trouve : $ISCC_BIN" eval "$ISCC_BIN \"$SCRIPT_DIR/Lea.iss\"" # Verification du resultat OUTPUT_EXE="$RELEASES_DIR/Lea-Setup-v${VERSION}.exe" if [[ -f "$OUTPUT_EXE" ]]; then EXE_SIZE=$(du -h "$OUTPUT_EXE" | cut -f1) echo "" echo -e "${GREEN}============================================================${NC}" echo -e "${GREEN} Installeur produit !${NC}" echo -e "${GREEN}============================================================${NC}" echo "" echo " Fichier : $OUTPUT_EXE" echo " Taille : $EXE_SIZE" echo "" echo " Deploiement :" echo " - Signer le .exe avec un certificat code-signing (voir README.md)" echo " - Publier sur : https://lea.labs.laurinebazin.design/downloads/" echo " - Installation silencieuse : Lea-Setup-v${VERSION}.exe /VERYSILENT /CONFIG=enroll.txt" echo "" else echo -e "${RED} Erreur : $OUTPUT_EXE n'a pas ete produit${NC}" exit 1 fi