feature/integracion-cpanel-asrecovery
This commit is contained in:
21
.gitignore
vendored
21
.gitignore
vendored
@@ -25,6 +25,8 @@ MANIFEST
|
|||||||
|
|
||||||
# Virtual Environment
|
# Virtual Environment
|
||||||
venv/
|
venv/
|
||||||
|
venv-windows/
|
||||||
|
venv-linux/
|
||||||
ENV/
|
ENV/
|
||||||
env/
|
env/
|
||||||
|
|
||||||
@@ -35,16 +37,25 @@ env/
|
|||||||
*.swo
|
*.swo
|
||||||
*~
|
*~
|
||||||
|
|
||||||
# Logs
|
# Logs y datos locales
|
||||||
logs/*.log
|
logs/*.log
|
||||||
logs/*.log.*
|
logs/*.log.*
|
||||||
|
|
||||||
# Database
|
|
||||||
data/*.db
|
data/*.db
|
||||||
data/*.db-journal
|
data/*.db-journal
|
||||||
|
config/.env
|
||||||
|
config/data/
|
||||||
|
config/logs/
|
||||||
|
config/odbc/
|
||||||
|
config/7zip/
|
||||||
|
config/.bootstrap_ok
|
||||||
|
config/.autostart_registered
|
||||||
|
|
||||||
# PyInstaller
|
# PyInstaller / empaquetado
|
||||||
*.spec
|
packaging/bundled/
|
||||||
|
dist/installers/
|
||||||
|
|
||||||
|
# Variables de entorno locales
|
||||||
|
.env
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -126,10 +126,10 @@ C:\CloudRestore\
|
|||||||
|
|
||||||
## Para Ejecutar 24/7
|
## Para Ejecutar 24/7
|
||||||
|
|
||||||
1. Inicia la aplicación
|
1. Inicia la aplicación (el motor arranca solo si `CLOUDRESTORE_AUTO_START=true`)
|
||||||
2. Menú Motor → Iniciar
|
2. Cierra la ventana con **X** — se minimiza a la bandeja del sistema
|
||||||
3. Minimiza (se va a la bandeja del sistema)
|
3. La app continuará monitoreando en segundo plano
|
||||||
4. La app continuará monitoreando en segundo plano
|
4. Para salir por completo: bandeja → **Salir** o menú **Archivo → Salir**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -73,19 +73,28 @@ CloudRestoreAS es una aplicación Windows de escritorio desarrollada en Python 3
|
|||||||
python runner.py
|
python runner.py
|
||||||
```
|
```
|
||||||
|
|
||||||
### Opción 2: Ejecutable Empaquetado
|
### Opción 2: Ejecutable portable (recomendado para producción)
|
||||||
|
|
||||||
1. **Generar el ejecutable**
|
**Windows** — generar:
|
||||||
```powershell
|
```powershell
|
||||||
.\build.ps1
|
.\build.ps1
|
||||||
```
|
```
|
||||||
|
Salida: `dist\CloudRestoreAS.exe`
|
||||||
Esto creará `CloudRestoreAS.exe` en la carpeta `dist\`
|
|
||||||
|
|
||||||
2. **Distribuir**
|
**Linux** — generar:
|
||||||
- Copiar `CloudRestoreAS.exe` a la ubicación deseada
|
```bash
|
||||||
- Crear carpetas `data` y `logs` en el mismo directorio
|
./build.sh
|
||||||
- El ejecutable es portable (no requiere instalación)
|
```
|
||||||
|
Salida: `dist/CloudRestoreAS`
|
||||||
|
|
||||||
|
**Desplegar en cada equipo** (sin Python, sin instalador):
|
||||||
|
1. Copiar **solo** el ejecutable a una carpeta.
|
||||||
|
2. Ejecutarlo (doble clic o `./CloudRestoreAS`).
|
||||||
|
3. Se crean automáticamente: `config/`, `Entrada/`, `Procesados/`, `Fallados/`, `Temp/`.
|
||||||
|
4. Editar `config/.env` (URL, token e instancia del panel).
|
||||||
|
5. Reiniciar la aplicación.
|
||||||
|
|
||||||
|
Ver `packaging/LEEME.txt` para instrucciones resumidas.
|
||||||
|
|
||||||
## ⚙️ Configuración Inicial
|
## ⚙️ Configuración Inicial
|
||||||
|
|
||||||
|
|||||||
36
app/config/__init__.py
Normal file
36
app/config/__init__.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
"""Configuración de entorno, bootstrap y arranque."""
|
||||||
|
|
||||||
|
from .bootstrap import ensure_runtime_layout
|
||||||
|
from .env_loader import (
|
||||||
|
apply_env_overrides,
|
||||||
|
get_launch_options,
|
||||||
|
is_panel_configured,
|
||||||
|
load_env_file,
|
||||||
|
)
|
||||||
|
from .odbc_setup import configure_odbc_environment
|
||||||
|
from .autostart import register_autostart_if_requested
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_runtime() -> None:
|
||||||
|
"""Prepara directorios, ODBC y auto-arranque (llamar antes de importar pyodbc)."""
|
||||||
|
ensure_runtime_layout()
|
||||||
|
configure_odbc_environment()
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_env() -> None:
|
||||||
|
"""Post-bootstrap: carga .env y registra auto-arranque si aplica."""
|
||||||
|
load_env_file()
|
||||||
|
register_autostart_if_requested()
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"initialize_runtime",
|
||||||
|
"initialize_env",
|
||||||
|
"ensure_runtime_layout",
|
||||||
|
"load_env_file",
|
||||||
|
"apply_env_overrides",
|
||||||
|
"get_launch_options",
|
||||||
|
"is_panel_configured",
|
||||||
|
"configure_odbc_environment",
|
||||||
|
"register_autostart_if_requested",
|
||||||
|
]
|
||||||
88
app/config/autostart.py
Normal file
88
app/config/autostart.py
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
"""Registro de arranque automático al login (Windows / Linux)."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ..constants import APP_DIR, CONFIG_DIR, IS_WINDOWS
|
||||||
|
from .env_loader import _env_bool, load_env_file
|
||||||
|
|
||||||
|
|
||||||
|
def _marker_path() -> Path:
|
||||||
|
return CONFIG_DIR / ".autostart_registered"
|
||||||
|
|
||||||
|
|
||||||
|
def _executable_command() -> tuple[str, list[str]]:
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
exe = Path(sys.executable).resolve()
|
||||||
|
return str(exe), ["--start-engine"]
|
||||||
|
runner = (APP_DIR / "runner.py").resolve()
|
||||||
|
return sys.executable, [str(runner), "--start-engine"]
|
||||||
|
|
||||||
|
|
||||||
|
def _register_windows(exe: str, args: list[str]) -> None:
|
||||||
|
task_name = "CloudRestoreAS"
|
||||||
|
arg_str = " ".join(f'"{a}"' if " " in a else a for a in args)
|
||||||
|
tr = f'"{exe}" {arg_str}'
|
||||||
|
check = subprocess.run(
|
||||||
|
["schtasks", "/Query", "/TN", task_name],
|
||||||
|
capture_output=True,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW if hasattr(subprocess, "CREATE_NO_WINDOW") else 0,
|
||||||
|
)
|
||||||
|
if check.returncode == 0:
|
||||||
|
return
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
"schtasks",
|
||||||
|
"/Create",
|
||||||
|
"/TN",
|
||||||
|
task_name,
|
||||||
|
"/TR",
|
||||||
|
tr,
|
||||||
|
"/SC",
|
||||||
|
"ONLOGON",
|
||||||
|
"/RL",
|
||||||
|
"LIMITED",
|
||||||
|
"/F",
|
||||||
|
],
|
||||||
|
check=False,
|
||||||
|
creationflags=subprocess.CREATE_NO_WINDOW if hasattr(subprocess, "CREATE_NO_WINDOW") else 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _register_linux(exe: str, args: list[str]) -> None:
|
||||||
|
autostart_dir = Path.home() / ".config" / "autostart"
|
||||||
|
autostart_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
desktop = autostart_dir / "cloudrestoreas.desktop"
|
||||||
|
if desktop.exists():
|
||||||
|
return
|
||||||
|
exec_line = " ".join([exe, *args])
|
||||||
|
content = f"""[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=CloudRestoreAS
|
||||||
|
Comment=Restauración automática SQL Server
|
||||||
|
Exec={exec_line}
|
||||||
|
Path={APP_DIR}
|
||||||
|
Terminal=false
|
||||||
|
X-GNOME-Autostart-enabled=true
|
||||||
|
"""
|
||||||
|
desktop.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def register_autostart_if_requested() -> None:
|
||||||
|
load_env_file()
|
||||||
|
if not _env_bool("CLOUDRESTORE_REGISTER_AUTOSTART", True):
|
||||||
|
return
|
||||||
|
if _marker_path().exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
exe, args = _executable_command()
|
||||||
|
try:
|
||||||
|
if IS_WINDOWS:
|
||||||
|
_register_windows(exe, args)
|
||||||
|
else:
|
||||||
|
_register_linux(exe, args)
|
||||||
|
_marker_path().write_text("ok", encoding="utf-8")
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
83
app/config/bootstrap.py
Normal file
83
app/config/bootstrap.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
"""Creación automática de config/ y carpetas de trabajo."""
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ..constants import (
|
||||||
|
APP_DIR,
|
||||||
|
BUNDLE_DIR,
|
||||||
|
BUNDLED_SOURCE_7ZIP,
|
||||||
|
BUNDLED_SOURCE_ODBC,
|
||||||
|
CONFIG_DIR,
|
||||||
|
DATA_DIR,
|
||||||
|
DIR_ENTRADA,
|
||||||
|
DIR_FALLADOS,
|
||||||
|
DIR_PROCESADOS,
|
||||||
|
DIR_TEMP,
|
||||||
|
ENV_PATH,
|
||||||
|
LOGS_DIR,
|
||||||
|
ODBC_DIR,
|
||||||
|
SEVEN_ZIP_DIR,
|
||||||
|
)
|
||||||
|
from ..db.database import DatabaseManager
|
||||||
|
from .env_loader import render_env_template
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_tree_if_missing(src: Path, dest: Path) -> None:
|
||||||
|
if not src.is_dir() or dest.exists():
|
||||||
|
return
|
||||||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copytree(src, dest)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_env_if_missing() -> None:
|
||||||
|
if ENV_PATH.exists():
|
||||||
|
return
|
||||||
|
template_path = BUNDLE_DIR / "packaging" / "templates" / "env.default"
|
||||||
|
if not template_path.is_file():
|
||||||
|
template_path = APP_DIR / "packaging" / "templates" / "env.default"
|
||||||
|
if template_path.is_file():
|
||||||
|
content = template_path.read_text(encoding="utf-8")
|
||||||
|
content = content.replace("{APP_DIR}", str(APP_DIR))
|
||||||
|
else:
|
||||||
|
content = render_env_template(APP_DIR)
|
||||||
|
ENV_PATH.write_text(content, encoding="utf-8")
|
||||||
|
try:
|
||||||
|
ENV_PATH.chmod(0o600)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_runtime_layout() -> None:
|
||||||
|
"""
|
||||||
|
Idempotente: crea config/, carpetas de trabajo y .env si no existen.
|
||||||
|
No sobrescribe .env ni app.db existentes.
|
||||||
|
"""
|
||||||
|
for directory in (
|
||||||
|
CONFIG_DIR,
|
||||||
|
DATA_DIR,
|
||||||
|
LOGS_DIR,
|
||||||
|
ODBC_DIR,
|
||||||
|
SEVEN_ZIP_DIR,
|
||||||
|
DIR_ENTRADA,
|
||||||
|
DIR_PROCESADOS,
|
||||||
|
DIR_FALLADOS,
|
||||||
|
DIR_TEMP,
|
||||||
|
):
|
||||||
|
directory.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
_write_env_if_missing()
|
||||||
|
|
||||||
|
_copy_tree_if_missing(BUNDLED_SOURCE_7ZIP, SEVEN_ZIP_DIR)
|
||||||
|
_copy_tree_if_missing(BUNDLED_SOURCE_ODBC, ODBC_DIR)
|
||||||
|
|
||||||
|
from ..constants import DB_PATH
|
||||||
|
|
||||||
|
if not DB_PATH.exists():
|
||||||
|
DatabaseManager(DB_PATH)
|
||||||
|
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
marker = CONFIG_DIR / ".bootstrap_ok"
|
||||||
|
if not marker.exists():
|
||||||
|
marker.write_text("ok", encoding="utf-8")
|
||||||
138
app/config/env_loader.py
Normal file
138
app/config/env_loader.py
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
"""Carga de variables desde config/.env."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from ..constants import (
|
||||||
|
APP_DIR,
|
||||||
|
DIR_ENTRADA,
|
||||||
|
DIR_FALLADOS,
|
||||||
|
DIR_PROCESADOS,
|
||||||
|
DIR_TEMP,
|
||||||
|
ENV_PATH,
|
||||||
|
default_seven_zip_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _env_bool(name: str, default: bool = False) -> bool:
|
||||||
|
raw = os.getenv(name, "").strip().lower()
|
||||||
|
if not raw:
|
||||||
|
return default
|
||||||
|
return raw in ("1", "true", "yes", "on")
|
||||||
|
|
||||||
|
|
||||||
|
def load_env_file() -> bool:
|
||||||
|
"""Carga config/.env si existe."""
|
||||||
|
if ENV_PATH.is_file():
|
||||||
|
load_dotenv(ENV_PATH, override=True)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_panel_configured() -> bool:
|
||||||
|
"""True si URL, token e instancia del panel están definidos."""
|
||||||
|
url = os.getenv("CLOUDRESTORE_PANEL_API_URL", "").strip()
|
||||||
|
token = os.getenv("CLOUDRESTORE_PANEL_API_TOKEN", "").strip()
|
||||||
|
instance = os.getenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", "").strip()
|
||||||
|
return bool(url and token and instance)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LaunchOptions:
|
||||||
|
minimized: bool
|
||||||
|
start_engine: bool
|
||||||
|
register_autostart: bool
|
||||||
|
|
||||||
|
|
||||||
|
def get_launch_options() -> LaunchOptions:
|
||||||
|
load_env_file()
|
||||||
|
return LaunchOptions(
|
||||||
|
minimized=_env_bool("CLOUDRESTORE_START_MINIMIZED", False),
|
||||||
|
start_engine=_env_bool("CLOUDRESTORE_AUTO_START", True),
|
||||||
|
register_autostart=_env_bool("CLOUDRESTORE_REGISTER_AUTOSTART", True),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _path_from_env(name: str, default: Path) -> str:
|
||||||
|
value = os.getenv(name, "").strip()
|
||||||
|
return value if value else str(default)
|
||||||
|
|
||||||
|
|
||||||
|
def apply_env_overrides(config: dict) -> dict:
|
||||||
|
"""Aplica variables de entorno sobre la configuración en memoria."""
|
||||||
|
load_env_file()
|
||||||
|
|
||||||
|
paths = config.setdefault("paths", {})
|
||||||
|
paths["input_folder"] = _path_from_env("CLOUDRESTORE_INPUT_FOLDER", DIR_ENTRADA)
|
||||||
|
paths["processed_folder"] = _path_from_env(
|
||||||
|
"CLOUDRESTORE_PROCESSED_FOLDER", DIR_PROCESADOS
|
||||||
|
)
|
||||||
|
paths["failed_folder"] = _path_from_env("CLOUDRESTORE_FAILED_FOLDER", DIR_FALLADOS)
|
||||||
|
paths["extract_folder"] = _path_from_env("CLOUDRESTORE_EXTRACT_FOLDER", DIR_TEMP)
|
||||||
|
data_sql = os.getenv("CLOUDRESTORE_DATA_SQL_FOLDER", "").strip()
|
||||||
|
if data_sql:
|
||||||
|
paths["data_sql_folder"] = data_sql
|
||||||
|
|
||||||
|
seven_zip = os.getenv("CLOUDRESTORE_SEVEN_ZIP_EXE", "").strip()
|
||||||
|
paths["seven_zip_exe"] = seven_zip or default_seven_zip_path()
|
||||||
|
|
||||||
|
panel = config.setdefault("panel", {})
|
||||||
|
api_url = os.getenv("CLOUDRESTORE_PANEL_API_URL", "").strip()
|
||||||
|
if api_url:
|
||||||
|
panel["api_url"] = api_url
|
||||||
|
api_token = os.getenv("CLOUDRESTORE_PANEL_API_TOKEN", "").strip()
|
||||||
|
if api_token:
|
||||||
|
panel["api_token"] = api_token
|
||||||
|
instance = os.getenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", "").strip()
|
||||||
|
if instance:
|
||||||
|
panel["instance_key"] = instance
|
||||||
|
if os.getenv("CLOUDRESTORE_PANEL_VERIFY_SSL"):
|
||||||
|
panel["verify_ssl"] = _env_bool("CLOUDRESTORE_PANEL_VERIFY_SSL", False)
|
||||||
|
|
||||||
|
sql = config.setdefault("sql", {})
|
||||||
|
server = os.getenv("CLOUDRESTORE_SQL_SERVER", "").strip()
|
||||||
|
if server:
|
||||||
|
sql["server"] = server
|
||||||
|
if os.getenv("CLOUDRESTORE_SQL_USERNAME"):
|
||||||
|
sql["username"] = os.getenv("CLOUDRESTORE_SQL_USERNAME", "").strip()
|
||||||
|
if os.getenv("CLOUDRESTORE_SQL_USE_WINDOWS_AUTH"):
|
||||||
|
sql["use_windows_auth"] = _env_bool("CLOUDRESTORE_SQL_USE_WINDOWS_AUTH", False)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def render_env_template(app_dir: Path | None = None) -> str:
|
||||||
|
"""Genera contenido inicial de config/.env."""
|
||||||
|
base = (app_dir or APP_DIR).resolve()
|
||||||
|
sep = "\\" if os.name == "nt" else "/"
|
||||||
|
|
||||||
|
def p(*parts: str) -> str:
|
||||||
|
return sep.join([str(base), *parts])
|
||||||
|
|
||||||
|
return f"""# CloudRestoreAS — configuración local (editar y reiniciar la app)
|
||||||
|
|
||||||
|
# Arranca el motor al abrir (la ventana siempre se muestra salvo START_MINIMIZED=true)
|
||||||
|
CLOUDRESTORE_AUTO_START=true
|
||||||
|
CLOUDRESTORE_START_MINIMIZED=false
|
||||||
|
CLOUDRESTORE_REGISTER_AUTOSTART=true
|
||||||
|
|
||||||
|
# Servicio PANEL_BASES_ANEXO24 (enrutamiento automático de nodos)
|
||||||
|
CLOUDRESTORE_PANEL_API_URL=
|
||||||
|
CLOUDRESTORE_PANEL_API_TOKEN=
|
||||||
|
CLOUDRESTORE_PANEL_INSTANCE_KEY=
|
||||||
|
CLOUDRESTORE_PANEL_VERIFY_SSL=false
|
||||||
|
|
||||||
|
# Carpetas de trabajo
|
||||||
|
CLOUDRESTORE_INPUT_FOLDER={p("Entrada")}
|
||||||
|
CLOUDRESTORE_PROCESSED_FOLDER={p("Procesados")}
|
||||||
|
CLOUDRESTORE_FAILED_FOLDER={p("Fallados")}
|
||||||
|
CLOUDRESTORE_EXTRACT_FOLDER={p("Temp")}
|
||||||
|
|
||||||
|
# SQL local (solo si no usa panel para credenciales)
|
||||||
|
# CLOUDRESTORE_SQL_SERVER=localhost
|
||||||
|
# CLOUDRESTORE_SQL_USERNAME=
|
||||||
|
# CLOUDRESTORE_DATA_SQL_FOLDER=
|
||||||
|
"""
|
||||||
71
app/config/odbc_setup.py
Normal file
71
app/config/odbc_setup.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
"""Configura ODBC portable desde config/odbc/."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ..constants import IS_WINDOWS, ODBC_DIR
|
||||||
|
from ..utils.logger import app_logger
|
||||||
|
|
||||||
|
|
||||||
|
def _write_portable_odbc_ini(odbc_dir: Path) -> None:
|
||||||
|
"""Genera odbcinst.ini mínimo si no existe."""
|
||||||
|
inst = odbc_dir / "odbcinst.ini"
|
||||||
|
if inst.exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
if IS_WINDOWS:
|
||||||
|
driver_path = odbc_dir / "msodbcsql18.dll"
|
||||||
|
if not driver_path.exists():
|
||||||
|
for candidate in odbc_dir.glob("msodbcsql*.dll"):
|
||||||
|
driver_path = candidate
|
||||||
|
break
|
||||||
|
driver_line = str(driver_path.resolve()) if driver_path.exists() else "msodbcsql18.dll"
|
||||||
|
content = f"""[ODBC Driver 18 for SQL Server]
|
||||||
|
Description=Microsoft ODBC Driver 18 for SQL Server
|
||||||
|
Driver={driver_line}
|
||||||
|
UsageCount=1
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
so_path = None
|
||||||
|
for pattern in ("libmsodbcsql-18*.so*", "msodbcsql-18*.so*"):
|
||||||
|
matches = list(odbc_dir.glob(pattern))
|
||||||
|
if matches:
|
||||||
|
so_path = matches[0]
|
||||||
|
break
|
||||||
|
driver_line = str(so_path.resolve()) if so_path else "libmsodbcsql-18.so"
|
||||||
|
content = f"""[ODBC Driver 18 for SQL Server]
|
||||||
|
Description=Microsoft ODBC Driver 18 for SQL Server
|
||||||
|
Driver={driver_line}
|
||||||
|
UsageCount=1
|
||||||
|
"""
|
||||||
|
inst.write_text(content, encoding="utf-8")
|
||||||
|
|
||||||
|
ini = odbc_dir / "odbc.ini"
|
||||||
|
if not ini.exists():
|
||||||
|
ini.write_text("[ODBC Data Sources]\n", encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def configure_odbc_environment() -> None:
|
||||||
|
"""Apunta pyodbc al driver embebido en config/odbc si está disponible."""
|
||||||
|
if not ODBC_DIR.is_dir():
|
||||||
|
return
|
||||||
|
|
||||||
|
lib_dir = ODBC_DIR / "lib"
|
||||||
|
if lib_dir.is_dir():
|
||||||
|
existing = os.environ.get("LD_LIBRARY_PATH", "")
|
||||||
|
lib_path = str(lib_dir.resolve())
|
||||||
|
if lib_path not in existing.split(":"):
|
||||||
|
os.environ["LD_LIBRARY_PATH"] = (
|
||||||
|
f"{lib_path}:{existing}" if existing else lib_path
|
||||||
|
)
|
||||||
|
|
||||||
|
_write_portable_odbc_ini(ODBC_DIR)
|
||||||
|
odbc_sys = str(ODBC_DIR.resolve())
|
||||||
|
os.environ["ODBCSYSINI"] = odbc_sys
|
||||||
|
os.environ["ODBCINI"] = str((ODBC_DIR / "odbc.ini").resolve())
|
||||||
|
|
||||||
|
if IS_WINDOWS:
|
||||||
|
os.environ["PATH"] = odbc_sys + os.pathsep + os.environ.get("PATH", "")
|
||||||
|
|
||||||
|
app_logger.debug(f"ODBC configurado: ODBCSYSINI={odbc_sys}")
|
||||||
106
app/constants.py
106
app/constants.py
@@ -1,13 +1,51 @@
|
|||||||
"""Constantes globales de la aplicación."""
|
"""Constantes globales de la aplicación."""
|
||||||
|
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Rutas base
|
|
||||||
APP_DIR = Path(__file__).parent.parent
|
|
||||||
DATA_DIR = APP_DIR / "data"
|
|
||||||
LOGS_DIR = APP_DIR / "logs"
|
|
||||||
|
|
||||||
# Base de datos
|
def _resolve_app_dir() -> Path:
|
||||||
|
"""Directorio donde vive el ejecutable (persistente)."""
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
return Path(sys.executable).resolve().parent
|
||||||
|
return Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_bundle_dir() -> Path:
|
||||||
|
"""Recursos embebidos en el binario PyInstaller onefile."""
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
return Path(sys._MEIPASS)
|
||||||
|
platform = "windows" if sys.platform == "win32" else "linux"
|
||||||
|
return _resolve_app_dir() / "packaging" / "bundled" / platform
|
||||||
|
|
||||||
|
|
||||||
|
APP_DIR = _resolve_app_dir()
|
||||||
|
CONFIG_DIR = APP_DIR / "config"
|
||||||
|
ENV_PATH = CONFIG_DIR / ".env"
|
||||||
|
DATA_DIR = CONFIG_DIR / "data"
|
||||||
|
LOGS_DIR = CONFIG_DIR / "logs"
|
||||||
|
ODBC_DIR = CONFIG_DIR / "odbc"
|
||||||
|
SEVEN_ZIP_DIR = CONFIG_DIR / "7zip"
|
||||||
|
|
||||||
|
IS_WINDOWS = sys.platform == "win32"
|
||||||
|
BUNDLE_DIR = _resolve_bundle_dir()
|
||||||
|
BUNDLED_SOURCE_7ZIP = BUNDLE_DIR / "bundled" / "7zip"
|
||||||
|
BUNDLED_SOURCE_ODBC = BUNDLE_DIR / "bundled" / "odbc"
|
||||||
|
def _default_7zip_name() -> str:
|
||||||
|
if IS_WINDOWS:
|
||||||
|
return "7z.exe"
|
||||||
|
return "7zz"
|
||||||
|
|
||||||
|
|
||||||
|
BUNDLED_7ZIP_EXE = SEVEN_ZIP_DIR / _default_7zip_name()
|
||||||
|
BUNDLED_7ZIP_FALLBACK = SEVEN_ZIP_DIR / ("7za.exe" if IS_WINDOWS else "7zz")
|
||||||
|
|
||||||
|
# Carpetas de trabajo junto al ejecutable
|
||||||
|
DIR_ENTRADA = APP_DIR / "Entrada"
|
||||||
|
DIR_PROCESADOS = APP_DIR / "Procesados"
|
||||||
|
DIR_FALLADOS = APP_DIR / "Fallados"
|
||||||
|
DIR_TEMP = APP_DIR / "Temp"
|
||||||
|
|
||||||
DB_PATH = DATA_DIR / "app.db"
|
DB_PATH = DATA_DIR / "app.db"
|
||||||
|
|
||||||
# Estados de jobs
|
# Estados de jobs
|
||||||
@@ -21,7 +59,7 @@ class JobStatus:
|
|||||||
FAILED_RESTART = "failed_restart"
|
FAILED_RESTART = "failed_restart"
|
||||||
CANCELLED = "cancelled"
|
CANCELLED = "cancelled"
|
||||||
|
|
||||||
# Niveles de log
|
|
||||||
class LogLevel:
|
class LogLevel:
|
||||||
DEBUG = "DEBUG"
|
DEBUG = "DEBUG"
|
||||||
INFO = "INFO"
|
INFO = "INFO"
|
||||||
@@ -29,7 +67,7 @@ class LogLevel:
|
|||||||
ERROR = "ERROR"
|
ERROR = "ERROR"
|
||||||
CRITICAL = "CRITICAL"
|
CRITICAL = "CRITICAL"
|
||||||
|
|
||||||
# Tipos de paso de job
|
|
||||||
class StepType:
|
class StepType:
|
||||||
STABILITY_CHECK = "stability_check"
|
STABILITY_CHECK = "stability_check"
|
||||||
NODE_MAPPING = "node_mapping"
|
NODE_MAPPING = "node_mapping"
|
||||||
@@ -39,57 +77,63 @@ class StepType:
|
|||||||
FILELIST = "filelist"
|
FILELIST = "filelist"
|
||||||
RESTORE = "restore"
|
RESTORE = "restore"
|
||||||
CLEANUP = "cleanup"
|
CLEANUP = "cleanup"
|
||||||
SFTP_COPY = "sftp_copy" # Transferencia del .bak al servidor SQL externo (SFTP/SSH)
|
SFTP_COPY = "sftp_copy"
|
||||||
FORWARD_ZIP = "forward_zip" # Reenvío del ZIP al input_folder del servidor destino
|
FORWARD_ZIP = "forward_zip"
|
||||||
|
|
||||||
# Configuración por defecto
|
|
||||||
DEFAULT_CONFIG = {
|
def default_seven_zip_path() -> str:
|
||||||
"paths": {
|
for candidate in (BUNDLED_7ZIP_EXE, BUNDLED_7ZIP_FALLBACK):
|
||||||
"input_folder": "",
|
if candidate.exists():
|
||||||
"processed_folder": "",
|
return str(candidate)
|
||||||
"failed_folder": "",
|
return ""
|
||||||
"extract_folder": "",
|
|
||||||
|
|
||||||
|
def default_work_paths() -> dict[str, str]:
|
||||||
|
return {
|
||||||
|
"input_folder": str(DIR_ENTRADA),
|
||||||
|
"processed_folder": str(DIR_PROCESADOS),
|
||||||
|
"failed_folder": str(DIR_FALLADOS),
|
||||||
|
"extract_folder": str(DIR_TEMP),
|
||||||
"data_sql_folder": "",
|
"data_sql_folder": "",
|
||||||
"seven_zip_exe": ""
|
"seven_zip_exe": default_seven_zip_path(),
|
||||||
},
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
"paths": default_work_paths(),
|
||||||
"sql": {
|
"sql": {
|
||||||
"server": "localhost",
|
"server": "localhost",
|
||||||
"use_windows_auth": True,
|
"use_windows_auth": IS_WINDOWS,
|
||||||
"username": "",
|
"username": "",
|
||||||
"password_encrypted": ""
|
"password_encrypted": "",
|
||||||
},
|
},
|
||||||
"concurrency": {
|
"concurrency": {
|
||||||
"extract_workers": 1,
|
"extract_workers": 1,
|
||||||
"restore_workers": 1
|
"restore_workers": 1,
|
||||||
},
|
},
|
||||||
"stability": {
|
"stability": {
|
||||||
"check_enabled": True,
|
"check_enabled": True,
|
||||||
"check_interval_seconds": 5,
|
"check_interval_seconds": 5,
|
||||||
"stable_duration_seconds": 10,
|
"stable_duration_seconds": 10,
|
||||||
"use_ready_marker": False
|
"use_ready_marker": False,
|
||||||
},
|
},
|
||||||
"timeouts": {
|
"timeouts": {
|
||||||
"extract_minutes": 30,
|
"extract_minutes": 30,
|
||||||
"restore_minutes": 60
|
"restore_minutes": 60,
|
||||||
},
|
},
|
||||||
"retries": {
|
"retries": {
|
||||||
"max_attempts": 3,
|
"max_attempts": 3,
|
||||||
"retry_delay_seconds": 60
|
"retry_delay_seconds": 60,
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"dry_run_mode": False,
|
"dry_run_mode": False,
|
||||||
"auto_scan_enabled": True,
|
"auto_scan_enabled": True,
|
||||||
"scan_interval_seconds": 30
|
"scan_interval_seconds": 30,
|
||||||
},
|
},
|
||||||
# Integración con PANEL_BASES_ANEXO24. Si api_url está vacío, CloudRestoreAS
|
|
||||||
# opera en modo local usando la sección "sql" (retrocompatibilidad).
|
|
||||||
"panel": {
|
"panel": {
|
||||||
"api_url": "",
|
"api_url": "",
|
||||||
"api_token": "",
|
"api_token": "",
|
||||||
# Nombre del restore_target en el panel (identidad de este CRA).
|
|
||||||
# Con panel configurado: enrutamiento automático restore_local | forward.
|
|
||||||
"instance_key": "",
|
"instance_key": "",
|
||||||
# False en dev: el panel local usa HTTPS con certificado propio.
|
|
||||||
"verify_ssl": False,
|
"verify_ssl": False,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ from .. import __version__
|
|||||||
from ..db.job_repository import JobRepository
|
from ..db.job_repository import JobRepository
|
||||||
from ..db.event_repository import EventRepository
|
from ..db.event_repository import EventRepository
|
||||||
from ..db.config_repository import ConfigRepository
|
from ..db.config_repository import ConfigRepository
|
||||||
|
from ..config.env_loader import apply_env_overrides, load_env_file
|
||||||
from ..constants import JobStatus, DEFAULT_CONFIG
|
from ..constants import JobStatus, DEFAULT_CONFIG
|
||||||
from ..panel import panel_client
|
from ..panel import panel_client
|
||||||
from ..utils.logger import app_logger
|
from ..utils.logger import app_logger
|
||||||
@@ -50,14 +51,15 @@ class RestoreEngine(QObject):
|
|||||||
app_logger.info("RestoreEngine inicializado")
|
app_logger.info("RestoreEngine inicializado")
|
||||||
|
|
||||||
def _load_config(self) -> dict:
|
def _load_config(self) -> dict:
|
||||||
"""Carga la configuración desde la base de datos."""
|
"""Carga la configuración desde la base de datos y variables de entorno."""
|
||||||
|
load_env_file()
|
||||||
config = ConfigRepository.get("app_config", DEFAULT_CONFIG.copy())
|
config = ConfigRepository.get("app_config", DEFAULT_CONFIG.copy())
|
||||||
|
|
||||||
# Asegurar que tiene todas las claves
|
|
||||||
for key, value in DEFAULT_CONFIG.items():
|
for key, value in DEFAULT_CONFIG.items():
|
||||||
if key not in config:
|
if key not in config:
|
||||||
config[key] = value
|
config[key] = value
|
||||||
|
|
||||||
|
config = apply_env_overrides(config)
|
||||||
self.signals.config_loaded.emit(config)
|
self.signals.config_loaded.emit(config)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|||||||
@@ -335,11 +335,17 @@ class RestoreWorker(QRunnable):
|
|||||||
stderr=stderr[:1000] if stderr else None
|
stderr=stderr[:1000] if stderr else None
|
||||||
)
|
)
|
||||||
|
|
||||||
# Buscar archivo .bak
|
# Buscar archivo .bak. El backup puede venir con terminaciones extra
|
||||||
|
# (p.ej. ".KNOWNWORLD") tanto en el ZIP como en el propio .bak; se
|
||||||
|
# normaliza a "<nodo>.bak". El nodo es siempre el primer segmento del
|
||||||
|
# nombre del archivo de origen.
|
||||||
locate_step_id = JobStepRepository.create(self.job_id, StepType.LOCATE_BAK)
|
locate_step_id = JobStepRepository.create(self.job_id, StepType.LOCATE_BAK)
|
||||||
|
|
||||||
self._bak_path = SevenZipExtractor.find_bak_file(self._extract_dir)
|
node_base = Path(job.source_name).name.split(".")[0].strip() or None
|
||||||
|
self._bak_path = SevenZipExtractor.find_bak_file(
|
||||||
|
self._extract_dir, node_name=node_base
|
||||||
|
)
|
||||||
|
|
||||||
if not self._bak_path:
|
if not self._bak_path:
|
||||||
raise FileNotFoundError("No se encontró archivo .bak en el archivo extraído")
|
raise FileNotFoundError("No se encontró archivo .bak en el archivo extraído")
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
"""Gestión de extracción de archivos con 7-Zip."""
|
"""Gestión de extracción de archivos con 7-Zip."""
|
||||||
|
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ..constants import BUNDLED_7ZIP_EXE, BUNDLED_7ZIP_FALLBACK, IS_WINDOWS
|
||||||
from ..utils.logger import app_logger
|
from ..utils.logger import app_logger
|
||||||
|
|
||||||
|
|
||||||
@@ -25,19 +29,30 @@ class SevenZipExtractor:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _auto_detect_7zip() -> Optional[str]:
|
def _auto_detect_7zip() -> Optional[str]:
|
||||||
"""Auto-detecta la ubicación de 7z.exe."""
|
"""Prioriza 7-Zip embebido; en desarrollo busca en el sistema."""
|
||||||
possible_paths = [
|
for candidate in (BUNDLED_7ZIP_EXE, BUNDLED_7ZIP_FALLBACK):
|
||||||
r"C:\Program Files\7-Zip\7z.exe",
|
if candidate.exists():
|
||||||
r"D:\Program Files\7-Zip\7z.exe",
|
app_logger.info(f"7-Zip embebido: {candidate}")
|
||||||
r"C:\Program Files (x86)\7-Zip\7z.exe",
|
return str(candidate)
|
||||||
r"D:\Program Files (x86)\7-Zip\7z.exe"
|
|
||||||
]
|
if not getattr(sys, "frozen", False):
|
||||||
|
if IS_WINDOWS:
|
||||||
for path in possible_paths:
|
possible_paths = [
|
||||||
if Path(path).exists():
|
r"C:\Program Files\7-Zip\7z.exe",
|
||||||
app_logger.info(f"7-Zip auto-detectado en: {path}")
|
r"C:\Program Files (x86)\7-Zip\7z.exe",
|
||||||
return path
|
]
|
||||||
|
else:
|
||||||
|
possible_paths = []
|
||||||
|
for name in ("7z", "7zz", "7za"):
|
||||||
|
found = shutil.which(name)
|
||||||
|
if found:
|
||||||
|
possible_paths.append(found)
|
||||||
|
|
||||||
|
for path in possible_paths:
|
||||||
|
if Path(path).exists():
|
||||||
|
app_logger.info(f"7-Zip detectado en: {path}")
|
||||||
|
return path
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def extract(
|
def extract(
|
||||||
@@ -134,35 +149,78 @@ class SevenZipExtractor:
|
|||||||
return result.returncode, result.stdout, result.stderr
|
return result.returncode, result.stdout, result.stderr
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_bak_file(extract_dir: str) -> Optional[str]:
|
def find_bak_file(extract_dir: str, node_name: Optional[str] = None) -> Optional[str]:
|
||||||
"""
|
"""
|
||||||
Busca el archivo .bak extraído en el directorio.
|
Busca el backup extraído y, si se indica node_name, lo normaliza a
|
||||||
|
'<node_name>.bak'.
|
||||||
|
|
||||||
|
Tolera terminaciones extra en el nombre (el backup puede venir como
|
||||||
|
'nodo.KNOWNWORLD.bak', 'nodo.bak.unknownworld' o incluso sin extensión
|
||||||
|
'.bak'). Estrategia de búsqueda en orden:
|
||||||
|
1. archivos que terminan exactamente en '.bak'
|
||||||
|
2. si no hay, archivos cuyo nombre contiene '.bak' en cualquier parte
|
||||||
|
3. si no hay, el archivo más grande de la extracción (el backup suele serlo)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
extract_dir: Directorio donde se extrajo
|
extract_dir: Directorio donde se extrajo
|
||||||
|
node_name: Nombre del nodo; si se indica, el backup se renombra a
|
||||||
|
'<node_name>.bak'
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Ruta al archivo .bak o None si no se encuentra
|
Ruta al archivo .bak (ya renombrado si node_name) o None si no hay archivos.
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: Si hay múltiples archivos .bak
|
|
||||||
"""
|
"""
|
||||||
extract_path = Path(extract_dir)
|
extract_path = Path(extract_dir)
|
||||||
bak_files = list(extract_path.rglob("*.bak"))
|
all_files = [p for p in extract_path.rglob("*") if p.is_file()]
|
||||||
|
|
||||||
if not bak_files:
|
if not all_files:
|
||||||
app_logger.error(f"No se encontró archivo .bak en {extract_dir}")
|
app_logger.error(f"No se encontró ningún archivo en {extract_dir}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if len(bak_files) > 1:
|
bak_files = [p for p in all_files if p.suffix.lower() == ".bak"]
|
||||||
# Si hay múltiples, tomar el más reciente
|
if not bak_files:
|
||||||
|
bak_files = [p for p in all_files if ".bak" in p.name.lower()]
|
||||||
|
if not bak_files:
|
||||||
|
largest = max(all_files, key=lambda p: p.stat().st_size)
|
||||||
app_logger.warning(
|
app_logger.warning(
|
||||||
f"Múltiples archivos .bak encontrados ({len(bak_files)}), "
|
"No se encontró archivo con extensión .bak; usando el archivo más "
|
||||||
"seleccionando el más reciente"
|
f"grande de la extracción: {largest.name}"
|
||||||
)
|
)
|
||||||
bak_files.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
bak_files = [largest]
|
||||||
|
|
||||||
bak_path = str(bak_files[0])
|
if len(bak_files) > 1:
|
||||||
|
# Preferir el que empiece con el nombre del nodo; si no, el más reciente.
|
||||||
|
if node_name:
|
||||||
|
prefixed = [
|
||||||
|
p for p in bak_files
|
||||||
|
if p.name.lower().startswith(node_name.lower())
|
||||||
|
]
|
||||||
|
if prefixed:
|
||||||
|
bak_files = prefixed
|
||||||
|
if len(bak_files) > 1:
|
||||||
|
app_logger.warning(
|
||||||
|
f"Múltiples backups encontrados ({len(bak_files)}), "
|
||||||
|
"seleccionando el más reciente"
|
||||||
|
)
|
||||||
|
bak_files.sort(key=lambda p: p.stat().st_mtime, reverse=True)
|
||||||
|
|
||||||
|
bak_file = bak_files[0]
|
||||||
|
|
||||||
|
# Normalizar el nombre a '<node_name>.bak'.
|
||||||
|
if node_name:
|
||||||
|
target = bak_file.parent / f"{node_name}.bak"
|
||||||
|
if bak_file.name != target.name:
|
||||||
|
try:
|
||||||
|
if target.exists() and not bak_file.samefile(target):
|
||||||
|
target.unlink()
|
||||||
|
bak_file = bak_file.rename(target)
|
||||||
|
app_logger.info(f"Backup normalizado a: {bak_file.name}")
|
||||||
|
except OSError as e:
|
||||||
|
# No es fatal para el RESTORE: se continúa con el nombre original.
|
||||||
|
app_logger.error(
|
||||||
|
f"No se pudo renombrar el backup a '{target.name}': {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
bak_path = str(bak_file)
|
||||||
app_logger.info(f"Archivo .bak encontrado: {bak_path}")
|
app_logger.info(f"Archivo .bak encontrado: {bak_path}")
|
||||||
return bak_path
|
return bak_path
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,28 @@ import pyodbc
|
|||||||
from typing import Optional, Tuple, List
|
from typing import Optional, Tuple, List
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from ..utils.logger import app_logger
|
from ..utils.logger import app_logger
|
||||||
|
|
||||||
|
_ODBC_DRIVER_CANDIDATES = (
|
||||||
|
"ODBC Driver 18 for SQL Server",
|
||||||
|
"ODBC Driver 17 for SQL Server",
|
||||||
|
"ODBC Driver 13 for SQL Server",
|
||||||
|
"FreeTDS",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_odbc_driver() -> str:
|
||||||
|
"""Devuelve el primer driver ODBC de SQL Server disponible."""
|
||||||
|
installed = set(pyodbc.drivers())
|
||||||
|
for name in _ODBC_DRIVER_CANDIDATES:
|
||||||
|
if name in installed:
|
||||||
|
return name
|
||||||
|
raise RuntimeError(
|
||||||
|
"No se encontró driver ODBC para SQL Server. "
|
||||||
|
f"Instalados: {', '.join(pyodbc.drivers()) or 'ninguno'}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class LogicalFile:
|
class LogicalFile:
|
||||||
@@ -50,10 +70,13 @@ class SQLServerManager:
|
|||||||
Returns:
|
Returns:
|
||||||
Cadena de conexión ODBC
|
Cadena de conexión ODBC
|
||||||
"""
|
"""
|
||||||
|
driver = resolve_odbc_driver()
|
||||||
parts = [
|
parts = [
|
||||||
f"DRIVER={{ODBC Driver 17 for SQL Server}}",
|
f"DRIVER={{{driver}}}",
|
||||||
f"SERVER={self.server}"
|
f"SERVER={self.server}",
|
||||||
]
|
]
|
||||||
|
if "18" in driver:
|
||||||
|
parts.append("TrustServerCertificate=yes")
|
||||||
|
|
||||||
if database:
|
if database:
|
||||||
parts.append(f"DATABASE={database}")
|
parts.append(f"DATABASE={database}")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
"""Tab de configuración."""
|
"""Tab de configuración."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
|
QWidget, QVBoxLayout, QHBoxLayout, QGroupBox,
|
||||||
QFormLayout, QLineEdit, QPushButton, QSpinBox,
|
QFormLayout, QLineEdit, QPushButton, QSpinBox,
|
||||||
@@ -104,6 +106,12 @@ class ConfigTab(QWidget):
|
|||||||
self.sql_windows_auth_checkbox.setChecked(True)
|
self.sql_windows_auth_checkbox.setChecked(True)
|
||||||
self.sql_windows_auth_checkbox.toggled.connect(self._on_auth_changed)
|
self.sql_windows_auth_checkbox.toggled.connect(self._on_auth_changed)
|
||||||
sql_layout.addRow("Usar Windows Auth:", self.sql_windows_auth_checkbox)
|
sql_layout.addRow("Usar Windows Auth:", self.sql_windows_auth_checkbox)
|
||||||
|
if sys.platform != "win32":
|
||||||
|
self.sql_windows_auth_checkbox.setChecked(False)
|
||||||
|
self.sql_windows_auth_checkbox.setEnabled(False)
|
||||||
|
self.sql_windows_auth_checkbox.setToolTip(
|
||||||
|
"Windows Auth no está disponible en Linux; use SQL Auth."
|
||||||
|
)
|
||||||
|
|
||||||
self.sql_username_input = QLineEdit()
|
self.sql_username_input = QLineEdit()
|
||||||
self.sql_username_input.setEnabled(False)
|
self.sql_username_input.setEnabled(False)
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ class DashboardTab(QWidget):
|
|||||||
title_font.setBold(True)
|
title_font.setBold(True)
|
||||||
title.setFont(title_font)
|
title.setFont(title_font)
|
||||||
layout.addWidget(title)
|
layout.addWidget(title)
|
||||||
|
|
||||||
|
self.panel_warning_label = QLabel("")
|
||||||
|
self.panel_warning_label.setWordWrap(True)
|
||||||
|
self.panel_warning_label.setStyleSheet(
|
||||||
|
"background-color: #fff3cd; color: #856404; padding: 8px; border-radius: 4px;"
|
||||||
|
)
|
||||||
|
self.panel_warning_label.hide()
|
||||||
|
layout.addWidget(self.panel_warning_label)
|
||||||
|
|
||||||
# Grid de estadísticas
|
# Grid de estadísticas
|
||||||
stats_group = QGroupBox("Estadísticas de Jobs")
|
stats_group = QGroupBox("Estadísticas de Jobs")
|
||||||
@@ -94,17 +102,29 @@ class DashboardTab(QWidget):
|
|||||||
times_group.setLayout(times_layout)
|
times_group.setLayout(times_layout)
|
||||||
layout.addWidget(times_group)
|
layout.addWidget(times_group)
|
||||||
|
|
||||||
|
self.engine_status_badge = QLabel("Detenido")
|
||||||
|
badge_font = QFont()
|
||||||
|
badge_font.setPointSize(12)
|
||||||
|
badge_font.setBold(True)
|
||||||
|
self.engine_status_badge.setFont(badge_font)
|
||||||
|
self.engine_status_badge.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
self.engine_status_badge.setStyleSheet(
|
||||||
|
"background-color: #e9ecef; color: #495057; padding: 6px 14px; "
|
||||||
|
"border-radius: 4px;"
|
||||||
|
)
|
||||||
|
layout.addWidget(self.engine_status_badge)
|
||||||
|
|
||||||
# Estado del motor
|
# Estado del motor
|
||||||
motor_group = QGroupBox("Estado del Motor")
|
motor_group = QGroupBox("Estado del Motor")
|
||||||
motor_layout = QHBoxLayout()
|
motor_layout = QHBoxLayout()
|
||||||
|
|
||||||
self.motor_status_label = QLabel("Detenido")
|
self.motor_status_label = QLabel("Detenido")
|
||||||
motor_status_font = QFont()
|
motor_status_font = QFont()
|
||||||
motor_status_font.setPointSize(14)
|
motor_status_font.setPointSize(14)
|
||||||
motor_status_font.setBold(True)
|
motor_status_font.setBold(True)
|
||||||
self.motor_status_label.setFont(motor_status_font)
|
self.motor_status_label.setFont(motor_status_font)
|
||||||
self.motor_status_label.setStyleSheet("color: red;")
|
self.motor_status_label.setStyleSheet("color: red;")
|
||||||
|
|
||||||
motor_layout.addWidget(QLabel("Estado:"))
|
motor_layout.addWidget(QLabel("Estado:"))
|
||||||
motor_layout.addWidget(self.motor_status_label)
|
motor_layout.addWidget(self.motor_status_label)
|
||||||
motor_layout.addStretch()
|
motor_layout.addStretch()
|
||||||
@@ -136,6 +156,7 @@ class DashboardTab(QWidget):
|
|||||||
|
|
||||||
def _load_initial_stats(self):
|
def _load_initial_stats(self):
|
||||||
"""Carga las estadísticas iniciales."""
|
"""Carga las estadísticas iniciales."""
|
||||||
|
self.update_motor_status()
|
||||||
stats = self.engine.get_stats()
|
stats = self.engine.get_stats()
|
||||||
self.update_stats(stats)
|
self.update_stats(stats)
|
||||||
self._refresh_recent_jobs()
|
self._refresh_recent_jobs()
|
||||||
@@ -193,3 +214,40 @@ class DashboardTab(QWidget):
|
|||||||
self.recent_table.setItem(i, 4, status_item)
|
self.recent_table.setItem(i, 4, status_item)
|
||||||
|
|
||||||
self.recent_table.resizeColumnsToContents()
|
self.recent_table.resizeColumnsToContents()
|
||||||
|
|
||||||
|
def update_motor_status(self) -> None:
|
||||||
|
"""Actualiza badge y etiqueta según el estado actual del motor."""
|
||||||
|
if not self.engine.is_running():
|
||||||
|
text = "Detenido"
|
||||||
|
badge_style = (
|
||||||
|
"background-color: #e9ecef; color: #495057; padding: 6px 14px; "
|
||||||
|
"border-radius: 4px;"
|
||||||
|
)
|
||||||
|
label_style = "color: red;"
|
||||||
|
elif self.engine.is_paused():
|
||||||
|
text = "Pausado"
|
||||||
|
badge_style = (
|
||||||
|
"background-color: #fff3cd; color: #856404; padding: 6px 14px; "
|
||||||
|
"border-radius: 4px;"
|
||||||
|
)
|
||||||
|
label_style = "color: orange;"
|
||||||
|
else:
|
||||||
|
text = "Activo"
|
||||||
|
badge_style = (
|
||||||
|
"background-color: #d4edda; color: #155724; padding: 6px 14px; "
|
||||||
|
"border-radius: 4px;"
|
||||||
|
)
|
||||||
|
label_style = "color: green;"
|
||||||
|
|
||||||
|
self.engine_status_badge.setText(f"Motor: {text}")
|
||||||
|
self.engine_status_badge.setStyleSheet(badge_style)
|
||||||
|
self.motor_status_label.setText(text)
|
||||||
|
self.motor_status_label.setStyleSheet(label_style)
|
||||||
|
|
||||||
|
def set_panel_warning(self, message: str) -> None:
|
||||||
|
"""Muestra aviso cuando falta configuración del servicio de bases en config/.env."""
|
||||||
|
if message:
|
||||||
|
self.panel_warning_label.setText(message)
|
||||||
|
self.panel_warning_label.show()
|
||||||
|
else:
|
||||||
|
self.panel_warning_label.hide()
|
||||||
|
|||||||
@@ -2,181 +2,207 @@
|
|||||||
|
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QMainWindow, QWidget, QVBoxLayout, QTabWidget,
|
QMainWindow, QWidget, QVBoxLayout, QTabWidget,
|
||||||
QSystemTrayIcon, QMenu
|
QSystemTrayIcon, QMenu, QMessageBox, QApplication,
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QTimer, Signal
|
from PySide6.QtCore import Qt, QTimer, Signal
|
||||||
from PySide6.QtGui import QIcon, QCloseEvent, QAction
|
from PySide6.QtGui import QCloseEvent, QAction
|
||||||
|
|
||||||
from .dashboard_tab import DashboardTab
|
from .dashboard_tab import DashboardTab
|
||||||
from .jobs_tab import JobsTab
|
from .jobs_tab import JobsTab
|
||||||
from .nodes_tab import NodesTab
|
from .nodes_tab import NodesTab
|
||||||
from .config_tab import ConfigTab
|
from .config_tab import ConfigTab
|
||||||
from .logs_tab import LogsTab
|
from .logs_tab import LogsTab
|
||||||
|
from .tray_assets import load_tray_icon
|
||||||
from ..engine.engine import RestoreEngine
|
from ..engine.engine import RestoreEngine
|
||||||
from ..utils.logger import app_logger
|
from ..utils.logger import app_logger
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
"""Ventana principal de la aplicación."""
|
"""Ventana principal de la aplicación."""
|
||||||
|
|
||||||
# Señal para minimizar a tray
|
|
||||||
minimize_to_tray = Signal()
|
minimize_to_tray = Signal()
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(
|
||||||
|
self,
|
||||||
|
minimized: bool = False,
|
||||||
|
start_engine: bool = False,
|
||||||
|
panel_configured: bool = True,
|
||||||
|
):
|
||||||
"""Inicializa la ventana principal."""
|
"""Inicializa la ventana principal."""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
# Motor de restauración
|
self._start_on_load = start_engine
|
||||||
|
self._minimized_on_load = minimized
|
||||||
|
self._panel_configured = panel_configured
|
||||||
|
self._force_quit = False
|
||||||
|
self._tray_hint_shown = False
|
||||||
|
|
||||||
self.engine = RestoreEngine()
|
self.engine = RestoreEngine()
|
||||||
|
|
||||||
# Configurar ventana
|
|
||||||
self.setWindowTitle("CloudRestoreAS - Restauración Automática SQL Server")
|
self.setWindowTitle("CloudRestoreAS - Restauración Automática SQL Server")
|
||||||
self.setMinimumSize(1200, 800)
|
self.setMinimumSize(1200, 800)
|
||||||
|
|
||||||
# System tray
|
self.tray_icon: QSystemTrayIcon | None = None
|
||||||
self.tray_icon: QSystemTrayIcon = None
|
|
||||||
self._setup_tray()
|
self._setup_tray()
|
||||||
|
|
||||||
# UI
|
|
||||||
self._setup_ui()
|
self._setup_ui()
|
||||||
|
|
||||||
# Conectar señales del motor
|
|
||||||
self._connect_engine_signals()
|
self._connect_engine_signals()
|
||||||
|
|
||||||
# Timer para actualizar stats
|
|
||||||
self.stats_timer = QTimer()
|
self.stats_timer = QTimer()
|
||||||
self.stats_timer.timeout.connect(self._update_stats)
|
self.stats_timer.timeout.connect(self._update_stats)
|
||||||
self.stats_timer.start(5000) # Cada 5 segundos
|
self.stats_timer.start(5000)
|
||||||
|
|
||||||
|
if not self._panel_configured:
|
||||||
|
self.dashboard_tab.set_panel_warning(
|
||||||
|
"Configure la conexión al servicio de bases en config/.env "
|
||||||
|
"(CLOUDRESTORE_PANEL_API_URL, TOKEN e INSTANCE_KEY)."
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._start_on_load:
|
||||||
|
QTimer.singleShot(500, self._start_engine)
|
||||||
|
|
||||||
|
if self._minimized_on_load:
|
||||||
|
QTimer.singleShot(100, self.hide)
|
||||||
|
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
app_logger.info("Ventana principal inicializada")
|
app_logger.info("Ventana principal inicializada")
|
||||||
|
|
||||||
def _setup_ui(self):
|
def _setup_ui(self):
|
||||||
"""Configura la interfaz de usuario."""
|
"""Configura la interfaz de usuario."""
|
||||||
# Widget central
|
|
||||||
central_widget = QWidget()
|
central_widget = QWidget()
|
||||||
self.setCentralWidget(central_widget)
|
self.setCentralWidget(central_widget)
|
||||||
|
|
||||||
# Layout principal
|
|
||||||
layout = QVBoxLayout(central_widget)
|
layout = QVBoxLayout(central_widget)
|
||||||
layout.setContentsMargins(10, 10, 10, 10)
|
layout.setContentsMargins(10, 10, 10, 10)
|
||||||
|
|
||||||
# Tabs
|
|
||||||
self.tabs = QTabWidget()
|
self.tabs = QTabWidget()
|
||||||
|
|
||||||
# Crear tabs
|
|
||||||
self.dashboard_tab = DashboardTab(self.engine)
|
self.dashboard_tab = DashboardTab(self.engine)
|
||||||
self.jobs_tab = JobsTab(self.engine)
|
self.jobs_tab = JobsTab(self.engine)
|
||||||
self.nodes_tab = NodesTab(self.engine)
|
self.nodes_tab = NodesTab(self.engine)
|
||||||
self.config_tab = ConfigTab(self.engine)
|
self.config_tab = ConfigTab(self.engine)
|
||||||
self.logs_tab = LogsTab(self.engine)
|
self.logs_tab = LogsTab(self.engine)
|
||||||
|
|
||||||
# Agregar tabs
|
|
||||||
self.tabs.addTab(self.dashboard_tab, "📊 Dashboard")
|
self.tabs.addTab(self.dashboard_tab, "📊 Dashboard")
|
||||||
self.tabs.addTab(self.jobs_tab, "📋 Jobs")
|
self.tabs.addTab(self.jobs_tab, "📋 Jobs")
|
||||||
self.tabs.addTab(self.nodes_tab, "🔗 Nodos")
|
self.tabs.addTab(self.nodes_tab, "🔗 Nodos")
|
||||||
self.tabs.addTab(self.config_tab, "⚙️ Configuración")
|
self.tabs.addTab(self.config_tab, "⚙️ Configuración")
|
||||||
self.tabs.addTab(self.logs_tab, "📝 Logs")
|
self.tabs.addTab(self.logs_tab, "📝 Logs")
|
||||||
|
|
||||||
layout.addWidget(self.tabs)
|
layout.addWidget(self.tabs)
|
||||||
|
|
||||||
# Menu bar
|
|
||||||
self._setup_menu()
|
self._setup_menu()
|
||||||
|
|
||||||
def _setup_menu(self):
|
def _setup_menu(self):
|
||||||
"""Configura el menú."""
|
"""Configura el menú."""
|
||||||
menubar = self.menuBar()
|
menubar = self.menuBar()
|
||||||
|
|
||||||
# Menú Motor
|
file_menu = menubar.addMenu("Archivo")
|
||||||
|
|
||||||
|
quit_action = QAction("Salir", self)
|
||||||
|
quit_action.triggered.connect(self._quit_application)
|
||||||
|
file_menu.addAction(quit_action)
|
||||||
|
|
||||||
motor_menu = menubar.addMenu("Motor")
|
motor_menu = menubar.addMenu("Motor")
|
||||||
|
|
||||||
self.start_action = QAction("▶️ Iniciar", self)
|
self.start_action = QAction("▶️ Iniciar", self)
|
||||||
self.start_action.triggered.connect(self._start_engine)
|
self.start_action.triggered.connect(self._start_engine)
|
||||||
motor_menu.addAction(self.start_action)
|
motor_menu.addAction(self.start_action)
|
||||||
|
|
||||||
self.pause_action = QAction("⏸️ Pausar", self)
|
self.pause_action = QAction("⏸️ Pausar", self)
|
||||||
self.pause_action.triggered.connect(self._pause_engine)
|
self.pause_action.triggered.connect(self._pause_engine)
|
||||||
self.pause_action.setEnabled(False)
|
self.pause_action.setEnabled(False)
|
||||||
motor_menu.addAction(self.pause_action)
|
motor_menu.addAction(self.pause_action)
|
||||||
|
|
||||||
self.resume_action = QAction("▶️ Continuar", self)
|
self.resume_action = QAction("▶️ Continuar", self)
|
||||||
self.resume_action.triggered.connect(self._resume_engine)
|
self.resume_action.triggered.connect(self._resume_engine)
|
||||||
self.resume_action.setEnabled(False)
|
self.resume_action.setEnabled(False)
|
||||||
motor_menu.addAction(self.resume_action)
|
motor_menu.addAction(self.resume_action)
|
||||||
|
|
||||||
self.stop_action = QAction("⏹️ Detener", self)
|
self.stop_action = QAction("⏹️ Detener", self)
|
||||||
self.stop_action.triggered.connect(self._stop_engine)
|
self.stop_action.triggered.connect(self._stop_engine)
|
||||||
self.stop_action.setEnabled(False)
|
self.stop_action.setEnabled(False)
|
||||||
motor_menu.addAction(self.stop_action)
|
motor_menu.addAction(self.stop_action)
|
||||||
|
|
||||||
motor_menu.addSeparator()
|
motor_menu.addSeparator()
|
||||||
|
|
||||||
self.scan_action = QAction("🔍 Escanear Ahora", self)
|
self.scan_action = QAction("🔍 Escanear Ahora", self)
|
||||||
self.scan_action.triggered.connect(self._scan_now)
|
self.scan_action.triggered.connect(self._scan_now)
|
||||||
motor_menu.addAction(self.scan_action)
|
motor_menu.addAction(self.scan_action)
|
||||||
|
|
||||||
# Menú Ayuda
|
|
||||||
help_menu = menubar.addMenu("Ayuda")
|
help_menu = menubar.addMenu("Ayuda")
|
||||||
|
|
||||||
about_action = QAction("Acerca de", self)
|
about_action = QAction("Acerca de", self)
|
||||||
about_action.triggered.connect(self._show_about)
|
about_action.triggered.connect(self._show_about)
|
||||||
help_menu.addAction(about_action)
|
help_menu.addAction(about_action)
|
||||||
|
|
||||||
def _setup_tray(self):
|
def _setup_tray(self):
|
||||||
"""Configura el icono de bandeja del sistema."""
|
"""Configura el icono de bandeja del sistema."""
|
||||||
# Crear icono (usar un icono por defecto o crear uno simple)
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
||||||
|
app_logger.warning("Bandeja del sistema no disponible en este entorno")
|
||||||
|
return
|
||||||
|
|
||||||
self.tray_icon = QSystemTrayIcon(self)
|
self.tray_icon = QSystemTrayIcon(self)
|
||||||
|
self.tray_icon.setIcon(load_tray_icon())
|
||||||
self.tray_icon.setToolTip("CloudRestoreAS")
|
self.tray_icon.setToolTip("CloudRestoreAS")
|
||||||
|
|
||||||
# Menú del tray
|
|
||||||
tray_menu = QMenu()
|
tray_menu = QMenu()
|
||||||
|
|
||||||
show_action = QAction("Mostrar", self)
|
show_action = QAction("Mostrar", self)
|
||||||
show_action.triggered.connect(self._show_window)
|
show_action.triggered.connect(self._show_window)
|
||||||
tray_menu.addAction(show_action)
|
tray_menu.addAction(show_action)
|
||||||
|
|
||||||
hide_action = QAction("Ocultar", self)
|
hide_action = QAction("Ocultar", self)
|
||||||
hide_action.triggered.connect(self.hide)
|
hide_action.triggered.connect(self.hide)
|
||||||
tray_menu.addAction(hide_action)
|
tray_menu.addAction(hide_action)
|
||||||
|
|
||||||
tray_menu.addSeparator()
|
tray_menu.addSeparator()
|
||||||
|
|
||||||
pause_tray_action = QAction("Pausar", self)
|
pause_tray_action = QAction("Pausar", self)
|
||||||
pause_tray_action.triggered.connect(self._pause_engine)
|
pause_tray_action.triggered.connect(self._pause_engine)
|
||||||
tray_menu.addAction(pause_tray_action)
|
tray_menu.addAction(pause_tray_action)
|
||||||
|
|
||||||
resume_tray_action = QAction("Continuar", self)
|
resume_tray_action = QAction("Continuar", self)
|
||||||
resume_tray_action.triggered.connect(self._resume_engine)
|
resume_tray_action.triggered.connect(self._resume_engine)
|
||||||
tray_menu.addAction(resume_tray_action)
|
tray_menu.addAction(resume_tray_action)
|
||||||
|
|
||||||
tray_menu.addSeparator()
|
tray_menu.addSeparator()
|
||||||
|
|
||||||
quit_action = QAction("Salir", self)
|
quit_tray_action = QAction("Salir", self)
|
||||||
quit_action.triggered.connect(self._quit_application)
|
quit_tray_action.triggered.connect(self._quit_application)
|
||||||
tray_menu.addAction(quit_action)
|
tray_menu.addAction(quit_tray_action)
|
||||||
|
|
||||||
self.tray_icon.setContextMenu(tray_menu)
|
self.tray_icon.setContextMenu(tray_menu)
|
||||||
|
|
||||||
# Doble clic en tray para mostrar/ocultar
|
|
||||||
self.tray_icon.activated.connect(self._on_tray_activated)
|
self.tray_icon.activated.connect(self._on_tray_activated)
|
||||||
|
|
||||||
# Mostrar tray
|
|
||||||
self.tray_icon.show()
|
self.tray_icon.show()
|
||||||
|
|
||||||
def _connect_engine_signals(self):
|
def _connect_engine_signals(self):
|
||||||
"""Conecta las señales del motor."""
|
"""Conecta las señales del motor."""
|
||||||
self.engine.signals.job_created.connect(self._on_job_created)
|
self.engine.signals.job_created.connect(self._on_job_created)
|
||||||
self.engine.signals.stats_updated.connect(self._on_stats_updated)
|
self.engine.signals.stats_updated.connect(self._on_stats_updated)
|
||||||
self.engine.signals.config_loaded.connect(self._on_config_loaded)
|
self.engine.signals.config_loaded.connect(self._on_config_loaded)
|
||||||
|
|
||||||
def closeEvent(self, event: QCloseEvent):
|
def closeEvent(self, event: QCloseEvent):
|
||||||
"""Maneja el evento de cierre de ventana (minimizar a tray)."""
|
"""Minimiza a bandeja al cerrar la ventana (no sale de la aplicación)."""
|
||||||
if self.tray_icon.isVisible():
|
if self._force_quit:
|
||||||
|
event.accept()
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.tray_icon and self.tray_icon.isVisible():
|
||||||
self.hide()
|
self.hide()
|
||||||
event.ignore()
|
event.ignore()
|
||||||
app_logger.info("Ventana minimizada a bandeja del sistema")
|
app_logger.info("Ventana minimizada a bandeja del sistema")
|
||||||
|
if not self._tray_hint_shown:
|
||||||
|
self.tray_icon.showMessage(
|
||||||
|
"CloudRestoreAS sigue en ejecución",
|
||||||
|
"La aplicación está en la bandeja. Use clic derecho → Salir para cerrar.",
|
||||||
|
QSystemTrayIcon.MessageIcon.Information,
|
||||||
|
4000,
|
||||||
|
)
|
||||||
|
self._tray_hint_shown = True
|
||||||
else:
|
else:
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
def _on_tray_activated(self, reason):
|
def _on_tray_activated(self, reason):
|
||||||
"""Maneja la activación del icono de tray."""
|
"""Maneja la activación del icono de tray."""
|
||||||
if reason == QSystemTrayIcon.ActivationReason.DoubleClick:
|
if reason == QSystemTrayIcon.ActivationReason.DoubleClick:
|
||||||
@@ -184,35 +210,56 @@ class MainWindow(QMainWindow):
|
|||||||
self.hide()
|
self.hide()
|
||||||
else:
|
else:
|
||||||
self._show_window()
|
self._show_window()
|
||||||
|
|
||||||
def _show_window(self):
|
def _show_window(self):
|
||||||
"""Muestra la ventana."""
|
"""Muestra la ventana."""
|
||||||
self.show()
|
self.show()
|
||||||
self.activateWindow()
|
self.activateWindow()
|
||||||
self.raise_()
|
self.raise_()
|
||||||
|
|
||||||
|
def _motor_status_text(self) -> str:
|
||||||
|
if not self.engine.is_running():
|
||||||
|
return "Detenido"
|
||||||
|
if self.engine.is_paused():
|
||||||
|
return "Pausado"
|
||||||
|
return "Activo"
|
||||||
|
|
||||||
|
def _update_tray_status(self):
|
||||||
|
"""Actualiza tooltip del icono de bandeja según estado del motor."""
|
||||||
|
if not self.tray_icon:
|
||||||
|
return
|
||||||
|
status = self._motor_status_text()
|
||||||
|
self.tray_icon.setToolTip(f"CloudRestoreAS — Motor: {status}")
|
||||||
|
|
||||||
def _start_engine(self):
|
def _start_engine(self):
|
||||||
"""Inicia el motor."""
|
"""Inicia el motor."""
|
||||||
self.engine.start()
|
self.engine.start()
|
||||||
self.start_action.setEnabled(False)
|
self.start_action.setEnabled(False)
|
||||||
self.pause_action.setEnabled(True)
|
self.pause_action.setEnabled(True)
|
||||||
self.stop_action.setEnabled(True)
|
self.stop_action.setEnabled(True)
|
||||||
|
self.resume_action.setEnabled(False)
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
app_logger.info("Motor iniciado desde UI")
|
app_logger.info("Motor iniciado desde UI")
|
||||||
|
|
||||||
def _pause_engine(self):
|
def _pause_engine(self):
|
||||||
"""Pausa el motor."""
|
"""Pausa el motor."""
|
||||||
self.engine.pause()
|
self.engine.pause()
|
||||||
self.pause_action.setEnabled(False)
|
self.pause_action.setEnabled(False)
|
||||||
self.resume_action.setEnabled(True)
|
self.resume_action.setEnabled(True)
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
app_logger.info("Motor pausado desde UI")
|
app_logger.info("Motor pausado desde UI")
|
||||||
|
|
||||||
def _resume_engine(self):
|
def _resume_engine(self):
|
||||||
"""Reanuda el motor."""
|
"""Reanuda el motor."""
|
||||||
self.engine.resume()
|
self.engine.resume()
|
||||||
self.resume_action.setEnabled(False)
|
self.resume_action.setEnabled(False)
|
||||||
self.pause_action.setEnabled(True)
|
self.pause_action.setEnabled(True)
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
app_logger.info("Motor reanudado desde UI")
|
app_logger.info("Motor reanudado desde UI")
|
||||||
|
|
||||||
def _stop_engine(self):
|
def _stop_engine(self):
|
||||||
"""Detiene el motor."""
|
"""Detiene el motor."""
|
||||||
self.engine.stop()
|
self.engine.stop()
|
||||||
@@ -220,48 +267,53 @@ class MainWindow(QMainWindow):
|
|||||||
self.pause_action.setEnabled(False)
|
self.pause_action.setEnabled(False)
|
||||||
self.resume_action.setEnabled(False)
|
self.resume_action.setEnabled(False)
|
||||||
self.start_action.setEnabled(True)
|
self.start_action.setEnabled(True)
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
app_logger.info("Motor detenido desde UI")
|
app_logger.info("Motor detenido desde UI")
|
||||||
|
|
||||||
def _scan_now(self):
|
def _scan_now(self):
|
||||||
"""Fuerza un escaneo manual."""
|
"""Fuerza un escaneo manual."""
|
||||||
self.engine.scan_now()
|
self.engine.scan_now()
|
||||||
app_logger.info("Escaneo manual solicitado desde UI")
|
app_logger.info("Escaneo manual solicitado desde UI")
|
||||||
|
|
||||||
def _update_stats(self):
|
def _update_stats(self):
|
||||||
"""Actualiza las estadísticas."""
|
"""Actualiza las estadísticas."""
|
||||||
|
self._update_tray_status()
|
||||||
|
self.dashboard_tab.update_motor_status()
|
||||||
if self.engine.is_running():
|
if self.engine.is_running():
|
||||||
stats = self.engine.get_stats()
|
stats = self.engine.get_stats()
|
||||||
self.dashboard_tab.update_stats(stats)
|
self.dashboard_tab.update_stats(stats)
|
||||||
|
|
||||||
def _on_job_created(self, job_id: str):
|
def _on_job_created(self, job_id: str):
|
||||||
"""Maneja la creación de un nuevo job."""
|
"""Maneja la creación de un nuevo job."""
|
||||||
self.jobs_tab.refresh_jobs()
|
self.jobs_tab.refresh_jobs()
|
||||||
self._update_stats()
|
self._update_stats()
|
||||||
|
|
||||||
def _on_stats_updated(self, stats: dict):
|
def _on_stats_updated(self, stats: dict):
|
||||||
"""Maneja la actualización de estadísticas."""
|
"""Maneja la actualización de estadísticas."""
|
||||||
self.dashboard_tab.update_stats(stats)
|
self.dashboard_tab.update_stats(stats)
|
||||||
|
|
||||||
def _on_config_loaded(self, config: dict):
|
def _on_config_loaded(self, config: dict):
|
||||||
"""Maneja la carga de configuración."""
|
"""Maneja la carga de configuración."""
|
||||||
self.config_tab.load_config(config)
|
self.config_tab.load_config(config)
|
||||||
|
|
||||||
def _show_about(self):
|
def _show_about(self):
|
||||||
"""Muestra el diálogo Acerca de."""
|
"""Muestra el diálogo Acerca de."""
|
||||||
from PySide6.QtWidgets import QMessageBox
|
|
||||||
QMessageBox.about(
|
QMessageBox.about(
|
||||||
self,
|
self,
|
||||||
"Acerca de CloudRestoreAS",
|
"Acerca de CloudRestoreAS",
|
||||||
"CloudRestoreAS v1.0.0\n\n"
|
"CloudRestoreAS v1.0.0\n\n"
|
||||||
"Aplicación de restauración automática de bases de datos SQL Server.\n\n"
|
"Aplicación de restauración automática de bases de datos SQL Server.\n\n"
|
||||||
"© 2026 Aduanasoft"
|
"Al cerrar la ventana, la aplicación permanece en la bandeja del sistema.\n"
|
||||||
|
"Use Archivo → Salir o la bandeja → Salir para cerrar por completo.\n\n"
|
||||||
|
"© 2026 Aduanasoft",
|
||||||
)
|
)
|
||||||
|
|
||||||
def _quit_application(self):
|
def _quit_application(self):
|
||||||
"""Sale de la aplicación completamente."""
|
"""Sale de la aplicación completamente."""
|
||||||
app_logger.info("Saliendo de la aplicación")
|
app_logger.info("Saliendo de la aplicación")
|
||||||
|
self._force_quit = True
|
||||||
self.engine.stop()
|
self.engine.stop()
|
||||||
self.tray_icon.hide()
|
if self.tray_icon:
|
||||||
self.close()
|
self.tray_icon.hide()
|
||||||
from PySide6.QtWidgets import QApplication
|
|
||||||
QApplication.quit()
|
QApplication.quit()
|
||||||
|
|||||||
55
app/ui/tray_assets.py
Normal file
55
app/ui/tray_assets.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"""Icono de bandeja del sistema."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt
|
||||||
|
from PySide6.QtGui import QColor, QIcon, QPainter, QPixmap
|
||||||
|
|
||||||
|
_ASSETS_DIR = Path(__file__).resolve().parent.parent.parent / "packaging" / "assets"
|
||||||
|
|
||||||
|
|
||||||
|
def _generated_tray_icon() -> QIcon:
|
||||||
|
"""Icono simple en memoria si no hay archivo empaquetado."""
|
||||||
|
size = 32
|
||||||
|
pixmap = QPixmap(size, size)
|
||||||
|
pixmap.fill(Qt.GlobalColor.transparent)
|
||||||
|
painter = QPainter(pixmap)
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||||
|
painter.setBrush(QColor(0, 120, 215))
|
||||||
|
painter.setPen(Qt.PenStyle.NoPen)
|
||||||
|
painter.drawRoundedRect(2, 2, size - 4, size - 4, 6, 6)
|
||||||
|
painter.setPen(QColor(255, 255, 255))
|
||||||
|
font = painter.font()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setPointSize(14)
|
||||||
|
painter.setFont(font)
|
||||||
|
painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "C")
|
||||||
|
painter.end()
|
||||||
|
return QIcon(pixmap)
|
||||||
|
|
||||||
|
|
||||||
|
def load_tray_icon() -> QIcon:
|
||||||
|
"""Carga icono de bandeja desde assets empaquetados o genera uno por defecto."""
|
||||||
|
candidates: list[Path] = []
|
||||||
|
meipass = getattr(sys, "_MEIPASS", None)
|
||||||
|
if meipass:
|
||||||
|
base = Path(meipass)
|
||||||
|
candidates.extend(
|
||||||
|
[
|
||||||
|
base / "packaging" / "assets" / "tray-icon.png",
|
||||||
|
base / "packaging" / "assets" / "tray-icon.ico",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
candidates.extend(
|
||||||
|
[
|
||||||
|
_ASSETS_DIR / "tray-icon.png",
|
||||||
|
_ASSETS_DIR / "tray-icon.ico",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for path in candidates:
|
||||||
|
if path.is_file():
|
||||||
|
icon = QIcon(str(path))
|
||||||
|
if not icon.isNull():
|
||||||
|
return icon
|
||||||
|
return _generated_tray_icon()
|
||||||
@@ -1,59 +1,68 @@
|
|||||||
"""Utilidades de cifrado para passwords usando DPAPI en Windows."""
|
"""Utilidades de cifrado para passwords (DPAPI en Windows, Fernet en Linux)."""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import win32crypt
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from ..constants import DATA_DIR
|
||||||
|
|
||||||
|
_IS_WINDOWS = sys.platform == "win32"
|
||||||
|
_SECRET_FILE = DATA_DIR / ".secret"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_fernet():
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
|
||||||
|
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
if not _SECRET_FILE.exists():
|
||||||
|
key = Fernet.generate_key()
|
||||||
|
_SECRET_FILE.write_bytes(key)
|
||||||
|
try:
|
||||||
|
_SECRET_FILE.chmod(0o600)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
key = _SECRET_FILE.read_bytes()
|
||||||
|
return Fernet(key)
|
||||||
|
|
||||||
|
|
||||||
def encrypt_password(password: str) -> str:
|
def encrypt_password(password: str) -> str:
|
||||||
"""
|
"""Cifra una contraseña."""
|
||||||
Cifra una contraseña usando DPAPI de Windows.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
password: Contraseña en texto plano
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Contraseña cifrada en base64
|
|
||||||
"""
|
|
||||||
if not password:
|
if not password:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
encrypted_bytes = win32crypt.CryptProtectData(
|
if _IS_WINDOWS:
|
||||||
password.encode('utf-8'),
|
import win32crypt
|
||||||
None,
|
|
||||||
None,
|
encrypted_bytes = win32crypt.CryptProtectData(
|
||||||
None,
|
password.encode("utf-8"), None, None, None, None, 0
|
||||||
None,
|
)
|
||||||
0
|
return base64.b64encode(encrypted_bytes).decode("ascii")
|
||||||
)
|
|
||||||
return base64.b64encode(encrypted_bytes).decode('ascii')
|
fernet = _get_fernet()
|
||||||
|
return fernet.encrypt(password.encode("utf-8")).decode("ascii")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(f"Error cifrando contraseña: {e}")
|
raise RuntimeError(f"Error cifrando contraseña: {e}") from e
|
||||||
|
|
||||||
|
|
||||||
def decrypt_password(encrypted_password: str) -> str:
|
def decrypt_password(encrypted_password: str) -> str:
|
||||||
"""
|
"""Descifra una contraseña."""
|
||||||
Descifra una contraseña usando DPAPI de Windows.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
encrypted_password: Contraseña cifrada en base64
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Contraseña en texto plano
|
|
||||||
"""
|
|
||||||
if not encrypted_password:
|
if not encrypted_password:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
encrypted_bytes = base64.b64decode(encrypted_password)
|
if _IS_WINDOWS:
|
||||||
decrypted_bytes = win32crypt.CryptUnprotectData(
|
import win32crypt
|
||||||
encrypted_bytes,
|
|
||||||
None,
|
encrypted_bytes = base64.b64decode(encrypted_password)
|
||||||
None,
|
decrypted_bytes = win32crypt.CryptUnprotectData(
|
||||||
None,
|
encrypted_bytes, None, None, None, 0
|
||||||
0
|
)[1]
|
||||||
)[1]
|
return decrypted_bytes.decode("utf-8")
|
||||||
return decrypted_bytes.decode('utf-8')
|
|
||||||
|
fernet = _get_fernet()
|
||||||
|
return fernet.decrypt(encrypted_password.encode("ascii")).decode("utf-8")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise RuntimeError(f"Error descifrando contraseña: {e}")
|
raise RuntimeError(f"Error descifrando contraseña: {e}") from e
|
||||||
|
|||||||
499
build-linux.log
Normal file
499
build-linux.log
Normal file
@@ -0,0 +1,499 @@
|
|||||||
|
debconf: delaying package configuration, since apt-utils is not installed
|
||||||
|
===============================================
|
||||||
|
CloudRestoreAS - Build Linux (onefile)
|
||||||
|
===============================================
|
||||||
|
==> 7-Zip Linux (7zz)
|
||||||
|
7zz ya existe
|
||||||
|
==> ODBC Driver 18 + unixODBC
|
||||||
|
ODBC ya existe
|
||||||
|
Listo: /app/packaging/bundled/linux
|
||||||
|
Ejecutando PyInstaller (onefile)...
|
||||||
|
74 INFO: PyInstaller: 6.20.0, contrib hooks: 2026.6
|
||||||
|
74 INFO: Python: 3.10.12
|
||||||
|
75 INFO: Platform: Linux-6.6.87.2-microsoft-standard-WSL2-x86_64-with-glibc2.35
|
||||||
|
75 INFO: Python environment: /app/venv-linux
|
||||||
|
77 INFO: Removing temporary files and cleaning cache in /root/.cache/pyinstaller
|
||||||
|
89 WARNING: Failed to collect submodules for 'PySide6.scripts.deploy_lib' because importing 'PySide6.scripts.deploy_lib' raised: ModuleNotFoundError: No module named 'project_lib'
|
||||||
|
713 INFO: Module search paths (PYTHONPATH):
|
||||||
|
['/app',
|
||||||
|
'/usr/lib/python310.zip',
|
||||||
|
'/usr/lib/python3.10',
|
||||||
|
'/usr/lib/python3.10/lib-dynload',
|
||||||
|
'/app/venv-linux/lib/python3.10/site-packages',
|
||||||
|
'/app']
|
||||||
|
793 INFO: Appending 'binaries' from .spec
|
||||||
|
797 INFO: Appending 'datas' from .spec
|
||||||
|
854 INFO: checking Analysis
|
||||||
|
854 INFO: Building Analysis because Analysis-00.toc is non existent
|
||||||
|
854 INFO: Looking for Python shared library...
|
||||||
|
861 INFO: Using Python shared library: /lib/x86_64-linux-gnu/libpython3.10.so.1.0
|
||||||
|
861 INFO: Running Analysis Analysis-00.toc
|
||||||
|
861 INFO: Target bytecode optimization level: 0
|
||||||
|
861 INFO: Initializing module dependency graph...
|
||||||
|
861 INFO: Initializing module graph hook caches...
|
||||||
|
867 INFO: Analyzing modules for base_library.zip ...
|
||||||
|
1077 INFO: Processing standard module hook 'hook-heapq.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
1111 INFO: Processing standard module hook 'hook-encodings.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
1770 INFO: Processing standard module hook 'hook-pickle.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
2325 INFO: Caching module dependency graph...
|
||||||
|
2349 INFO: Analyzing /app/runner.py
|
||||||
|
2355 INFO: Processing standard module hook 'hook-sqlite3.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
2595 INFO: Processing standard module hook 'hook-PySide6.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
2687 INFO: Processing standard module hook 'hook-shiboken6.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
2753 INFO: Processing standard module hook 'hook-PySide6.QtNetwork.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
3261 INFO: Processing standard module hook 'hook-PySide6.QtCore.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
3732 INFO: Processing standard module hook 'hook-PySide6.QtWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
4244 INFO: Processing standard module hook 'hook-PySide6.QtGui.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
5411 INFO: Processing standard module hook 'hook-platform.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
5434 INFO: Processing standard module hook 'hook-cryptography.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
6128 INFO: hook-cryptography: cryptography does not seem to be using dynamically linked OpenSSL.
|
||||||
|
6278 INFO: Processing standard module hook 'hook-pyodbc.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
6390 INFO: Processing standard module hook 'hook-urllib3.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
6500 INFO: Processing pre-safe-import-module hook 'hook-backports.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/pre_safe_import_module'
|
||||||
|
6503 INFO: SetuptoolsInfo: initializing cached setuptools info...
|
||||||
|
7023 INFO: Processing pre-safe-import-module hook 'hook-typing_extensions.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/pre_safe_import_module'
|
||||||
|
7167 INFO: Processing standard module hook 'hook-multiprocessing.util.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
7199 INFO: Processing standard module hook 'hook-xml.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
7334 INFO: Processing standard module hook 'hook-_ctypes.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
7979 INFO: Processing standard module hook 'hook-certifi.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
7998 INFO: Processing standard module hook 'hook-charset_normalizer.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
8193 INFO: Processing standard module hook 'hook-bcrypt.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
8489 INFO: Processing standard module hook 'hook-difflib.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
8655 INFO: Processing standard module hook 'hook-nacl.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/stdhooks'
|
||||||
|
8816 INFO: Analyzing hidden import 'PySide6.Qt3DAnimation'
|
||||||
|
8830 INFO: Processing standard module hook 'hook-PySide6.Qt3DAnimation.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
8938 INFO: Processing standard module hook 'hook-PySide6.Qt3DCore.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
9135 INFO: Processing standard module hook 'hook-PySide6.Qt3DRender.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10294 INFO: Processing standard module hook 'hook-PySide6.QtOpenGL.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10400 INFO: Analyzing hidden import 'PySide6.Qt3DExtras'
|
||||||
|
10458 INFO: Processing standard module hook 'hook-PySide6.Qt3DExtras.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10552 INFO: Analyzing hidden import 'PySide6.Qt3DInput'
|
||||||
|
10564 INFO: Processing standard module hook 'hook-PySide6.Qt3DInput.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10645 INFO: Analyzing hidden import 'PySide6.Qt3DLogic'
|
||||||
|
10646 INFO: Processing standard module hook 'hook-PySide6.Qt3DLogic.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10725 INFO: Analyzing hidden import 'PySide6.QtAsyncio'
|
||||||
|
10740 INFO: Analyzing hidden import 'PySide6.QtBluetooth'
|
||||||
|
10770 INFO: Processing standard module hook 'hook-PySide6.QtBluetooth.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
10850 INFO: Analyzing hidden import 'PySide6.QtCanvasPainter'
|
||||||
|
10915 INFO: Processing standard module hook 'hook-PySide6.QtQuick.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
11049 INFO: Processing standard module hook 'hook-PySide6.QtQml.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
--- Logging error ---
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "/usr/lib/python3.10/logging/__init__.py", line 1100, in emit
|
||||||
|
msg = self.format(record)
|
||||||
|
File "/usr/lib/python3.10/logging/__init__.py", line 943, in format
|
||||||
|
return fmt.format(record)
|
||||||
|
File "/usr/lib/python3.10/logging/__init__.py", line 678, in format
|
||||||
|
record.message = record.getMessage()
|
||||||
|
File "/usr/lib/python3.10/logging/__init__.py", line 368, in getMessage
|
||||||
|
msg = msg % self.args
|
||||||
|
TypeError: not enough arguments for format string
|
||||||
|
Call stack:
|
||||||
|
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
|
||||||
|
return _run_code(code, main_globals, None,
|
||||||
|
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
|
||||||
|
exec(code, run_globals)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/__main__.py", line 321, in <module>
|
||||||
|
run()
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/__main__.py", line 215, in run
|
||||||
|
run_build(pyi_config, spec_file, **vars(args))
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/__main__.py", line 70, in run_build
|
||||||
|
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 1275, in main
|
||||||
|
build(specfile, distpath, workpath, clean_build)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 1213, in build
|
||||||
|
exec(code, spec_namespace)
|
||||||
|
File "packaging/CloudRestoreAS.spec", line 59, in <module>
|
||||||
|
a = Analysis(
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 584, in __init__
|
||||||
|
self.__postinit__()
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/building/datastruct.py", line 184, in __postinit__
|
||||||
|
self.assemble()
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 719, in assemble
|
||||||
|
self.graph.add_hiddenimports(self.hiddenimports)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 770, in add_hiddenimports
|
||||||
|
nodes = self.import_hook(modnm)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 477, in _safe_import_hook
|
||||||
|
ret_modules = super()._safe_import_hook(
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 2103, in _safe_import_hook
|
||||||
|
target_modules = self.import_hook(
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 477, in _safe_import_hook
|
||||||
|
ret_modules = super()._safe_import_hook(
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 2103, in _safe_import_hook
|
||||||
|
target_modules = self.import_hook(
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/lib/modulegraph/modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 385, in _safe_import_hook
|
||||||
|
excluded_imports = self._find_all_excluded_imports(source_module.identifier)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 373, in _find_all_excluded_imports
|
||||||
|
excluded_imports.update(module_hook.excludedimports)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/imphook.py", line 343, in __getattr__
|
||||||
|
self._load_hook_module()
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/depend/imphook.py", line 422, in _load_hook_module
|
||||||
|
self._hook_module = importlib_load_source(self.hook_module_name, self.hook_filename)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/compat.py", line 566, in importlib_load_source
|
||||||
|
mod_loader.exec_module(mod)
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/hook-PySide6.QtQml.py", line 15, in <module>
|
||||||
|
qml_binaries, qml_datas = pyside6_library_info.collect_qtqml_files()
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/utils/hooks/qt/__init__.py", line 963, in collect_qtqml_files
|
||||||
|
plugin_binaries, plugin_datas = self._process_qml_plugin(qmldir_file)
|
||||||
|
File "/app/venv-linux/lib/python3.10/site-packages/PyInstaller/utils/hooks/qt/__init__.py", line 1014, in _process_qml_plugin
|
||||||
|
logger.warn("%s: QML plugin binary %r does not exist!", str(plugin_file))
|
||||||
|
Message: '%s: QML plugin binary %r does not exist!'
|
||||||
|
Arguments: ('/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/Qt/labs/assetdownloader/libqmlassetdownloaderprivateplugin.so',)
|
||||||
|
12557 INFO: Analyzing hidden import 'PySide6.QtCharts'
|
||||||
|
12610 INFO: Processing standard module hook 'hook-PySide6.QtCharts.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
12689 INFO: Analyzing hidden import 'PySide6.QtConcurrent'
|
||||||
|
12692 INFO: Processing standard module hook 'hook-PySide6.QtConcurrent.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
12769 INFO: Analyzing hidden import 'PySide6.QtDBus'
|
||||||
|
12787 INFO: Processing standard module hook 'hook-PySide6.QtDBus.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
12863 INFO: Analyzing hidden import 'PySide6.QtDataVisualization'
|
||||||
|
12910 INFO: Processing standard module hook 'hook-PySide6.QtDataVisualization.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
12990 INFO: Analyzing hidden import 'PySide6.QtDesigner'
|
||||||
|
13019 INFO: Processing standard module hook 'hook-PySide6.QtDesigner.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13139 INFO: Analyzing hidden import 'PySide6.QtGraphs'
|
||||||
|
13211 INFO: Processing standard module hook 'hook-PySide6.QtGraphs.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13297 INFO: Analyzing hidden import 'PySide6.QtGraphsWidgets'
|
||||||
|
13307 INFO: Processing standard module hook 'hook-PySide6.QtGraphsWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13384 INFO: Processing standard module hook 'hook-PySide6.QtQuickWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13465 INFO: Analyzing hidden import 'PySide6.QtHelp'
|
||||||
|
13473 INFO: Processing standard module hook 'hook-PySide6.QtHelp.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13554 INFO: Analyzing hidden import 'PySide6.QtHttpServer'
|
||||||
|
13561 INFO: Processing standard module hook 'hook-PySide6.QtHttpServer.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13642 INFO: Analyzing hidden import 'PySide6.QtLocation'
|
||||||
|
13689 INFO: Processing standard module hook 'hook-PySide6.QtLocation.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13809 INFO: Processing standard module hook 'hook-PySide6.QtPositioning.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
13921 INFO: Analyzing hidden import 'PySide6.QtMultimedia'
|
||||||
|
13959 INFO: Processing standard module hook 'hook-PySide6.QtMultimedia.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14068 INFO: Analyzing hidden import 'PySide6.QtMultimediaWidgets'
|
||||||
|
14070 INFO: Processing standard module hook 'hook-PySide6.QtMultimediaWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14149 INFO: Analyzing hidden import 'PySide6.QtNetworkAuth'
|
||||||
|
14162 INFO: Processing standard module hook 'hook-PySide6.QtNetworkAuth.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14243 INFO: Analyzing hidden import 'PySide6.QtNfc'
|
||||||
|
14253 INFO: Processing standard module hook 'hook-PySide6.QtNfc.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14336 INFO: Analyzing hidden import 'PySide6.QtOpenGLWidgets'
|
||||||
|
14338 INFO: Processing standard module hook 'hook-PySide6.QtOpenGLWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14418 INFO: Analyzing hidden import 'PySide6.QtPdf'
|
||||||
|
14426 INFO: Processing standard module hook 'hook-PySide6.QtPdf.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14510 INFO: Analyzing hidden import 'PySide6.QtPdfWidgets'
|
||||||
|
14513 INFO: Processing standard module hook 'hook-PySide6.QtPdfWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14596 INFO: Analyzing hidden import 'PySide6.QtPrintSupport'
|
||||||
|
14605 INFO: Processing standard module hook 'hook-PySide6.QtPrintSupport.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14698 INFO: Analyzing hidden import 'PySide6.QtQuick3D'
|
||||||
|
14704 INFO: Processing standard module hook 'hook-PySide6.QtQuick3D.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14786 INFO: Analyzing hidden import 'PySide6.QtQuickControls2'
|
||||||
|
14787 INFO: Processing standard module hook 'hook-PySide6.QtQuickControls2.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14866 INFO: Analyzing hidden import 'PySide6.QtQuickTest'
|
||||||
|
14867 INFO: Analyzing hidden import 'PySide6.QtRemoteObjects'
|
||||||
|
14877 INFO: Processing standard module hook 'hook-PySide6.QtRemoteObjects.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
14959 INFO: Analyzing hidden import 'PySide6.QtScxml'
|
||||||
|
14968 INFO: Processing standard module hook 'hook-PySide6.QtScxml.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15052 INFO: Analyzing hidden import 'PySide6.QtSensors'
|
||||||
|
15081 INFO: Processing standard module hook 'hook-PySide6.QtSensors.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15169 INFO: Analyzing hidden import 'PySide6.QtSerialBus'
|
||||||
|
15186 INFO: Processing standard module hook 'hook-PySide6.QtSerialBus.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15301 INFO: Analyzing hidden import 'PySide6.QtSerialPort'
|
||||||
|
15306 INFO: Processing standard module hook 'hook-PySide6.QtSerialPort.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15381 INFO: Analyzing hidden import 'PySide6.QtSpatialAudio'
|
||||||
|
15387 INFO: Processing standard module hook 'hook-PySide6.QtSpatialAudio.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15469 INFO: Analyzing hidden import 'PySide6.QtSql'
|
||||||
|
15487 INFO: Processing standard module hook 'hook-PySide6.QtSql.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15670 INFO: Analyzing hidden import 'PySide6.QtStateMachine'
|
||||||
|
15678 INFO: Processing standard module hook 'hook-PySide6.QtStateMachine.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15758 INFO: Analyzing hidden import 'PySide6.QtSvg'
|
||||||
|
15762 INFO: Processing standard module hook 'hook-PySide6.QtSvg.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15841 INFO: Analyzing hidden import 'PySide6.QtSvgWidgets'
|
||||||
|
15843 INFO: Processing standard module hook 'hook-PySide6.QtSvgWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
15922 INFO: Analyzing hidden import 'PySide6.QtTest'
|
||||||
|
15932 INFO: Processing standard module hook 'hook-PySide6.QtTest.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16010 INFO: Analyzing hidden import 'PySide6.QtTextToSpeech'
|
||||||
|
16015 INFO: Processing standard module hook 'hook-PySide6.QtTextToSpeech.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16112 INFO: Analyzing hidden import 'PySide6.QtUiTools'
|
||||||
|
16114 INFO: Processing standard module hook 'hook-PySide6.QtUiTools.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16198 INFO: Analyzing hidden import 'PySide6.QtWebChannel'
|
||||||
|
16200 INFO: Processing standard module hook 'hook-PySide6.QtWebChannel.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16295 INFO: Analyzing hidden import 'PySide6.QtWebEngineCore'
|
||||||
|
16332 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineCore.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16522 INFO: Analyzing hidden import 'PySide6.QtWebEngineQuick'
|
||||||
|
16526 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineQuick.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16617 INFO: Analyzing hidden import 'PySide6.QtWebEngineWidgets'
|
||||||
|
16621 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineWidgets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16707 INFO: Analyzing hidden import 'PySide6.QtWebSockets'
|
||||||
|
16713 INFO: Processing standard module hook 'hook-PySide6.QtWebSockets.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16790 INFO: Analyzing hidden import 'PySide6.QtWebView'
|
||||||
|
16793 INFO: Analyzing hidden import 'PySide6.QtXml'
|
||||||
|
16804 INFO: Processing standard module hook 'hook-PySide6.QtXml.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16894 INFO: Analyzing hidden import 'PySide6._config'
|
||||||
|
16896 INFO: Analyzing hidden import 'PySide6._git_pyside_version'
|
||||||
|
16897 INFO: Analyzing hidden import 'PySide6.scripts'
|
||||||
|
16897 INFO: Analyzing hidden import 'PySide6.scripts.android_deploy'
|
||||||
|
16901 INFO: Analyzing hidden import 'PySide6.scripts.deploy'
|
||||||
|
16904 INFO: Analyzing hidden import 'PySide6.scripts.metaobjectdump'
|
||||||
|
16912 INFO: Analyzing hidden import 'PySide6.scripts.project'
|
||||||
|
16936 INFO: Analyzing hidden import 'PySide6.scripts.project_lib'
|
||||||
|
16972 INFO: Processing standard module hook 'hook-xml.etree.cElementTree.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
16978 INFO: Processing pre-safe-import-module hook 'hook-tomli.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/pre_safe_import_module'
|
||||||
|
17002 INFO: Analyzing hidden import 'PySide6.scripts.pyside_tool'
|
||||||
|
17016 INFO: Processing standard module hook 'hook-sysconfig.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
17020 INFO: Analyzing hidden import 'PySide6.scripts.qml'
|
||||||
|
17024 INFO: Analyzing hidden import 'PySide6.scripts.qtpy2cpp'
|
||||||
|
17026 INFO: Analyzing hidden import 'PySide6.support'
|
||||||
|
17027 INFO: Analyzing hidden import 'PySide6.support.deprecated'
|
||||||
|
17028 INFO: Analyzing hidden import 'PySide6.support.generate_pyi'
|
||||||
|
17030 INFO: Processing module hooks (post-graph stage)...
|
||||||
|
17104 INFO: Performing binary vs. data reclassification (3660 entries)
|
||||||
|
19240 INFO: Looking for ctypes DLLs
|
||||||
|
19242 INFO: Analyzing run-time hooks ...
|
||||||
|
19245 INFO: Including run-time hook 'pyi_rth_inspect.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/rthooks'
|
||||||
|
19246 INFO: Including run-time hook 'pyi_rth_pkgutil.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/rthooks'
|
||||||
|
19248 INFO: Including run-time hook 'pyi_rth_multiprocessing.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/rthooks'
|
||||||
|
19249 INFO: Including run-time hook 'pyi_rth_cryptography_openssl.py' from '/app/venv-linux/lib/python3.10/site-packages/_pyinstaller_hooks_contrib/rthooks'
|
||||||
|
19250 INFO: Including run-time hook 'pyi_rth_pyside6.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/rthooks'
|
||||||
|
19251 INFO: Processing pre-find-module-path hook 'hook-_pyi_rth_utils.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks/pre_find_module_path'
|
||||||
|
19252 INFO: Processing standard module hook 'hook-_pyi_rth_utils.py' from '/app/venv-linux/lib/python3.10/site-packages/PyInstaller/hooks'
|
||||||
|
19329 INFO: Creating base_library.zip...
|
||||||
|
19340 INFO: Looking for dynamic libraries
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6FFmpegStub-crypto.so.3'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6FFmpegStub-ssl.so.3'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6FFmpegStub-va-drm.so.2'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6FFmpegStub-va-x11.so.2'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6FFmpegStub-va.so.2'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6Multimedia.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6MultimediaQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6MultimediaWidgets.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpcsclite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6Nfc.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6Quick3DSpatialAudio.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6SpatialAudio.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6TextToSpeech.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23477 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineQuick.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6WebEngineWidgets.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-shape.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-render-util.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-icccm.so.4', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-render.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-util.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxkbcommon-x11.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-cursor.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-image.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxcb-keysyms.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libQt6XcbQpa.so.6'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavcodec.so.61'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavcodec.so.61.19.101'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavformat.so.61'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavformat.so.61.7.100'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavutil.so.59'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavutil.so.59.39.100'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswresample.so.5'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswresample.so.5.3.100'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswscale.so.8'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswscale.so.8.3.100'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/libexec/QtWebEngineProcess'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavcodec.so'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavformat.so'.
|
||||||
|
23478 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libavutil.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswresample.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/lib/libswscale.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/designer/libqwebengineview.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libQt6EglFsKmsGbmSupport.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/egldeviceintegrations/libqeglfs-kms-integration.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/multimedia/libffmpegmediaplugin.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/multimedia/libffmpegmediaplugin.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-shape.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-render-util.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-icccm.so.4', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-render.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-util.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxkbcommon-x11.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-cursor.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-image.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libxcb-keysyms.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platforms/libqxcb.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libharfbuzz.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libcairo-gobject.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpangocairo-1.0.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libcairo.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libgdk_pixbuf-2.0.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpango-1.0.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libgtk-3.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libgdk-3.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libatk-1.0.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/platformthemes/libqgtk3.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libcups.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/printsupport/libcupsprintersupport.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libfbclient.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/sqldrivers/libqsqlibase.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libmimerapi.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/sqldrivers/libqsqlmimer.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libmysqlclient.so.21', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/sqldrivers/libqsqlmysql.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libclntsh.so.23.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/sqldrivers/libqsqloci.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpq.so.5', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/sqldrivers/libqsqlpsql.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/texttospeech/libqtexttospeech_mock.so'.
|
||||||
|
23479 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/texttospeech/libqtexttospeech_speechd.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libspeechd.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/texttospeech/libqtexttospeech_speechd.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/webview/libqtwebview_webengine.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-shape.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-render-util.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-icccm.so.4', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-render.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-util.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxkbcommon-x11.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-cursor.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-image.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-keysyms.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-egl-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-shape.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-render-util.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-icccm.so.4', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-render.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-util.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxkbcommon-x11.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-cursor.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-image.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libxcb-keysyms.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/plugins/xcbglintegrations/libqxcb-glx-integration.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtMultimedia/libquickmultimediaplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libQt6QuickShapesDesignHelpers.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtQuick/Shapes/DesignHelpers/libqtquickshapesdesignhelpersplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtQuick/VirtualKeyboard/Components/libqtvkbcomponentsplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtQuick3D/SpatialAudio/libquick3dspatialaudioplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtTextToSpeech/libtexttospeechqmlplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libQt6WaylandCompositorIviapplication.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWayland/Compositor/IviApplication/libwaylandcompositoriviapplicationplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libQt6WaylandCompositorPresentationTime.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWayland/Compositor/PresentationTime/libwaylandcompositorpresentationtimeplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libQt6WaylandCompositorWLShell.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWayland/Compositor/WlShell/libwaylandcompositorwlshellplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libQt6WaylandCompositorXdgShell.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWayland/Compositor/XdgShell/libwaylandcompositorxdgshellplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23480 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/Qt/qml/QtWebEngine/libqtwebenginequickplugin.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineQuick.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libasound.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXcomposite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXtst.so.6', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnspr4.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnss3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libxkbfile.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXrandr.so.2', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libXdamage.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libsmime3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libnssutil3.so', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtWebEngineCore.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtTextToSpeech.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtSpatialAudio.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libpcsclite.so.1', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtNfc.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtMultimediaWidgets.abi3.so'.
|
||||||
|
23481 WARNING: Library not found: could not resolve 'libpulse.so.0', dependency of '/app/venv-linux/lib/python3.10/site-packages/PySide6/QtMultimedia.abi3.so'.
|
||||||
|
23545 INFO: Warnings written to /tmp/cloudrestore-build/CloudRestoreAS/warn-CloudRestoreAS.txt
|
||||||
|
23570 INFO: Graph cross-reference written to /tmp/cloudrestore-build/CloudRestoreAS/xref-CloudRestoreAS.html
|
||||||
|
23670 INFO: checking PYZ
|
||||||
|
23670 INFO: Building PYZ because PYZ-00.toc is non existent
|
||||||
|
23670 INFO: Building PYZ (ZlibArchive) /tmp/cloudrestore-build/CloudRestoreAS/PYZ-00.pyz
|
||||||
|
23962 INFO: Building PYZ (ZlibArchive) /tmp/cloudrestore-build/CloudRestoreAS/PYZ-00.pyz completed successfully.
|
||||||
|
24040 INFO: checking PKG
|
||||||
|
24040 INFO: Building PKG because PKG-00.toc is non existent
|
||||||
|
24040 INFO: Building PKG (CArchive) CloudRestoreAS.pkg
|
||||||
|
93529 INFO: Building PKG (CArchive) CloudRestoreAS.pkg completed successfully.
|
||||||
|
93583 INFO: Bootloader /app/venv-linux/lib/python3.10/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run
|
||||||
|
93583 INFO: checking EXE
|
||||||
|
93583 INFO: Building EXE because EXE-00.toc is non existent
|
||||||
|
93583 INFO: Building EXE from EXE-00.toc
|
||||||
|
93583 INFO: Copying bootloader EXE to /app/dist/CloudRestoreAS
|
||||||
|
93585 INFO: Appending PKG archive to custom ELF section in EXE
|
||||||
|
99643 INFO: Building EXE from EXE-00.toc completed successfully.
|
||||||
|
99693 INFO: Build complete! The results are available in: /app/dist
|
||||||
|
|
||||||
|
Build OK: /app/dist/CloudRestoreAS
|
||||||
|
Distribuir solo el binario; al ejecutar crea config/ automaticamente.
|
||||||
|
===LINUX_BUILD_EXIT=0===
|
||||||
326
build-windows.log
Normal file
326
build-windows.log
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
===============================================
|
||||||
|
CloudRestoreAS - Build Windows (onefile)
|
||||||
|
===============================================
|
||||||
|
==> 7-Zip Extra (26.01)
|
||||||
|
7-Zip ya existe
|
||||||
|
==> ODBC Driver 18 (extraer DLLs del MSI)
|
||||||
|
ODBC ya existe
|
||||||
|
Listo: \\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\packaging\bundled\windows
|
||||||
|
Python: C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\python.exe
|
||||||
|
|
||||||
|
[notice] A new release of pip is available: 25.0.1 -> 26.1.2
|
||||||
|
[notice] To update, run: \\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Scripts\python.exe -m pip install --upgrade pip
|
||||||
|
Ejecutando PyInstaller (onefile)...
|
||||||
|
Workpath: C:\Users\Hugo Reyes\AppData\Local\Temp\cloudrestore-build
|
||||||
|
739 INFO: PyInstaller: 6.20.0, contrib hooks: 2026.6
|
||||||
|
739 INFO: Python: 3.13.3
|
||||||
|
760 INFO: Platform: Windows-11-10.0.26200-SP0
|
||||||
|
760 INFO: Python environment: \\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows
|
||||||
|
767 INFO: Removing temporary files and cleaning cache in C:\Users\Hugo Reyes\AppData\Local\pyinstaller
|
||||||
|
1995 WARNING: Failed to collect submodules for 'PySide6.scripts.deploy_lib' because importing 'PySide6.scripts.deploy_lib' raised: ModuleNotFoundError: No module named 'project_lib'
|
||||||
|
60908 INFO: Module search paths (PYTHONPATH):
|
||||||
|
['\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS',
|
||||||
|
'C:\\Users\\Hugo '
|
||||||
|
'Reyes\\AppData\\Local\\Programs\\Python\\Python313\\python313.zip',
|
||||||
|
'C:\\Users\\Hugo Reyes\\AppData\\Local\\Programs\\Python\\Python313\\DLLs',
|
||||||
|
'C:\\Users\\Hugo Reyes\\AppData\\Local\\Programs\\Python\\Python313\\Lib',
|
||||||
|
'C:\\Users\\Hugo Reyes\\AppData\\Local\\Programs\\Python\\Python313',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\win32',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\win32\\lib',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\pythonwin',
|
||||||
|
'\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS']
|
||||||
|
62173 INFO: Appending 'binaries' from .spec
|
||||||
|
63219 INFO: Appending 'datas' from .spec
|
||||||
|
73737 INFO: checking Analysis
|
||||||
|
73738 INFO: Building Analysis because Analysis-00.toc is non existent
|
||||||
|
73738 INFO: Looking for Python shared library...
|
||||||
|
73738 INFO: Using Python shared library: C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\python313.dll
|
||||||
|
73738 INFO: Running Analysis Analysis-00.toc
|
||||||
|
73738 INFO: Target bytecode optimization level: 0
|
||||||
|
73738 INFO: Initializing module dependency graph...
|
||||||
|
73739 INFO: Initializing module graph hook caches...
|
||||||
|
73939 INFO: Analyzing modules for base_library.zip ...
|
||||||
|
79161 INFO: Processing standard module hook 'hook-encodings.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
83574 INFO: Processing standard module hook 'hook-pickle.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
86088 INFO: Processing standard module hook 'hook-heapq.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
89220 INFO: Caching module dependency graph...
|
||||||
|
89327 INFO: Analyzing \\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\runner.py
|
||||||
|
89562 INFO: Processing standard module hook 'hook-sqlite3.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
91855 INFO: Processing standard module hook 'hook-PySide6.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
92619 INFO: Processing standard module hook 'hook-shiboken6.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
92791 INFO: Processing standard module hook 'hook-PySide6.QtNetwork.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
97922 INFO: Processing standard module hook 'hook-PySide6.QtCore.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
102127 INFO: Processing standard module hook 'hook-PySide6.QtWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
109064 INFO: Processing standard module hook 'hook-PySide6.QtGui.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
140346 INFO: Processing standard module hook 'hook-platform.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
140386 INFO: Processing standard module hook 'hook-_ctypes.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
140584 INFO: Processing standard module hook 'hook-cryptography.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
144730 INFO: hook-cryptography: cryptography does not seem to be using dynamically linked OpenSSL.
|
||||||
|
145207 INFO: Processing standard module hook 'hook-pyodbc.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
145794 INFO: Processing standard module hook 'hook-urllib3.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
146377 INFO: Processing pre-safe-import-module hook 'hook-backports.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
146440 INFO: SetuptoolsInfo: initializing cached setuptools info...
|
||||||
|
150867 INFO: Setuptools: 'backports' appears to be a full setuptools-vendored copy - creating alias to 'setuptools._vendor.backports'!
|
||||||
|
150904 INFO: Processing standard module hook 'hook-setuptools.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
151016 INFO: Processing pre-safe-import-module hook 'hook-distutils.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
151182 INFO: Processing standard module hook 'hook-sysconfig.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
151201 INFO: Processing pre-safe-import-module hook 'hook-jaraco.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
151205 INFO: Setuptools: 'jaraco' appears to be a full setuptools-vendored copy - creating alias to 'setuptools._vendor.jaraco'!
|
||||||
|
151239 INFO: Processing pre-safe-import-module hook 'hook-more_itertools.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
151242 INFO: Setuptools: 'more_itertools' appears to be a setuptools-vendored copy - creating alias to 'setuptools._vendor.more_itertools'!
|
||||||
|
151523 INFO: Processing pre-safe-import-module hook 'hook-typing_extensions.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
151727 INFO: Processing pre-safe-import-module hook 'hook-packaging.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
152152 INFO: Processing standard module hook 'hook-setuptools._vendor.jaraco.text.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
152159 INFO: Processing pre-safe-import-module hook 'hook-importlib_resources.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
152946 INFO: Processing pre-safe-import-module hook 'hook-importlib_metadata.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
152950 INFO: Setuptools: 'importlib_metadata' appears to be a setuptools-vendored copy - creating alias to 'setuptools._vendor.importlib_metadata'!
|
||||||
|
152983 INFO: Processing standard module hook 'hook-setuptools._vendor.importlib_metadata.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
153157 INFO: Processing pre-safe-import-module hook 'hook-zipp.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
153161 INFO: Setuptools: 'zipp' appears to be a setuptools-vendored copy - creating alias to 'setuptools._vendor.zipp'!
|
||||||
|
153794 INFO: Processing pre-safe-import-module hook 'hook-tomli.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
153800 INFO: Setuptools: 'tomli' appears to be a setuptools-vendored copy - creating alias to 'setuptools._vendor.tomli'!
|
||||||
|
155363 INFO: Processing pre-safe-import-module hook 'hook-wheel.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_safe_import_module'
|
||||||
|
155367 INFO: Setuptools: 'wheel' appears to be a setuptools-vendored copy - creating alias to 'setuptools._vendor.wheel'!
|
||||||
|
156755 INFO: Processing standard module hook 'hook-certifi.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
157092 INFO: Processing standard module hook 'hook-charset_normalizer.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
159788 INFO: Processing standard module hook 'hook-bcrypt.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
162515 INFO: Processing standard module hook 'hook-difflib.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
162955 INFO: Processing standard module hook 'hook-multiprocessing.util.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
163298 INFO: Processing standard module hook 'hook-xml.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
165811 INFO: Processing standard module hook 'hook-nacl.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\stdhooks'
|
||||||
|
168908 INFO: Analyzing hidden import 'PySide6.Qt3DAnimation'
|
||||||
|
168980 INFO: Processing standard module hook 'hook-PySide6.Qt3DAnimation.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
171050 INFO: Processing standard module hook 'hook-PySide6.Qt3DCore.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
173412 INFO: Processing standard module hook 'hook-PySide6.Qt3DRender.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
187367 INFO: Processing standard module hook 'hook-PySide6.QtOpenGL.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
193279 INFO: Analyzing hidden import 'PySide6.Qt3DExtras'
|
||||||
|
193358 INFO: Processing standard module hook 'hook-PySide6.Qt3DExtras.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
195332 INFO: Analyzing hidden import 'PySide6.Qt3DInput'
|
||||||
|
195365 INFO: Processing standard module hook 'hook-PySide6.Qt3DInput.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
196759 INFO: Analyzing hidden import 'PySide6.Qt3DLogic'
|
||||||
|
196773 INFO: Processing standard module hook 'hook-PySide6.Qt3DLogic.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
198361 INFO: Analyzing hidden import 'PySide6.QtAsyncio'
|
||||||
|
198435 INFO: Analyzing hidden import 'PySide6.QtAxContainer'
|
||||||
|
198462 INFO: Processing standard module hook 'hook-PySide6.QtAxContainer.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
199952 INFO: Analyzing hidden import 'PySide6.QtBluetooth'
|
||||||
|
200101 INFO: Processing standard module hook 'hook-PySide6.QtBluetooth.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
201249 INFO: Analyzing hidden import 'PySide6.QtCanvasPainter'
|
||||||
|
201572 INFO: Processing standard module hook 'hook-PySide6.QtQuick.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
204027 INFO: Processing standard module hook 'hook-PySide6.QtQml.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
--- Logging error ---
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\Lib\logging\__init__.py", line 1150, in emit
|
||||||
|
msg = self.format(record)
|
||||||
|
File "C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\Lib\logging\__init__.py", line 998, in format
|
||||||
|
return fmt.format(record)
|
||||||
|
~~~~~~~~~~^^^^^^^^
|
||||||
|
File "C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\Lib\logging\__init__.py", line 711, in format
|
||||||
|
record.message = record.getMessage()
|
||||||
|
~~~~~~~~~~~~~~~~~^^
|
||||||
|
File "C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\Lib\logging\__init__.py", line 400, in getMessage
|
||||||
|
msg = msg % self.args
|
||||||
|
~~~~^~~~~~~~~~~
|
||||||
|
TypeError: not enough arguments for format string
|
||||||
|
Call stack:
|
||||||
|
File "<frozen runpy>", line 198, in _run_module_as_main
|
||||||
|
File "<frozen runpy>", line 88, in _run_code
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\__main__.py", line 321, in <module>
|
||||||
|
run()
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\__main__.py", line 215, in run
|
||||||
|
run_build(pyi_config, spec_file, **vars(args))
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\__main__.py", line 70, in run_build
|
||||||
|
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\building\build_main.py", line 1275, in main
|
||||||
|
build(specfile, distpath, workpath, clean_build)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\building\build_main.py", line 1213, in build
|
||||||
|
exec(code, spec_namespace)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\packaging\CloudRestoreAS.spec", line 59, in <module>
|
||||||
|
a = Analysis(
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\building\build_main.py", line 584, in __init__
|
||||||
|
self.__postinit__()
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\building\datastruct.py", line 184, in __postinit__
|
||||||
|
self.assemble()
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\building\build_main.py", line 719, in assemble
|
||||||
|
self.graph.add_hiddenimports(self.hiddenimports)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 770, in add_hiddenimports
|
||||||
|
nodes = self.import_hook(modnm)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 477, in _safe_import_hook
|
||||||
|
ret_modules = super()._safe_import_hook(
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 2103, in _safe_import_hook
|
||||||
|
target_modules = self.import_hook(
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 477, in _safe_import_hook
|
||||||
|
ret_modules = super()._safe_import_hook(
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 2103, in _safe_import_hook
|
||||||
|
target_modules = self.import_hook(
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1279, in import_hook
|
||||||
|
submodule = self._safe_import_module(head, mname, submodule)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 539, in _safe_import_module
|
||||||
|
return super()._safe_import_module(module_basename, module_name, parent_package)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1826, in _safe_import_module
|
||||||
|
self._process_imports(n)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 2654, in _process_imports
|
||||||
|
target_modules = self._safe_import_hook(*import_info, **kwargs)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 385, in _safe_import_hook
|
||||||
|
excluded_imports = self._find_all_excluded_imports(source_module.identifier)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\analysis.py", line 373, in _find_all_excluded_imports
|
||||||
|
excluded_imports.update(module_hook.excludedimports)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\imphook.py", line 343, in __getattr__
|
||||||
|
self._load_hook_module()
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\depend\imphook.py", line 422, in _load_hook_module
|
||||||
|
self._hook_module = importlib_load_source(self.hook_module_name, self.hook_filename)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\compat.py", line 566, in importlib_load_source
|
||||||
|
mod_loader.exec_module(mod)
|
||||||
|
File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
|
||||||
|
File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\hooks\hook-PySide6.QtQml.py", line 15, in <module>
|
||||||
|
qml_binaries, qml_datas = pyside6_library_info.collect_qtqml_files()
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\utils\hooks\qt\__init__.py", line 963, in collect_qtqml_files
|
||||||
|
plugin_binaries, plugin_datas = self._process_qml_plugin(qmldir_file)
|
||||||
|
File "\\wsl.localhost\Debian\home\hugo_reyes\dev\CloudRecoveryAS\venv-windows\Lib\site-packages\PyInstaller\utils\hooks\qt\__init__.py", line 1014, in _process_qml_plugin
|
||||||
|
logger.warn("%s: QML plugin binary %r does not exist!", str(plugin_file))
|
||||||
|
Message: '%s: QML plugin binary %r does not exist!'
|
||||||
|
Arguments: ('\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\qml\\Qt\\labs\\assetdownloader\\qmlassetdownloaderprivateplugin.dll',)
|
||||||
|
275746 INFO: Analyzing hidden import 'PySide6.QtCharts'
|
||||||
|
276105 INFO: Processing standard module hook 'hook-PySide6.QtCharts.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
279221 INFO: Analyzing hidden import 'PySide6.QtConcurrent'
|
||||||
|
279250 INFO: Processing standard module hook 'hook-PySide6.QtConcurrent.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
280311 INFO: Analyzing hidden import 'PySide6.QtDBus'
|
||||||
|
280357 INFO: Processing standard module hook 'hook-PySide6.QtDBus.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
281539 INFO: Analyzing hidden import 'PySide6.QtDataVisualization'
|
||||||
|
281715 INFO: Processing standard module hook 'hook-PySide6.QtDataVisualization.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
283429 INFO: Analyzing hidden import 'PySide6.QtDesigner'
|
||||||
|
283475 INFO: Processing standard module hook 'hook-PySide6.QtDesigner.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
287863 INFO: Analyzing hidden import 'PySide6.QtGraphs'
|
||||||
|
288258 INFO: Processing standard module hook 'hook-PySide6.QtGraphs.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
290498 INFO: Analyzing hidden import 'PySide6.QtGraphsWidgets'
|
||||||
|
290529 INFO: Processing standard module hook 'hook-PySide6.QtGraphsWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
291489 INFO: Processing standard module hook 'hook-PySide6.QtQuickWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
293266 INFO: Analyzing hidden import 'PySide6.QtHelp'
|
||||||
|
293297 INFO: Processing standard module hook 'hook-PySide6.QtHelp.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
294778 INFO: Analyzing hidden import 'PySide6.QtHttpServer'
|
||||||
|
294836 INFO: Processing standard module hook 'hook-PySide6.QtHttpServer.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
295978 INFO: Analyzing hidden import 'PySide6.QtLocation'
|
||||||
|
296080 INFO: Processing standard module hook 'hook-PySide6.QtLocation.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
299546 INFO: Processing standard module hook 'hook-PySide6.QtPositioning.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
302720 INFO: Analyzing hidden import 'PySide6.QtMultimedia'
|
||||||
|
302889 INFO: Processing standard module hook 'hook-PySide6.QtMultimedia.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
307961 INFO: Analyzing hidden import 'PySide6.QtMultimediaWidgets'
|
||||||
|
308000 INFO: Processing standard module hook 'hook-PySide6.QtMultimediaWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
310129 INFO: Analyzing hidden import 'PySide6.QtNetworkAuth'
|
||||||
|
310201 INFO: Processing standard module hook 'hook-PySide6.QtNetworkAuth.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
311724 INFO: Analyzing hidden import 'PySide6.QtNfc'
|
||||||
|
311759 INFO: Processing standard module hook 'hook-PySide6.QtNfc.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
312965 INFO: Analyzing hidden import 'PySide6.QtOpenGLWidgets'
|
||||||
|
312999 INFO: Processing standard module hook 'hook-PySide6.QtOpenGLWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
314755 INFO: Analyzing hidden import 'PySide6.QtPdf'
|
||||||
|
314785 INFO: Processing standard module hook 'hook-PySide6.QtPdf.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
316217 INFO: Analyzing hidden import 'PySide6.QtPdfWidgets'
|
||||||
|
316256 INFO: Processing standard module hook 'hook-PySide6.QtPdfWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
318721 INFO: Analyzing hidden import 'PySide6.QtPrintSupport'
|
||||||
|
318783 INFO: Processing standard module hook 'hook-PySide6.QtPrintSupport.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
321097 INFO: Analyzing hidden import 'PySide6.QtQuick3D'
|
||||||
|
321121 INFO: Processing standard module hook 'hook-PySide6.QtQuick3D.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
323189 INFO: Analyzing hidden import 'PySide6.QtQuickControls2'
|
||||||
|
323210 INFO: Processing standard module hook 'hook-PySide6.QtQuickControls2.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
324672 INFO: Analyzing hidden import 'PySide6.QtQuickTest'
|
||||||
|
324686 INFO: Analyzing hidden import 'PySide6.QtRemoteObjects'
|
||||||
|
324716 INFO: Processing standard module hook 'hook-PySide6.QtRemoteObjects.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
325812 INFO: Analyzing hidden import 'PySide6.QtScxml'
|
||||||
|
325844 INFO: Processing standard module hook 'hook-PySide6.QtScxml.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
327910 INFO: Analyzing hidden import 'PySide6.QtSensors'
|
||||||
|
327951 INFO: Processing standard module hook 'hook-PySide6.QtSensors.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
329877 INFO: Analyzing hidden import 'PySide6.QtSerialBus'
|
||||||
|
329978 INFO: Processing standard module hook 'hook-PySide6.QtSerialBus.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
333019 INFO: Analyzing hidden import 'PySide6.QtSerialPort'
|
||||||
|
333041 INFO: Processing standard module hook 'hook-PySide6.QtSerialPort.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
334172 INFO: Analyzing hidden import 'PySide6.QtSpatialAudio'
|
||||||
|
334196 INFO: Processing standard module hook 'hook-PySide6.QtSpatialAudio.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
335737 INFO: Analyzing hidden import 'PySide6.QtSql'
|
||||||
|
335786 INFO: Processing standard module hook 'hook-PySide6.QtSql.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
340576 INFO: Analyzing hidden import 'PySide6.QtStateMachine'
|
||||||
|
340648 INFO: Processing standard module hook 'hook-PySide6.QtStateMachine.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
342135 INFO: Analyzing hidden import 'PySide6.QtSvg'
|
||||||
|
342220 INFO: Processing standard module hook 'hook-PySide6.QtSvg.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
344343 INFO: Analyzing hidden import 'PySide6.QtSvgWidgets'
|
||||||
|
344415 INFO: Processing standard module hook 'hook-PySide6.QtSvgWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
346445 INFO: Analyzing hidden import 'PySide6.QtTest'
|
||||||
|
346515 INFO: Processing standard module hook 'hook-PySide6.QtTest.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
348584 INFO: Analyzing hidden import 'PySide6.QtTextToSpeech'
|
||||||
|
348616 INFO: Processing standard module hook 'hook-PySide6.QtTextToSpeech.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
351294 INFO: Analyzing hidden import 'PySide6.QtUiTools'
|
||||||
|
351319 INFO: Processing standard module hook 'hook-PySide6.QtUiTools.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
353034 INFO: Analyzing hidden import 'PySide6.QtWebChannel'
|
||||||
|
353050 INFO: Processing standard module hook 'hook-PySide6.QtWebChannel.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
354101 INFO: Analyzing hidden import 'PySide6.QtWebEngineCore'
|
||||||
|
354172 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineCore.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
358005 INFO: Analyzing hidden import 'PySide6.QtWebEngineQuick'
|
||||||
|
358049 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineQuick.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
359992 INFO: Analyzing hidden import 'PySide6.QtWebEngineWidgets'
|
||||||
|
360012 INFO: Processing standard module hook 'hook-PySide6.QtWebEngineWidgets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
361731 INFO: Analyzing hidden import 'PySide6.QtWebSockets'
|
||||||
|
361758 INFO: Processing standard module hook 'hook-PySide6.QtWebSockets.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
362821 INFO: Analyzing hidden import 'PySide6.QtWebView'
|
||||||
|
362842 INFO: Analyzing hidden import 'PySide6.QtXml'
|
||||||
|
362877 INFO: Processing standard module hook 'hook-PySide6.QtXml.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
364018 INFO: Analyzing hidden import 'PySide6._config'
|
||||||
|
364032 INFO: Analyzing hidden import 'PySide6._git_pyside_version'
|
||||||
|
364047 INFO: Analyzing hidden import 'PySide6.scripts'
|
||||||
|
364051 INFO: Analyzing hidden import 'PySide6.scripts.deploy'
|
||||||
|
364083 INFO: Analyzing hidden import 'PySide6.scripts.metaobjectdump'
|
||||||
|
364144 INFO: Analyzing hidden import 'PySide6.scripts.project'
|
||||||
|
364206 INFO: Analyzing hidden import 'PySide6.scripts.project_lib'
|
||||||
|
364407 INFO: Processing standard module hook 'hook-xml.etree.cElementTree.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
364588 INFO: Analyzing hidden import 'PySide6.scripts.pyside_tool'
|
||||||
|
364619 INFO: Analyzing hidden import 'PySide6.scripts.qml'
|
||||||
|
364648 INFO: Analyzing hidden import 'PySide6.scripts.qtpy2cpp'
|
||||||
|
364670 INFO: Analyzing hidden import 'PySide6.support'
|
||||||
|
364682 INFO: Analyzing hidden import 'PySide6.support.deprecated'
|
||||||
|
364697 INFO: Analyzing hidden import 'PySide6.support.generate_pyi'
|
||||||
|
364717 INFO: Processing module hooks (post-graph stage)...
|
||||||
|
366519 INFO: Performing binary vs. data reclassification (3704 entries)
|
||||||
|
434075 INFO: Looking for ctypes DLLs
|
||||||
|
434137 INFO: Analyzing run-time hooks ...
|
||||||
|
434140 INFO: Including run-time hook 'pyi_rth_inspect.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks'
|
||||||
|
434182 INFO: Including run-time hook 'pyi_rth_setuptools.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks'
|
||||||
|
434219 INFO: Including run-time hook 'pyi_rth_pkgutil.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks'
|
||||||
|
434274 INFO: Including run-time hook 'pyi_rth_multiprocessing.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks'
|
||||||
|
434306 INFO: Including run-time hook 'pyi_rth_cryptography_openssl.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\rthooks'
|
||||||
|
434323 INFO: Including run-time hook 'pyi_rth_pyside6.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks'
|
||||||
|
434347 INFO: Processing pre-find-module-path hook 'hook-_pyi_rth_utils.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks\\pre_find_module_path'
|
||||||
|
434407 INFO: Processing standard module hook 'hook-_pyi_rth_utils.py' from '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PyInstaller\\hooks'
|
||||||
|
434578 INFO: Creating base_library.zip...
|
||||||
|
434595 INFO: Looking for dynamic libraries
|
||||||
|
448674 INFO: Extra DLL search directories (AddDllDirectory): ['\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\shiboken6']
|
||||||
|
448674 INFO: Extra DLL search directories (PATH): ['\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6']
|
||||||
|
627416 WARNING: Library not found: could not resolve 'fbclient.dll', dependency of '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\plugins\\sqldrivers\\qsqlibase.dll'.
|
||||||
|
627645 WARNING: Library not found: could not resolve 'MIMAPI64.dll', dependency of '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\plugins\\sqldrivers\\qsqlmimer.dll'.
|
||||||
|
627727 WARNING: Library not found: could not resolve 'OCI.dll', dependency of '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\plugins\\sqldrivers\\qsqloci.dll'.
|
||||||
|
627756 WARNING: Library not found: could not resolve 'LIBPQ.dll', dependency of '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\plugins\\sqldrivers\\qsqlpsql.dll'.
|
||||||
|
628660 WARNING: Library not found: could not resolve 'Qt6QuickShapesDesignHelpers.dll', dependency of '\\\\wsl.localhost\\Debian\\home\\hugo_reyes\\dev\\CloudRecoveryAS\\venv-windows\\Lib\\site-packages\\PySide6\\qml\\QtQuick\\Shapes\\DesignHelpers\\qtquickshapesdesignhelpersplugin.dll'.
|
||||||
|
634420 INFO: Warnings written to C:\Users\Hugo Reyes\AppData\Local\Temp\cloudrestore-build\CloudRestoreAS\warn-CloudRestoreAS.txt
|
||||||
|
634496 INFO: Graph cross-reference written to C:\Users\Hugo Reyes\AppData\Local\Temp\cloudrestore-build\CloudRestoreAS\xref-CloudRestoreAS.html
|
||||||
|
634828 INFO: checking PYZ
|
||||||
|
634828 INFO: Building PYZ because PYZ-00.toc is non existent
|
||||||
|
634828 INFO: Building PYZ (ZlibArchive) C:\Users\Hugo Reyes\AppData\Local\Temp\cloudrestore-build\CloudRestoreAS\PYZ-00.pyz
|
||||||
|
635544 INFO: Building PYZ (ZlibArchive) C:\Users\Hugo Reyes\AppData\Local\Temp\cloudrestore-build\CloudRestoreAS\PYZ-00.pyz completed successfully.
|
||||||
|
635679 INFO: checking PKG
|
||||||
|
635679 INFO: Building PKG because PKG-00.toc is non existent
|
||||||
|
635679 INFO: Building PKG (CArchive) CloudRestoreAS.pkg
|
||||||
113
build.ps1
113
build.ps1
@@ -1,72 +1,63 @@
|
|||||||
# Script de build para PyInstaller
|
# Build CloudRestoreAS — PyInstaller onefile portable
|
||||||
# Genera un ejecutable único de la aplicación
|
$ErrorActionPreference = "Stop"
|
||||||
|
$Root = $PSScriptRoot
|
||||||
|
|
||||||
Write-Host "===============================================" -ForegroundColor Cyan
|
Write-Host "===============================================" -ForegroundColor Cyan
|
||||||
Write-Host "CloudRestoreAS - Build Script" -ForegroundColor Cyan
|
Write-Host "CloudRestoreAS - Build Windows (onefile)" -ForegroundColor Cyan
|
||||||
Write-Host "===============================================" -ForegroundColor Cyan
|
Write-Host "===============================================" -ForegroundColor Cyan
|
||||||
Write-Host ""
|
|
||||||
|
|
||||||
# Verificar que PyInstaller esté instalado
|
& "$Root\packaging\scripts\download-bundled-deps.ps1"
|
||||||
Write-Host "Verificando PyInstaller..." -ForegroundColor Yellow
|
|
||||||
$pyinstallerCheck = pip show pyinstaller 2>$null
|
# Python de Windows (evitar venv creado desde WSL)
|
||||||
if (-not $pyinstallerCheck) {
|
$PythonCandidates = @(
|
||||||
Write-Host "PyInstaller no está instalado. Instalando..." -ForegroundColor Yellow
|
"$env:LOCALAPPDATA\Programs\Python\Python313\python.exe",
|
||||||
pip install pyinstaller
|
"$env:LOCALAPPDATA\Programs\Python\Python312\python.exe",
|
||||||
|
"$env:LOCALAPPDATA\Programs\Python\Python311\python.exe"
|
||||||
|
)
|
||||||
|
$Python = $PythonCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||||
|
if (-not $Python) {
|
||||||
|
throw "No se encontró Python 3.11+ en Windows. Instale desde python.org"
|
||||||
}
|
}
|
||||||
|
Write-Host "Python: $Python" -ForegroundColor Gray
|
||||||
|
|
||||||
# Crear directorio de build
|
$venvDir = Join-Path $Root "venv-windows"
|
||||||
$buildDir = "build"
|
$venvPython = Join-Path $venvDir "Scripts\python.exe"
|
||||||
$distDir = "dist"
|
if (-not (Test-Path $venvPython)) {
|
||||||
|
if (Test-Path $venvDir) { Remove-Item -Recurse -Force $venvDir }
|
||||||
Write-Host ""
|
& $Python -m venv $venvDir
|
||||||
Write-Host "Limpiando builds anteriores..." -ForegroundColor Yellow
|
|
||||||
if (Test-Path $buildDir) {
|
|
||||||
Remove-Item -Recurse -Force $buildDir
|
|
||||||
}
|
|
||||||
if (Test-Path $distDir) {
|
|
||||||
Remove-Item -Recurse -Force $distDir
|
|
||||||
}
|
|
||||||
if (Test-Path "*.spec") {
|
|
||||||
Remove-Item -Force *.spec
|
|
||||||
}
|
}
|
||||||
|
& $venvPython -m pip install --upgrade pip -q
|
||||||
|
& $venvPython -m pip install -r (Join-Path $Root "requirements-windows.txt") -q
|
||||||
|
|
||||||
Write-Host ""
|
$distDir = Join-Path $Root "dist"
|
||||||
Write-Host "Ejecutando PyInstaller..." -ForegroundColor Yellow
|
$isUncRoot = $Root -like "\\*"
|
||||||
Write-Host ""
|
# PyInstaller no puede usar workpath en UNC (WSL); usar carpeta local en Windows
|
||||||
|
if ($isUncRoot) {
|
||||||
# Ejecutar PyInstaller
|
$buildDir = Join-Path $env:LOCALAPPDATA "Temp\cloudrestore-build"
|
||||||
pyinstaller --name CloudRestoreAS `
|
|
||||||
--onefile `
|
|
||||||
--windowed `
|
|
||||||
--icon=NONE `
|
|
||||||
--add-data "app;app" `
|
|
||||||
--hidden-import PySide6 `
|
|
||||||
--hidden-import pyodbc `
|
|
||||||
--hidden-import win32crypt `
|
|
||||||
--collect-all PySide6 `
|
|
||||||
runner.py
|
|
||||||
|
|
||||||
if ($LASTEXITCODE -eq 0) {
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "===============================================" -ForegroundColor Green
|
|
||||||
Write-Host "Build completado exitosamente!" -ForegroundColor Green
|
|
||||||
Write-Host "===============================================" -ForegroundColor Green
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "El ejecutable se encuentra en:" -ForegroundColor Cyan
|
|
||||||
Write-Host " $PWD\dist\CloudRestoreAS.exe" -ForegroundColor White
|
|
||||||
Write-Host ""
|
|
||||||
Write-Host "IMPORTANTE:" -ForegroundColor Yellow
|
|
||||||
Write-Host " - Copia las carpetas 'data' y 'logs' junto al .exe" -ForegroundColor White
|
|
||||||
Write-Host " - Asegúrate de tener 7-Zip instalado" -ForegroundColor White
|
|
||||||
Write-Host " - Asegúrate de tener ODBC Driver 17 for SQL Server" -ForegroundColor White
|
|
||||||
Write-Host ""
|
|
||||||
} else {
|
} else {
|
||||||
Write-Host ""
|
$buildDir = Join-Path $Root "build"
|
||||||
Write-Host "===============================================" -ForegroundColor Red
|
}
|
||||||
Write-Host "Error durante el build" -ForegroundColor Red
|
if (Test-Path $buildDir) {
|
||||||
Write-Host "===============================================" -ForegroundColor Red
|
Remove-Item -Recurse -Force $buildDir -ErrorAction SilentlyContinue
|
||||||
Write-Host ""
|
}
|
||||||
|
New-Item -ItemType Directory -Force -Path $distDir, $buildDir | Out-Null
|
||||||
|
if (Test-Path (Join-Path $distDir "CloudRestoreAS.exe")) {
|
||||||
|
Remove-Item -Force (Join-Path $distDir "CloudRestoreAS.exe") -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
# Pausar para ver resultados
|
Write-Host "Ejecutando PyInstaller (onefile)..." -ForegroundColor Yellow
|
||||||
Read-Host "Presiona Enter para continuar..."
|
Write-Host "Workpath: $buildDir" -ForegroundColor Gray
|
||||||
|
& $venvPython -m PyInstaller (Join-Path $Root "packaging\CloudRestoreAS.spec") `
|
||||||
|
--clean --noconfirm `
|
||||||
|
--distpath $distDir `
|
||||||
|
--workpath $buildDir
|
||||||
|
|
||||||
|
$exe = Join-Path $Root "dist\CloudRestoreAS.exe"
|
||||||
|
if (Test-Path $exe) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Build OK: $exe" -ForegroundColor Green
|
||||||
|
Write-Host "Distribuir solo el .exe; al ejecutar crea config/ automaticamente." -ForegroundColor Cyan
|
||||||
|
} else {
|
||||||
|
Write-Host "Error: no se genero el ejecutable" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|||||||
43
build.sh
Executable file
43
build.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build CloudRestoreAS — PyInstaller onefile portable (Linux)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
cd "$ROOT"
|
||||||
|
|
||||||
|
echo "==============================================="
|
||||||
|
echo "CloudRestoreAS - Build Linux (onefile)"
|
||||||
|
echo "==============================================="
|
||||||
|
|
||||||
|
bash "$ROOT/packaging/scripts/download-bundled-deps.sh"
|
||||||
|
|
||||||
|
VENV="$ROOT/venv-linux"
|
||||||
|
if [[ ! -x "$VENV/bin/python" ]]; then
|
||||||
|
rm -rf "$VENV"
|
||||||
|
python3 -m venv "$VENV"
|
||||||
|
fi
|
||||||
|
"$VENV/bin/pip" install --upgrade pip -q
|
||||||
|
"$VENV/bin/pip" install -r requirements.txt -q
|
||||||
|
|
||||||
|
BUILD_DIR="${CLOUDRESTORE_BUILD_DIR:-/tmp/cloudrestore-build}"
|
||||||
|
DIST_DIR="${CLOUDRESTORE_DIST_DIR:-$ROOT/dist}"
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
mkdir -p "$BUILD_DIR" "$DIST_DIR"
|
||||||
|
rm -f "$DIST_DIR/CloudRestoreAS"
|
||||||
|
|
||||||
|
echo "Ejecutando PyInstaller (onefile)..."
|
||||||
|
"$VENV/bin/python" -m PyInstaller packaging/CloudRestoreAS.spec \
|
||||||
|
--clean --noconfirm \
|
||||||
|
--distpath "$DIST_DIR" \
|
||||||
|
--workpath "$BUILD_DIR"
|
||||||
|
|
||||||
|
BIN="$ROOT/dist/CloudRestoreAS"
|
||||||
|
if [[ -f "$BIN" ]]; then
|
||||||
|
chmod +x "$BIN"
|
||||||
|
echo ""
|
||||||
|
echo "Build OK: $BIN"
|
||||||
|
echo "Distribuir solo el binario; al ejecutar crea config/ automaticamente."
|
||||||
|
else
|
||||||
|
echo "Error: no se genero el binario" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
97
packaging/CloudRestoreAS.spec
Normal file
97
packaging/CloudRestoreAS.spec
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
"""PyInstaller spec — onefile portable (ejecutar en Windows o Linux según destino)."""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
block_cipher = None
|
||||||
|
ROOT = Path(SPECPATH).resolve().parent
|
||||||
|
platform = "windows" if sys.platform == "win32" else "linux"
|
||||||
|
bundled = ROOT / "packaging" / "bundled" / platform
|
||||||
|
|
||||||
|
_assets = ROOT / "packaging" / "assets"
|
||||||
|
datas = [
|
||||||
|
(str(ROOT / "packaging" / "templates" / "env.default"), "packaging/templates"),
|
||||||
|
]
|
||||||
|
if _assets.is_dir():
|
||||||
|
for _icon in _assets.iterdir():
|
||||||
|
if _icon.is_file() and _icon.suffix.lower() in (".png", ".ico"):
|
||||||
|
datas.append((str(_icon), "packaging/assets"))
|
||||||
|
|
||||||
|
binaries = []
|
||||||
|
|
||||||
|
seven_dir = bundled / "7zip"
|
||||||
|
if seven_dir.is_dir():
|
||||||
|
for item in seven_dir.iterdir():
|
||||||
|
if item.is_file():
|
||||||
|
binaries.append((str(item), "bundled/7zip"))
|
||||||
|
|
||||||
|
odbc_dir = bundled / "odbc"
|
||||||
|
if odbc_dir.is_dir():
|
||||||
|
for item in odbc_dir.rglob("*"):
|
||||||
|
if not item.is_file():
|
||||||
|
continue
|
||||||
|
if item.suffix.lower() in (".msi", ".deb"):
|
||||||
|
continue
|
||||||
|
rel = item.relative_to(odbc_dir)
|
||||||
|
dest = f"bundled/odbc/{rel.parent}".replace("\\", "/")
|
||||||
|
if str(rel.parent) == ".":
|
||||||
|
dest = "bundled/odbc"
|
||||||
|
binaries.append((str(item), dest))
|
||||||
|
|
||||||
|
hiddenimports = [
|
||||||
|
"PySide6",
|
||||||
|
"pyodbc",
|
||||||
|
"requests",
|
||||||
|
"paramiko",
|
||||||
|
"dotenv",
|
||||||
|
"cryptography.fernet",
|
||||||
|
]
|
||||||
|
if platform == "windows":
|
||||||
|
hiddenimports.append("win32crypt")
|
||||||
|
|
||||||
|
from PyInstaller.utils.hooks import collect_all
|
||||||
|
|
||||||
|
pyside_datas, pyside_binaries, pyside_hidden = collect_all("PySide6")
|
||||||
|
datas += pyside_datas
|
||||||
|
binaries += pyside_binaries
|
||||||
|
hiddenimports += pyside_hidden
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
[str(ROOT / "runner.py")],
|
||||||
|
pathex=[str(ROOT)],
|
||||||
|
binaries=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="CloudRestoreAS",
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
)
|
||||||
18
packaging/LEEME.txt
Normal file
18
packaging/LEEME.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
CloudRestoreAS — despliegue portable
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Windows: copie CloudRestoreAS.exe a la carpeta deseada.
|
||||||
|
Linux: copie CloudRestoreAS y ejecute chmod +x CloudRestoreAS si hace falta.
|
||||||
|
|
||||||
|
1. Ejecute el programa (doble clic o ./CloudRestoreAS).
|
||||||
|
- Se abre la ventana principal y un icono en la bandeja del sistema.
|
||||||
|
- El motor arranca automaticamente (CLOUDRESTORE_AUTO_START=true por defecto).
|
||||||
|
2. Se crean automaticamente: config/, Entrada/, Procesados/, Fallados/, Temp/
|
||||||
|
3. Edite config/.env con la URL, token e instancia del servicio de bases.
|
||||||
|
4. Reinicie la aplicacion si cambio la configuracion.
|
||||||
|
|
||||||
|
Cerrar la ventana (X) minimiza a la bandeja; la app sigue en ejecucion.
|
||||||
|
Para salir por completo: clic derecho en el icono de bandeja -> Salir,
|
||||||
|
o menu Archivo -> Salir.
|
||||||
|
|
||||||
|
No requiere Python ni instaladores adicionales en el equipo destino.
|
||||||
9
packaging/bundled-versions.json
Normal file
9
packaging/bundled-versions.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"seven_zip": "26.01",
|
||||||
|
"seven_zip_windows_extra": "https://github.com/ip7z/7zip/releases/download/26.01/7z2601-extra.7z",
|
||||||
|
"seven_zip_windows_7zr": "https://github.com/ip7z/7zip/releases/download/26.01/7zr.exe",
|
||||||
|
"seven_zip_linux_x64": "https://github.com/ip7z/7zip/releases/download/26.01/7z2601-linux-x64.tar.xz",
|
||||||
|
"msodbcsql18_msi": "https://go.microsoft.com/fwlink/?linkid=2281204",
|
||||||
|
"msodbcsql18_deb": "https://packages.microsoft.com/ubuntu/22.04/prod/pool/main/m/msodbcsql18/msodbcsql18_18.5.1.1-1_amd64.deb",
|
||||||
|
"unixodbc_deb": "http://archive.ubuntu.com/ubuntu/pool/main/u/unixodbc/unixodbc_2.3.12-1ubuntu0.24.04.1_amd64.deb"
|
||||||
|
}
|
||||||
34
packaging/scripts/build-all.sh
Normal file
34
packaging/scripts/build-all.sh
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Genera ambos artefactos: Linux (local/Docker) y Windows (PowerShell + Python en Windows).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
RELEASE="$ROOT/dist/release"
|
||||||
|
mkdir -p "$RELEASE"
|
||||||
|
|
||||||
|
echo "=== Build Linux ==="
|
||||||
|
if [[ -f "$ROOT/build.sh" ]]; then
|
||||||
|
bash "$ROOT/build.sh"
|
||||||
|
cp -f "$ROOT/dist/CloudRestoreAS" "$RELEASE/CloudRestoreAS-linux"
|
||||||
|
chmod +x "$RELEASE/CloudRestoreAS-linux"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Build Windows (via PowerShell) ==="
|
||||||
|
WSL_PATH=$(wslpath -w "$ROOT" 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$WSL_PATH" ]] && command -v powershell.exe >/dev/null 2>&1; then
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "
|
||||||
|
Set-Location '$WSL_PATH'
|
||||||
|
& 'C:\Users\Hugo Reyes\AppData\Local\Programs\Python\Python313\python.exe' -m pip install -q -r requirements-windows.txt 2>\$null
|
||||||
|
& .\build.ps1
|
||||||
|
"
|
||||||
|
if [[ -f "$ROOT/dist/CloudRestoreAS.exe" ]]; then
|
||||||
|
cp -f "$ROOT/dist/CloudRestoreAS.exe" "$RELEASE/CloudRestoreAS.exe"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Omitido: ejecute build.ps1 en Windows manualmente"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -f "$ROOT/packaging/LEEME.txt" "$RELEASE/"
|
||||||
|
echo ""
|
||||||
|
echo "Artefactos en: $RELEASE"
|
||||||
|
ls -la "$RELEASE"
|
||||||
19
packaging/scripts/docker-build-linux.sh
Executable file
19
packaging/scripts/docker-build-linux.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build Linux onefile dentro de Docker con dependencias Qt del sistema.
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
docker run --rm \
|
||||||
|
-v "$ROOT:/app" \
|
||||||
|
-w /app \
|
||||||
|
ubuntu:22.04 bash -c '
|
||||||
|
set -e
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq \
|
||||||
|
python3 python3-venv python3-pip curl dpkg-dev binutils unixodbc \
|
||||||
|
libglib2.0-0 libdbus-1-3 libxkbcommon0 libfontconfig1 libxcb1 libx11-6 \
|
||||||
|
libxcb-xkb1 libegl1 libgl1 libxi6 libxrender1 libxext6 \
|
||||||
|
> /dev/null
|
||||||
|
chmod +x build.sh packaging/scripts/download-bundled-deps.sh
|
||||||
|
./build.sh
|
||||||
|
'
|
||||||
93
packaging/scripts/download-bundled-deps.ps1
Normal file
93
packaging/scripts/download-bundled-deps.ps1
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Descarga 7-Zip Extra y ODBC para empaquetar en CloudRestoreAS.exe
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$Root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
|
||||||
|
$Versions = Get-Content (Join-Path $Root "packaging\bundled-versions.json") | ConvertFrom-Json
|
||||||
|
$Bundled = Join-Path $Root "packaging\bundled\windows"
|
||||||
|
$Seven = Join-Path $Bundled "7zip"
|
||||||
|
$Odbc = Join-Path $Bundled "odbc"
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path $Seven, $Odbc | Out-Null
|
||||||
|
|
||||||
|
Write-Host "==> 7-Zip Extra ($($Versions.seven_zip))" -ForegroundColor Cyan
|
||||||
|
if (-not (Test-Path (Join-Path $Seven "7z.exe"))) {
|
||||||
|
$tmp = Join-Path $env:TEMP "cloudrestore-7z-$(Get-Random)"
|
||||||
|
New-Item -ItemType Directory -Path $tmp | Out-Null
|
||||||
|
$sevenR = Join-Path $tmp "7zr.exe"
|
||||||
|
$extra = Join-Path $tmp "7z-extra.7z"
|
||||||
|
Invoke-WebRequest -Uri $Versions.seven_zip_windows_7zr -OutFile $sevenR
|
||||||
|
Invoke-WebRequest -Uri $Versions.seven_zip_windows_extra -OutFile $extra
|
||||||
|
& $sevenR x $extra ("-o" + $Seven) -y | Out-Null
|
||||||
|
$x64Exe = Join-Path $Seven "x64\7za.exe"
|
||||||
|
$x64Dll = Join-Path $Seven "x64\7za.dll"
|
||||||
|
if (Test-Path $x64Exe) {
|
||||||
|
Copy-Item $x64Exe (Join-Path $Seven "7z.exe") -Force
|
||||||
|
Copy-Item $x64Exe (Join-Path $Seven "7za.exe") -Force
|
||||||
|
}
|
||||||
|
if (Test-Path $x64Dll) {
|
||||||
|
Copy-Item $x64Dll (Join-Path $Seven "7z.dll") -Force
|
||||||
|
Copy-Item $x64Dll (Join-Path $Seven "7za.dll") -Force
|
||||||
|
}
|
||||||
|
Remove-Item -Recurse -Force $tmp
|
||||||
|
Write-Host " 7z.exe en $Seven"
|
||||||
|
} else {
|
||||||
|
Write-Host " 7-Zip ya existe"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "==> ODBC Driver 18 (extraer DLLs del MSI)" -ForegroundColor Cyan
|
||||||
|
$Msi = Join-Path $Odbc "msodbcsql18.msi"
|
||||||
|
if (-not (Test-Path (Join-Path $Odbc "msodbcsql18.dll"))) {
|
||||||
|
if (-not (Test-Path $Msi)) {
|
||||||
|
Invoke-WebRequest -Uri $Versions.msodbcsql18_msi -OutFile $Msi
|
||||||
|
}
|
||||||
|
$extract = Join-Path $Odbc "_msi_extract"
|
||||||
|
if (Test-Path $extract) { Remove-Item -Recurse -Force $extract }
|
||||||
|
New-Item -ItemType Directory -Path $extract | Out-Null
|
||||||
|
$msiArgs = @("/a", "`"$Msi`"", "/qn", "TARGETDIR=`"$extract`"", "IACCEPTMSODBCSQLLICENSETERMS=YES")
|
||||||
|
$proc = Start-Process msiexec.exe -ArgumentList $msiArgs -Wait -PassThru
|
||||||
|
if ($proc.ExitCode -ne 0) {
|
||||||
|
Write-Host " msiexec /a fallo (codigo $($proc.ExitCode)); intentando instalacion silenciosa local..." -ForegroundColor Yellow
|
||||||
|
$local = Join-Path $Odbc "driver_install"
|
||||||
|
New-Item -ItemType Directory -Force -Path $local | Out-Null
|
||||||
|
Start-Process msiexec.exe -ArgumentList "/i", "`"$Msi`"", "/qn", "IACCEPTMSODBCSQLLICENSETERMS=YES", "ADDLOCAL=ALL" -Wait
|
||||||
|
$sysOdbc = "${env:ProgramFiles}\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn"
|
||||||
|
if (Test-Path $sysOdbc) {
|
||||||
|
Get-ChildItem $sysOdbc -Filter "*.dll" | Copy-Item -Destination $Odbc -Force
|
||||||
|
}
|
||||||
|
$driverDir = "${env:ProgramFiles}\Microsoft SQL Server\Client SDK\ODBC\180\Tools\Binn"
|
||||||
|
if (Test-Path $driverDir) {
|
||||||
|
Get-ChildItem $driverDir -Filter "*.dll" | Copy-Item -Destination $Odbc -Force
|
||||||
|
}
|
||||||
|
foreach ($dll in @("msodbcsql18.dll", "msodbcsql17.dll")) {
|
||||||
|
$sys = Join-Path $env:SystemRoot "System32\$dll"
|
||||||
|
if (Test-Path $sys) { Copy-Item $sys $Odbc -Force }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Get-ChildItem -Path $extract -Recurse -Filter "msodbcsql*.dll" | ForEach-Object {
|
||||||
|
Copy-Item $_.FullName $Odbc -Force
|
||||||
|
}
|
||||||
|
Get-ChildItem -Path $extract -Recurse -Filter "*.dll" | Where-Object {
|
||||||
|
$_.Name -match "mso|odbc|ssl|crypto|bcp"
|
||||||
|
} | ForEach-Object { Copy-Item $_.FullName $Odbc -Force -ErrorAction SilentlyContinue }
|
||||||
|
Remove-Item -Recurse -Force $extract -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
Write-Host " DLLs ODBC en $Odbc"
|
||||||
|
} else {
|
||||||
|
Write-Host " ODBC ya existe"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path (Join-Path $Odbc "odbcinst.ini"))) {
|
||||||
|
@"
|
||||||
|
[ODBC Driver 18 for SQL Server]
|
||||||
|
Description=Microsoft ODBC Driver 18 for SQL Server
|
||||||
|
Driver=msodbcsql18.dll
|
||||||
|
UsageCount=1
|
||||||
|
|
||||||
|
[ODBC Driver 17 for SQL Server]
|
||||||
|
Description=Microsoft ODBC Driver 17 for SQL Server
|
||||||
|
Driver=msodbcsql17.dll
|
||||||
|
UsageCount=1
|
||||||
|
"@ | Set-Content (Join-Path $Odbc "odbcinst.ini") -Encoding ASCII
|
||||||
|
"[ODBC Data Sources]" | Set-Content (Join-Path $Odbc "odbc.ini") -Encoding ASCII
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Listo: $Bundled" -ForegroundColor Green
|
||||||
58
packaging/scripts/download-bundled-deps.sh
Executable file
58
packaging/scripts/download-bundled-deps.sh
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Descarga 7zz y bibliotecas ODBC para empaquetar en el binario Linux.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
VERSIONS="$ROOT/packaging/bundled-versions.json"
|
||||||
|
BUNDLED="$ROOT/packaging/bundled/linux"
|
||||||
|
SEVEN="$BUNDLED/7zip"
|
||||||
|
ODBC="$BUNDLED/odbc/lib"
|
||||||
|
|
||||||
|
mkdir -p "$SEVEN" "$ODBC"
|
||||||
|
|
||||||
|
read_url() {
|
||||||
|
python3 -c "import json; print(json.load(open('$VERSIONS'))['$1'])"
|
||||||
|
}
|
||||||
|
|
||||||
|
LINUX_7Z_URL="$(read_url seven_zip_linux_x64)"
|
||||||
|
MSODBC_DEB="$(read_url msodbcsql18_deb)"
|
||||||
|
|
||||||
|
echo "==> 7-Zip Linux (7zz)"
|
||||||
|
if [[ ! -f "$SEVEN/7zz" ]]; then
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
curl -fsSL -o "$TMP/7z.tar.xz" "$LINUX_7Z_URL"
|
||||||
|
tar -xJf "$TMP/7z.tar.xz" -C "$TMP"
|
||||||
|
cp "$TMP/7zz" "$SEVEN/7zz"
|
||||||
|
chmod +x "$SEVEN/7zz"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
echo " 7zz instalado"
|
||||||
|
else
|
||||||
|
echo " 7zz ya existe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> ODBC Driver 18 + unixODBC"
|
||||||
|
if [[ -z "$(ls -A "$ODBC" 2>/dev/null || true)" ]]; then
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
cd "$TMP"
|
||||||
|
curl -fsSL -o msodbcsql18.deb "$MSODBC_DEB"
|
||||||
|
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq
|
||||||
|
apt-get install -y -qq unixodbc dpkg-dev > /dev/null 2>&1 || true
|
||||||
|
if dpkg -l unixodbc 2>/dev/null | grep -q ^ii; then
|
||||||
|
find /usr/lib -name 'libodbc*.so*' -exec cp -P {} "$ODBC/" \; 2>/dev/null || true
|
||||||
|
find /usr/lib -name 'libodbcinst*.so*' -exec cp -P {} "$ODBC/" \; 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
dpkg-deb -x msodbcsql18.deb msodbcsql
|
||||||
|
find msodbcsql -name '*.so*' -exec cp -P {} "$ODBC/" \;
|
||||||
|
cd "$ROOT"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
echo " Bibliotecas ODBC en $ODBC"
|
||||||
|
else
|
||||||
|
echo " ODBC ya existe"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Listo: $BUNDLED"
|
||||||
27
packaging/scripts/package-release.sh
Normal file
27
packaging/scripts/package-release.sh
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Empaqueta artefactos en dist/release/
|
||||||
|
set -euo pipefail
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
RELEASE="$ROOT/dist/release"
|
||||||
|
mkdir -p "$RELEASE"
|
||||||
|
|
||||||
|
[[ -f "$ROOT/dist/CloudRestoreAS.exe" ]] && cp -f "$ROOT/dist/CloudRestoreAS.exe" "$RELEASE/"
|
||||||
|
[[ -f "$ROOT/dist/CloudRestoreAS" ]] && cp -f "$ROOT/dist/CloudRestoreAS" "$RELEASE/CloudRestoreAS-linux" && chmod +x "$RELEASE/CloudRestoreAS-linux"
|
||||||
|
cp -f "$ROOT/packaging/LEEME.txt" "$RELEASE/"
|
||||||
|
|
||||||
|
python3 <<'PY'
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
release = Path("dist/release")
|
||||||
|
if (release / "CloudRestoreAS.exe").exists():
|
||||||
|
with zipfile.ZipFile(release / "CloudRestoreAS-win.zip", "w", zipfile.ZIP_DEFLATED) as z:
|
||||||
|
z.write(release / "CloudRestoreAS.exe", "CloudRestoreAS.exe")
|
||||||
|
z.write(release / "LEEME.txt", "LEEME.txt")
|
||||||
|
PY
|
||||||
|
|
||||||
|
if [[ -f "$RELEASE/CloudRestoreAS-linux" ]]; then
|
||||||
|
tar czf "$RELEASE/CloudRestoreAS-linux.tar.gz" -C "$RELEASE" CloudRestoreAS-linux LEEME.txt
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Release en: $RELEASE"
|
||||||
|
ls -lh "$RELEASE"
|
||||||
18
packaging/templates/env.default
Normal file
18
packaging/templates/env.default
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# CloudRestoreAS — configuración local (editar y reiniciar la app)
|
||||||
|
|
||||||
|
# Arranca el motor al abrir (la ventana siempre se muestra salvo START_MINIMIZED=true)
|
||||||
|
CLOUDRESTORE_AUTO_START=true
|
||||||
|
CLOUDRESTORE_START_MINIMIZED=false
|
||||||
|
CLOUDRESTORE_REGISTER_AUTOSTART=true
|
||||||
|
|
||||||
|
# Servicio PANEL_BASES_ANEXO24
|
||||||
|
CLOUDRESTORE_PANEL_API_URL=
|
||||||
|
CLOUDRESTORE_PANEL_API_TOKEN=
|
||||||
|
CLOUDRESTORE_PANEL_INSTANCE_KEY=
|
||||||
|
CLOUDRESTORE_PANEL_VERIFY_SSL=false
|
||||||
|
|
||||||
|
# Carpetas (se crean automáticamente junto al ejecutable)
|
||||||
|
CLOUDRESTORE_INPUT_FOLDER={APP_DIR}/Entrada
|
||||||
|
CLOUDRESTORE_PROCESSED_FOLDER={APP_DIR}/Procesados
|
||||||
|
CLOUDRESTORE_FAILED_FOLDER={APP_DIR}/Fallados
|
||||||
|
CLOUDRESTORE_EXTRACT_FOLDER={APP_DIR}/Temp
|
||||||
2
requirements-windows.txt
Normal file
2
requirements-windows.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
pywin32>=306
|
||||||
@@ -1,21 +1,13 @@
|
|||||||
# CloudRestoreAS - Dependencias
|
# CloudRestoreAS - Dependencias base (Windows y Linux)
|
||||||
|
|
||||||
# PySide6 para la interfaz gráfica
|
|
||||||
PySide6>=6.6.0
|
PySide6>=6.6.0
|
||||||
|
|
||||||
# pyodbc para SQL Server
|
|
||||||
pyodbc>=5.0.0
|
pyodbc>=5.0.0
|
||||||
|
|
||||||
# pywin32 para DPAPI (cifrado de passwords)
|
|
||||||
pywin32>=306
|
|
||||||
|
|
||||||
# requests para consultar al PANEL el servidor de restauración de cada base
|
|
||||||
requests>=2.31.0
|
requests>=2.31.0
|
||||||
|
|
||||||
# paramiko para transferir el .bak por SFTP/SSH a los servidores SQL externos
|
|
||||||
paramiko>=3.4.0
|
paramiko>=3.4.0
|
||||||
|
python-dotenv>=1.0.0
|
||||||
|
cryptography>=42.0.0
|
||||||
|
|
||||||
# Para empaquetado (opcional)
|
# Empaquetado (opcional, solo build)
|
||||||
pyinstaller>=6.0.0
|
pyinstaller>=6.0.0
|
||||||
|
|
||||||
# Pruebas (opcional)
|
# Pruebas (opcional)
|
||||||
|
|||||||
84
runner.py
84
runner.py
@@ -1,51 +1,91 @@
|
|||||||
"""Punto de entrada principal de la aplicación."""
|
"""Punto de entrada principal de la aplicación."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Agregar el directorio raíz al path
|
ROOT_DIR = Path(__file__).parent.resolve()
|
||||||
ROOT_DIR = Path(__file__).parent
|
if not getattr(sys, "frozen", False):
|
||||||
sys.path.insert(0, str(ROOT_DIR))
|
sys.path.insert(0, str(ROOT_DIR))
|
||||||
|
|
||||||
|
# Bootstrap y ODBC antes de importar módulos que usan pyodbc
|
||||||
|
from app.config.bootstrap import ensure_runtime_layout
|
||||||
|
from app.config.odbc_setup import configure_odbc_environment
|
||||||
|
|
||||||
|
ensure_runtime_layout()
|
||||||
|
configure_odbc_environment()
|
||||||
|
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
|
|
||||||
|
from app.config import get_launch_options, initialize_env, is_panel_configured
|
||||||
from app.ui.main_window import MainWindow
|
from app.ui.main_window import MainWindow
|
||||||
from app.utils.logger import app_logger
|
from app.utils.logger import app_logger
|
||||||
from app.constants import DATA_DIR, LOGS_DIR
|
|
||||||
|
|
||||||
|
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(description="CloudRestoreAS")
|
||||||
|
parser.add_argument(
|
||||||
|
"--minimized",
|
||||||
|
action="store_true",
|
||||||
|
help="Inicia minimizado en la bandeja del sistema",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--start-engine",
|
||||||
|
action="store_true",
|
||||||
|
help="Inicia el motor de restauración automáticamente",
|
||||||
|
)
|
||||||
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Función principal."""
|
"""Función principal."""
|
||||||
# Crear directorios necesarios
|
args = parse_args()
|
||||||
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
launch = get_launch_options()
|
||||||
LOGS_DIR.mkdir(parents=True, exist_ok=True)
|
initialize_env()
|
||||||
|
|
||||||
|
minimized = args.minimized or launch.minimized
|
||||||
|
panel_ok = is_panel_configured()
|
||||||
|
start_engine = args.start_engine or launch.start_engine
|
||||||
|
|
||||||
app_logger.info("=" * 80)
|
app_logger.info("=" * 80)
|
||||||
app_logger.info("CloudRestoreAS - Iniciando aplicación")
|
app_logger.info("CloudRestoreAS - Iniciando aplicación")
|
||||||
|
app_logger.info(f"Directorio app: {ROOT_DIR}")
|
||||||
|
if minimized:
|
||||||
|
app_logger.info("Modo: ventana oculta (--minimized o START_MINIMIZED)")
|
||||||
|
else:
|
||||||
|
app_logger.info("Modo: ventana visible; cerrar minimiza a bandeja")
|
||||||
|
if start_engine:
|
||||||
|
app_logger.info("Modo: motor auto-inicio")
|
||||||
|
if not panel_ok:
|
||||||
|
app_logger.warning(
|
||||||
|
"Servicio PANEL_BASES_ANEXO24 no configurado en config/.env — "
|
||||||
|
"complete CLOUDRESTORE_PANEL_* para enrutamiento automático."
|
||||||
|
)
|
||||||
app_logger.info("=" * 80)
|
app_logger.info("=" * 80)
|
||||||
|
|
||||||
# Configurar aplicación Qt
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setApplicationName("CloudRestoreAS")
|
app.setApplicationName("CloudRestoreAS")
|
||||||
app.setOrganizationName("Aduanasoft")
|
app.setOrganizationName("Aduanasoft")
|
||||||
|
|
||||||
# Habilitar high DPI scaling
|
|
||||||
app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
||||||
|
app.setQuitOnLastWindowClosed(False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Crear y mostrar ventana principal
|
window = MainWindow(
|
||||||
window = MainWindow()
|
minimized=minimized,
|
||||||
window.show()
|
start_engine=start_engine,
|
||||||
|
panel_configured=panel_ok,
|
||||||
app_logger.info("Ventana principal mostrada")
|
)
|
||||||
|
if not minimized:
|
||||||
# Ejecutar aplicación
|
window.show()
|
||||||
|
app_logger.info("Ventana principal mostrada")
|
||||||
|
else:
|
||||||
|
app_logger.info("Ventana oculta; icono en bandeja del sistema")
|
||||||
|
|
||||||
exit_code = app.exec()
|
exit_code = app.exec()
|
||||||
|
|
||||||
app_logger.info(f"Aplicación finalizada con código: {exit_code}")
|
app_logger.info(f"Aplicación finalizada con código: {exit_code}")
|
||||||
sys.exit(exit_code)
|
sys.exit(exit_code)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
app_logger.critical(f"Error fatal en la aplicación: {e}", exc_info=True)
|
app_logger.critical(f"Error fatal en la aplicación: {e}", exc_info=True)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
79
tests/test_bootstrap.py
Normal file
79
tests/test_bootstrap.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""Pruebas de bootstrap y carga de .env."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.config.bootstrap import ensure_runtime_layout
|
||||||
|
from app.config.env_loader import (
|
||||||
|
apply_env_overrides,
|
||||||
|
get_launch_options,
|
||||||
|
is_panel_configured,
|
||||||
|
render_env_template,
|
||||||
|
)
|
||||||
|
from app.constants import CONFIG_DIR, DEFAULT_CONFIG, DIR_ENTRADA, ENV_PATH
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_env_template_contains_app_dir(tmp_path: Path):
|
||||||
|
text = render_env_template(tmp_path)
|
||||||
|
assert str(tmp_path) in text
|
||||||
|
assert "CLOUDRESTORE_PANEL_API_URL" in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_ensure_runtime_layout_creates_structure(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.APP_DIR", tmp_path)
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.CONFIG_DIR", tmp_path / "config")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.DATA_DIR", tmp_path / "config" / "data")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.LOGS_DIR", tmp_path / "config" / "logs")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.ODBC_DIR", tmp_path / "config" / "odbc")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.SEVEN_ZIP_DIR", tmp_path / "config" / "7zip")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.ENV_PATH", tmp_path / "config" / ".env")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.DIR_ENTRADA", tmp_path / "Entrada")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.DIR_PROCESADOS", tmp_path / "Procesados")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.DIR_FALLADOS", tmp_path / "Fallados")
|
||||||
|
monkeypatch.setattr("app.config.bootstrap.DIR_TEMP", tmp_path / "Temp")
|
||||||
|
monkeypatch.setattr("app.constants.DB_PATH", tmp_path / "config" / "data" / "app.db")
|
||||||
|
|
||||||
|
ensure_runtime_layout()
|
||||||
|
|
||||||
|
assert (tmp_path / "config" / ".env").is_file()
|
||||||
|
assert (tmp_path / "Entrada").is_dir()
|
||||||
|
assert (tmp_path / "config" / "data" / "app.db").is_file()
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_panel_configured(monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.delenv("CLOUDRESTORE_PANEL_API_URL", raising=False)
|
||||||
|
monkeypatch.delenv("CLOUDRESTORE_PANEL_API_TOKEN", raising=False)
|
||||||
|
monkeypatch.delenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", raising=False)
|
||||||
|
assert not is_panel_configured()
|
||||||
|
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_PANEL_API_URL", "https://panel:3000")
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_PANEL_API_TOKEN", "secret")
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", "srv1")
|
||||||
|
assert is_panel_configured()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_launch_options_auto_start_does_not_minimize(monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_AUTO_START", "true")
|
||||||
|
monkeypatch.delenv("CLOUDRESTORE_START_MINIMIZED", raising=False)
|
||||||
|
opts = get_launch_options()
|
||||||
|
assert opts.start_engine is True
|
||||||
|
assert opts.minimized is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_launch_options_start_minimized(monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_START_MINIMIZED", "true")
|
||||||
|
opts = get_launch_options()
|
||||||
|
assert opts.minimized is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_render_env_template_documents_start_minimized(tmp_path: Path):
|
||||||
|
text = render_env_template(tmp_path)
|
||||||
|
assert "CLOUDRESTORE_START_MINIMIZED=false" in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_env_overrides_paths(monkeypatch: pytest.MonkeyPatch):
|
||||||
|
monkeypatch.setenv("CLOUDRESTORE_INPUT_FOLDER", "/tmp/in")
|
||||||
|
cfg = apply_env_overrides(DEFAULT_CONFIG.copy())
|
||||||
|
assert cfg["paths"]["input_folder"] == "/tmp/in"
|
||||||
Reference in New Issue
Block a user