diff --git a/BUILD.spec b/BUILD.spec index 602f831..4b02db2 100644 --- a/BUILD.spec +++ b/BUILD.spec @@ -1,34 +1,38 @@ # -*- mode: python ; coding: utf-8 -*- import json +import sys +import os from pathlib import Path +from os import getenv -# Load config.json +# --- Load config.json --- config_path = Path("../config.json") with config_path.open("r", encoding="utf-8") as f: config = json.load(f) -# Extract values +# --- Extract values --- version = config.get("app_version", "0.0.0") arch = config.get("architecture", "x64") python_version = config.get("python_version", "3.x") -os = config.get("app_os", "Windows") -name = config.get("app_name", "Application") +os_name = config.get("app_os", sys.platform) +app_name = config.get("app_name", "Application") -# Construct dynamic name -name = f"{name}-{os}-{arch}-v{version}" +# --- Construct dynamic name --- +name = f"{app_name}-{os_name}-{arch}-v{version}" -# Optional icon path (can still be overridden via environment if needed) -from os import getenv +# --- Optional icon path --- icon = getenv("ICON_PATH", "") -# Data files to bundle +# --- Data files to bundle --- datas = [ ("data/assets/*", "data/assets/"), ("data/", "data/"), - ("config.json", ".") + ("config.json", "."), + (".env", "."), ] binaries = [] +# --- Analysis --- a = Analysis( ["main.py"], pathex=[], @@ -45,6 +49,7 @@ a = Analysis( pyz = PYZ(a.pure) +# --- EXE common to all platforms --- exe = EXE( pyz, a.scripts, @@ -59,10 +64,48 @@ exe = EXE( upx=True, upx_exclude=[], runtime_tmpdir=None, - console=False, + console=False, # pas de terminal par défaut disable_windowed_traceback=False, - argv_emulation=False, + argv_emulation=(sys.platform == "darwin"), # utile sur macOS GUI target_arch=None, codesign_identity=None, entitlements_file=None, ) + +# --- Platform-specific targets --- +if sys.platform == "darwin": + # macOS: wrap EXE in a .app bundle + app = BUNDLE( + exe, + name=f"{name}.app", + icon=icon if icon else None, + bundle_identifier=f"com.example.{app_name.lower()}" + ) + # La dernière variable = objet final PyInstaller doit construire + coll = app + +elif sys.platform.startswith("linux"): + # Linux: keep binary + generate .desktop file + coll = exe + + dist_dir = Path("build") + dist_bin = dist_dir / name + desktop_file = dist_dir / f"{app_name}.desktop" + + desktop_content = f"""[Desktop Entry] +Type=Application +Name={app_name} +Exec={dist_bin} +Icon={icon if icon else "application-default-icon"} +Terminal=false +Categories=Utility; +""" + # Création post-build + os.makedirs(dist_dir, exist_ok=True) + with open(desktop_file, "w", encoding="utf-8") as f: + f.write(desktop_content) + os.chmod(desktop_file, 0o755) + +else: + # Windows: just the exe + coll = exe diff --git a/app/ui/windows/suggestion_window.py b/app/ui/windows/suggestion_window.py index 2d5a136..ff342d5 100644 --- a/app/ui/windows/suggestion_window.py +++ b/app/ui/windows/suggestion_window.py @@ -1,4 +1,4 @@ -from PyQt6.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QPushButton, QLabel, QMessageBox, QHBoxLayout +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QPushButton, QLabel, QHBoxLayout from PyQt6.QtCore import Qt, QThread, pyqtSignal import smtplib, os from email.mime.text import MIMEText @@ -6,9 +6,9 @@ from email.mime.multipart import MIMEMultipart from dotenv import load_dotenv from app.core.main_manager import MainManager, NotificationType from typing import Optional - +import app.utils.paths as path # Load environment variables from .env file -load_dotenv() +load_dotenv(path.resource_path(".env")) class EmailSender(QThread): success = pyqtSignal() diff --git a/tools/build.command b/tools/build.command new file mode 100644 index 0000000..69841f9 --- /dev/null +++ b/tools/build.command @@ -0,0 +1,59 @@ +#!/bin/bash +set -e + +# === PATH SETUP === +PARENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CONFIG_FILE="$PARENT_DIR/config.json" +ENV_FILE="$PARENT_DIR/.env" + +# --- Check .env file --- +if [[ ! -f "$ENV_FILE" ]]; then + echo "[ERROR] .env file not found. Please copy .env.example to .env and configure it." + exit 1 +fi + +# --- Check jq availability --- +if ! command -v jq &>/dev/null; then + echo "[ERROR] 'jq' is required. Install it with: brew install jq" + exit 1 +fi + +# --- Extract values from config.json --- +ICON_PATH=$(jq -r '.icon_path' "$CONFIG_FILE") +APP_NAME=$(jq -r '.app_name' "$CONFIG_FILE") +ARCHITECTURE=$(jq -r '.architecture' "$CONFIG_FILE") + +# --- Extract PYTHON_PATH from .env --- +SYSTEM_PYTHON=$(grep -E "^PYTHON_PATH=" "$ENV_FILE" | cut -d '=' -f2) + +VENV_PATH="$PARENT_DIR/MACenv_$ARCHITECTURE" +EXE_NAME="${APP_NAME}-MacOS-${ARCHITECTURE}" +PYTHON_IN_VENV="$VENV_PATH/bin/python" + +# --- Verify Python existence --- +if [[ ! -x "$SYSTEM_PYTHON" ]]; then + echo "[ERROR] Python not found at: $SYSTEM_PYTHON" + exit 1 +fi + +# --- Check if virtual environment exists --- +if [[ ! -f "$VENV_PATH/bin/activate" ]]; then + echo "[INFO] Virtual environment not found. Creating..." + "$SYSTEM_PYTHON" -m venv "$VENV_PATH" + "$PYTHON_IN_VENV" -m pip install --upgrade pip + "$PYTHON_IN_VENV" -m pip install -r "$PARENT_DIR/requirements.txt" +else + echo "[INFO] Virtual environment found." +fi + +# --- Run PyInstaller --- +"$PYTHON_IN_VENV" -m PyInstaller \ + --distpath "$PARENT_DIR/build" \ + --workpath "$PARENT_DIR/build/dist" \ + --clean \ + "$PARENT_DIR/BUILD.spec" + +# --- Clean build cache --- +rm -rf "$PARENT_DIR/build/dist" + +echo "[INFO] Build complete: $EXE_NAME" \ No newline at end of file diff --git a/tools/open.command b/tools/open.command new file mode 100644 index 0000000..675450f --- /dev/null +++ b/tools/open.command @@ -0,0 +1,59 @@ +#!/bin/bash +set -e + +# Root paths +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CONFIG_FILE="$ROOT_DIR/config.json" +REQUIREMENTS="$ROOT_DIR/requirements.txt" +ENV_FILE="$ROOT_DIR/.env" + +# Check if .env exists +if [[ ! -f "$ENV_FILE" ]]; then + echo "[ERROR] .env file not found. Please copy .env.example to .env and configure it." + exit 1 +fi + +# Extract architecture from config.json (requires jq) +if ! command -v jq &>/dev/null; then + echo "[ERROR] 'jq' is required. Install it with: brew install jq" + exit 1 +fi +ARCHITECTURE=$(jq -r '.architecture' "$CONFIG_FILE") + +# Extract python path from .env +PYTHON_EXEC=$(grep -E "^PYTHON_PATH=" "$ENV_FILE" | cut -d '=' -f2) + +# Construct venv path +ENV_NAME="MACenv_$ARCHITECTURE" +ENV_PATH="$ROOT_DIR/$ENV_NAME" + +# Check python executable +if [[ ! -x "$PYTHON_EXEC" ]]; then + echo "[ERROR] Python not found at: $PYTHON_EXEC" + echo "Please check your .env or installation path." + exit 1 +fi + +# Show info +echo "[INFO] Configuration:" +echo " Python: $PYTHON_EXEC" +echo " Env: $ENV_NAME" + +# Create virtual env if missing +if [[ ! -d "$ENV_PATH/bin" ]]; then + echo "[INFO] Virtual environment not found, creating..." + "$PYTHON_EXEC" -m venv "$ENV_PATH" + echo "[INFO] Installing dependencies..." + "$ENV_PATH/bin/python" -m pip install --upgrade pip + "$ENV_PATH/bin/pip" install -r "$REQUIREMENTS" +else + echo "[INFO] Virtual environment found." +fi + +# Activate and launch VS Code +echo "[INFO] Launching VS Code..." +# shellcheck source=/dev/null +source "$ENV_PATH/bin/activate" +open -a "Visual Studio Code" "$ROOT_DIR" + +exit 0 \ No newline at end of file