13 KiB
BUILD.md — Compilación, empaquetado y despliegue
Referencia de todos los comandos, ejecutables y scripts para generar, empaquetar, instalar y verificar CloudRestoreAS en Windows y Linux.
El ejecutable es autocontenido: no requiere Python, 7-Zip, driver ODBC ni librerías Qt instaladas en el equipo destino. Todo se embebe dentro del binario en tiempo de build.
1. Todo en una tarea (recomendado) — build-all.sh
Orquestador único. Se ejecuta desde WSL (bash). Genera Windows + Linux + los paquetes.
./build-all.sh # Windows + Linux + paquetes versionados en dist/release/
./build-all.sh --linux-only # solo Linux (Docker)
./build-all.sh --windows-only # solo Windows (PowerShell + build.ps1)
./build-all.sh --no-package # compila sin generar .tar.gz/.zip
./build-all.sh --clean # rebuild desde cero (borra venvs, bundled, dist)
./build-all.sh --publish # además publica en Gitea (ver §5; requiere GITEA_TOKEN)
./build-all.sh --help
Requisitos:
- Linux: Docker (usa
docker-build-linux.shen ubuntu:22.04). - Windows:
powershell.exeaccesible desde WSL + Python 3.11+ instalado en Windows (build.ps1lo auto-detecta en%LOCALAPPDATA%\Programs\Python\Python31X). - Es fail-soft: si no hay
powershell.exe, compila solo Linux y avisa.
El build de Windows se hace sobre la ruta
\\wsl.localhost\..., por eso tarda (~15-18 min: pip install de PySide6 + PyInstaller). El de Linux (Docker, con deps cacheadas) es rápido.
packaging/scripts/build-all.sh es un wrapper que delega en este mismo script.
2. Builds individuales
| Objetivo | Comando | Salida | Notas |
|---|---|---|---|
| Linux (Docker, recomendado) | bash packaging/scripts/docker-build-linux.sh |
dist/CloudRestoreAS |
ubuntu:22.04 con todas las deps + patchelf; garantiza autocontención |
| Linux (host) | ./build.sh |
dist/CloudRestoreAS |
Requiere que el host tenga las libs Qt/ODBC; usar solo si no hay Docker |
| Windows | .\build.ps1 (en Windows/PowerShell) |
dist\CloudRestoreAS.exe |
Auto-detecta Python 3.11+; crea venv-windows |
Ambos usan el mismo spec: packaging/CloudRestoreAS.spec (PyInstaller onefile, console=False).
3. Dependencias embebidas (build-time)
Se descargan e integran al binario. No se instalan en el destino.
| Script | Qué embebe |
|---|---|
packaging/scripts/download-bundled-deps.sh (Linux) |
7zz (7-Zip Linux), driver MS ODBC 18 + unixODBC + Kerberos/GSSAPI + libltdl + OpenSSL, y cluster Qt xcb/X11 + EGL. Aplica patchelf --set-rpath '$ORIGIN' a las .so del cluster ODBC para que resuelvan entre sí. |
packaging/scripts/download-bundled-deps.ps1 (Windows) |
7z.exe y msodbcsql18.dll. |
Versiones/URLs en packaging/bundled-versions.json.
Los binarios quedan en packaging/bundled/{linux,windows}/ (git-ignored, se generan en el build).
Ubicación en runtime (creada por el bootstrap en la primera ejecución):
config/7zip/7zz— extractor.config/odbc/lib/— driver ODBC + toda su cadena (resuelven por$ORIGIN).- Cluster Qt xcb/EGL — dentro del onefile, en
PySide6/Qt/lib.
4. Empaquetado — package-release.sh
bash packaging/scripts/package-release.sh
La versión sale de app/__init__.py (fuente única) y va en el nombre de cada paquete.
El script aborta si la versión no es puntos-y-números: el PANEL las compara como tuplas
de enteros y otro formato rompería en silencio la detección de "hay versión nueva".
Genera en dist/release/:
| Archivo | Contenido |
|---|---|
CloudRestoreAS-<version>-linux-<arch>.tar.gz |
CloudRestoreAS/ → binario + install.sh + packaging/linux/cloudrestoreas.service + LEEME.txt |
CloudRestoreAS-<version>-win-<arch>.zip |
CloudRestoreAS/ → CloudRestoreAS.exe + install.ps1 + LEEME.txt |
SHA256SUMS |
Checksums de los dos paquetes |
release.json |
Manifiesto: versión, fecha, artefactos (platform/arch/tamaño/sha256) y deps embebidas. Es lo que lee publish-release.sh para saber qué subir |
Además deja copias crudas sin versión (CloudRestoreAS.exe, CloudRestoreAS-linux) para
la verificación de autocontención de la §9. Esas no se publican.
arch se declara con CLOUDRESTORE_TARGET_ARCH (default x86_64): el .exe lo compila
el host Windows y desde WSL no hay forma de inferir su arquitectura.
5. Publicación a Gitea — publish-release.sh
Los binarios viven en el registro de paquetes genéricos de Gitea, que es la fuente de
verdad que consume el PANEL. Gitea calcula y expone el sha256 de cada archivo, así que
no hace falta mantener un manifiesto de integridad propio: el PANEL verifica sus descargas
contra ese hash.
# Requiere un PAT de Gitea con scope write:package
export GITEA_TOKEN=xxxxxxxx
bash packaging/scripts/publish-release.sh --dry-run # lista qué subiría
bash packaging/scripts/publish-release.sh # sube y verifica
bash packaging/scripts/publish-release.sh --notify-panel # y avisa al PANEL
Destino: https://git.aduanasoft.com/api/packages/ADUANASOFT/generic/cloudrestoreas/<version>/
Tras subir, el script relee la API de Gitea y compara el sha256 y el tamaño de cada
artefacto contra release.json. Si no coinciden falla: una publicación a medias no debe
pasar por buena, porque el PANEL rechazaría la descarga por hash y el error aparecería
mucho después, al intentar instalar.
Los paquetes genéricos son inmutables: reintentar la misma versión da HTTP 409. Lo
correcto es subir una versión nueva; --force borra y reemplaza, y solo aplica cuando la
versión anterior nunca se instaló en ningún servidor.
Todo en una sola tarea:
GITEA_TOKEN=xxxx ./build-all.sh --publish --notify-panel
--publish exige el build de ambas plataformas: publicar una versión a la que le falta
una dejaría en el PANEL un release que no se le puede instalar a la mitad de los servidores,
y corregirlo obligaría a quemar el número de versión.
| Variable | Default | Para qué |
|---|---|---|
GITEA_TOKEN |
— | Requerida. PAT con scope write:package |
GITEA_BASE_URL |
https://git.aduanasoft.com |
Instancia de Gitea |
GITEA_OWNER |
ADUANASOFT |
Organización dueña del paquete |
CRAS_PACKAGE |
cloudrestoreas |
Nombre del paquete genérico |
PANEL_API_URL |
— | Solo con --notify-panel |
CLOUDRESTORE_API_TOKEN |
— | Solo con --notify-panel (token de servicio del PANEL) |
Siguiente paso, en el PANEL: /versiones-cras → Sincronizar con Gitea → Activar, y de ahí Instalar / Actualizar por servidor.
6. Instalación / despliegue
Lo normal es que el PANEL instale por SSH desde /versiones-cras, sembrando además las
credenciales. Lo de abajo es el camino manual y lo que el PANEL ejecuta por dentro.
Linux — install.sh (no instala nada del sistema)
tar xzf CloudRestoreAS-<version>-linux-x86_64.tar.gz && cd CloudRestoreAS
sudo ./install.sh --service # servicio systemd 24/7 headless (recomendado en servidor)
./install.sh --desktop # autostart .desktop (requiere sesión gráfica)
./install.sh # solo instala + bootstrap; lo corres a mano
./install.sh --help
Variables: PREFIX=/opt/cloudrestoreas (destino), SERVICE_USER=<usuario> (usuario del servicio).
Detiene el servicio antes de reemplazar el binario (un ELF en ejecución da ETXTBSY) y lo
vuelve a levantar si estaba activo.
Servicio systemd:
systemctl status cloudrestoreas
journalctl -u cloudrestoreas -f
sudo systemctl restart cloudrestoreas # tras editar config/.env
Windows — install.ps1 (autocontenido, sin NSSM ni descargas)
Expand-Archive CloudRestoreAS-<version>-win-x86_64.zip -DestinationPath .
cd CloudRestoreAS
.\install.ps1 -Service # tarea programada ONSTART como SYSTEM (24/7 headless)
.\install.ps1 -Desktop # arranque al iniciar sesión (tarea ONLOGON de la app)
.\install.ps1 # solo instala + bootstrap
Get-Help .\install.ps1 -Detailed
Parámetros: -Prefix (default C:\Aduanasoft\CloudRestoreAS), -PanelEnvFile.
-Service requiere PowerShell como Administrador (la tarea corre como SYSTEM). El
arranque 24/7 se resuelve con una tarea programada, no con NSSM: descargarlo violaría la
regla de que en el servidor destino no se instala ni se baja nada.
scripts/dev-setup.ps1es otra cosa: prepara el entorno de desarrollo (Python, venv,requirements.txt) para correrpython runner.py. No sirve para desplegar el binario.
Siembra de credenciales del PANEL
Ambos instaladores aceptan un archivo KEY=valor con las claves CLOUDRESTORE_PANEL_*,
que fusionan en config/.env (replace-or-append, idempotente, con lista blanca) y luego
borran:
./install.sh --service --panel-env-file /tmp/panel.env
.\install.ps1 -Service -PanelEnvFile C:\Temp\panel.env
Va por archivo y no por argumentos a propósito: un token en la línea de comandos queda
visible en ps y en el historial del servidor destino.
7. Ejecución manual y flags del binario
# Linux servidor sin pantalla (headless): motor de restauración sin GUI
QT_QPA_PLATFORM=offscreen ./CloudRestoreAS --start-engine --headless
# Linux con escritorio o Windows: abre la GUI normal
./CloudRestoreAS
| Flag / variable | Efecto |
|---|---|
--start-engine |
Inicia el motor de restauración al arrancar |
--headless |
Fuerza modo sin interfaz (Qt offscreen), para servidores sin display |
--minimized |
Inicia minimizado en la bandeja |
--version |
Imprime CloudRestoreAS <version> (<platform>/<arch>) y termina. En Windows requiere consola del padre (el .exe es console=False); el instalador remoto prefiere leer config/.version |
QT_QPA_PLATFORM=offscreen |
Plataforma Qt sin display (el binario ya cae a esto automáticamente si no hay DISPLAY/WAYLAND_DISPLAY en Linux) |
En Linux sin DISPLAY, el binario selecciona offscreen solo; con display usa xcb.
8. Configuración (primera ejecución)
El binario crea automáticamente: config/, config/.env, Entrada/, Procesados/,
Fallados/, Temp/. Editar config/.env:
CLOUDRESTORE_AUTO_START=true # el motor arranca solo
CLOUDRESTORE_PANEL_API_URL=... # servicio PANEL_BASES_ANEXO24 (enrutamiento)
CLOUDRESTORE_PANEL_API_TOKEN=...
CLOUDRESTORE_PANEL_INSTANCE_KEY=...
El PANEL entrega el servidor SQL destino y su data_folder. Con SQL Server sobre Linux
serán rutas POSIX (p. ej. /var/opt/mssql/data); el RESTORE ... MOVE adapta el separador
automáticamente según el formato del data_folder.
9. Verificación de autocontención (contenedor pelado)
Confirma que el binario Linux corre sin instalar NADA del sistema:
docker run --rm -v "$PWD/dist:/dist:ro" debian:12-slim bash -c '
cp /dist/CloudRestoreAS /root/app && cd /root
QT_QPA_PLATFORM=offscreen timeout 12 ./app --headless --start-engine 2>&1 | \
grep -iE "offscreen|Ventana principal|Traceback|platform plugin"
# ODBC: driver + cadena resuelven por $ORIGIN (debe dar 0)
ldd /root/config/odbc/lib/libmsodbcsql-18*.so* 2>&1 | grep -c "not found"
# 7-Zip embebido
/root/config/7zip/7zz | head -1
'
Esperado: arranca en offscreen sin errores Qt, 0 deps ODBC faltantes, 7zz ejecuta.
10. Artefactos y ubicaciones
| Ruta | Qué es |
|---|---|
dist/CloudRestoreAS |
Binario Linux onefile |
dist/CloudRestoreAS.exe |
Ejecutable Windows onefile |
dist/release/CloudRestoreAS-<version>-*.{tar.gz,zip} |
Paquetes de despliegue publicables (binario + instalador + docs) |
dist/release/release.json |
Manifiesto de la versión (lo consume publish-release.sh) |
dist/release/SHA256SUMS |
Checksums de los paquetes |
config/.version |
Sello de la versión que corrió (lo lee el instalador remoto por SFTP) |
config/.bundled_deps |
Sello del bundled-versions.json desplegado; si cambia, se re-copian config/7zip y config/odbc |
packaging/bundled/{linux,windows}/ |
Deps embebidas (generadas en build; git-ignored) |
venv-linux/, venv-windows/ |
Entornos virtuales de build (git-ignored) |
11. Scripts de referencia rápida
| Script | Propósito |
|---|---|
build-all.sh |
Todo en uno (Windows + Linux + paquetes) desde WSL |
build.sh / build.ps1 |
Build individual Linux / Windows |
packaging/scripts/docker-build-linux.sh |
Build Linux en contenedor controlado |
packaging/scripts/download-bundled-deps.sh / .ps1 |
Descarga+embebe deps |
packaging/scripts/package-release.sh |
Genera los paquetes versionados + SHA256SUMS + release.json |
packaging/scripts/publish-release.sh |
Publica en los paquetes genéricos de Gitea y verifica el sha256 |
install.sh / install.ps1 |
Instalador de despliegue Linux / Windows (autocontenidos) |
scripts/dev-setup.ps1 |
Entorno de desarrollo en Windows (Python + venv). No sirve para desplegar |
packaging/linux/cloudrestoreas.service |
Unit systemd (24/7 headless) |