caudal/actualizar_app.sh
2026-10-13 08:01:06 -05:00

137 lines
5.6 KiB
Bash
Executable file

#!/bin/bash
# actualizar_app.sh — Trae del servidor git la última versión APROBADA (rama main).
#
# bash actualizar_app.sh ← buscar, probar y aplicar actualizaciones
# bash actualizar_app.sh --volver ← volver a la versión anterior
#
# Nunca toca tus datos, las copias de seguridad ni wheels/ (no están en el
# repositorio). Antes de aplicar prueba la versión nueva en una copia aparte y
# comprueba que lee tus datos; si algo falla, no cambia nada.
set -u
cd "$(dirname "$0")" || exit 1
export PYTHONDONTWRITEBYTECODE=1
pausa() { read -r -p "Pulsa Enter para cerrar..."; }
elegir_python() {
PY=python3
if [ -x /tmp/.cartera-venv/bin/python ]; then PY=/tmp/.cartera-venv/bin/python; fi
}
elegir_python
# Dónde está el programa ahora mismo
if [ -d programa/cartera ]; then CODIGO=programa; else CODIGO=.; fi
# El entorno vive en /tmp y desaparece al reiniciar el equipo: se recrea, para
# que las pruebas no fallen por dependencias que no están
if ! "$PY" -c "import requests, openpyxl" 2>/dev/null && [ -f "$CODIGO/entorno_python.sh" ]; then
echo "Preparando el entorno de Python (tras reiniciar el equipo, unos segundos)…"
bash "$CODIGO/entorno_python.sh"
elegir_python
fi
DATOS="$CODIGO/datos"
COPIAS="$CODIGO/backups"
command -v git >/dev/null || { echo "Falta git: sudo apt install git"; pausa; exit 1; }
[ -d .git ] || { echo "Esta carpeta aún no está enlazada con el servidor git."; pausa; exit 1; }
if [ -f "$DATOS/.cerrojo" ] && ! "$PY" -c "import fcntl, sys; fcntl.flock(open(sys.argv[1], 'a'), fcntl.LOCK_EX | fcntl.LOCK_NB)" "$DATOS/.cerrojo" 2>/dev/null; then
echo "✗ La cartera está abierta. Pulsa «Salir» en la aplicación y vuelve a ejecutar esto."
pausa; exit 1
fi
if [ "${1:-}" = "--volver" ]; then
guardada="$COPIAS/app_version_anterior"
[ -f "$guardada" ] || guardada=backups/app_version_anterior
[ -f "$guardada" ] || { echo "No hay versión anterior guardada."; pausa; exit 1; }
anterior=$(cat "$guardada")
if [ "$CODIGO" = "programa" ] && ! git cat-file -e "$anterior:programa/cartera/__init__.py" 2>/dev/null; then
echo "✗ La versión anterior es de antes de reorganizar la carpeta; no se puede volver automáticamente."
pausa; exit 1
fi
git reset --hard --quiet "$anterior" && echo "✓ Vuelto a la versión $(git log -1 --format='%h del %ad' --date=short). Tus datos no se tocan."
pausa; exit 0
fi
if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
echo "⚠ Hay cambios locales en ficheros del programa; no se actualiza para no perderlos:"
git status --short --untracked-files=no
pausa; exit 1
fi
# Con doble clic desde el gestor de archivos se hereda el agente SSH del
# escritorio (llavero), no el de la terminal: si el agente de GPG tiene claves
# (la SSH vive en la llave de seguridad), se usa ese.
if command -v gpgconf >/dev/null; then
socket=$(gpgconf --list-dirs agent-ssh-socket 2>/dev/null)
if [ -n "$socket" ] && SSH_AUTH_SOCK="$socket" ssh-add -L >/dev/null 2>&1; then
export SSH_AUTH_SOCK="$socket"
fi
fi
if command -v gpg-connect-agent >/dev/null; then
gpg-connect-agent updatestartuptty /bye >/dev/null 2>&1 # el PIN se pide en esta ventana
fi
echo "Buscando actualizaciones en el servidor git… (si la llave de seguridad parpadea, tócala)"
if ! git fetch --quiet origin main; then
echo "✗ No se pudo conectar con el servidor git (¿estás en casa o con el túnel? ¿la llave de seguridad puesta?)."
pausa; exit 1
fi
if [ "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)" ]; then
echo "✓ Ya tienes la última versión ($(git log -1 --format='%h del %ad' --date=short))."
pausa; exit 0
fi
if ! git merge-base --is-ancestor HEAD origin/main; then
echo "✗ La versión del servidor git no continúa la tuya; no se aplica automáticamente."
pausa; exit 1
fi
echo
echo "Novedades:"
git log --reverse --format=' • %s (%ad)' --date=short HEAD..origin/main
echo
echo "Ficheros que cambian:"
git diff --stat HEAD origin/main | tail -20
prueba=$(mktemp -d /tmp/cartera-prueba.XXXXXX)
trap 'rm -rf "$prueba"' EXIT
git archive origin/main | tar -x -C "$prueba"
if [ -d "$prueba/programa/cartera" ]; then codigo_nuevo="$prueba/programa"; else codigo_nuevo="$prueba"; fi
echo
echo "Probando la versión nueva en una copia aparte…"
if ! (cd "$codigo_nuevo" && "$PY" -m unittest discover -s pruebas >"$prueba/pruebas.log" 2>&1); then
echo "✗ Las pruebas de la versión nueva fallan: no se aplica nada."
tail -25 "$prueba/pruebas.log"
pausa; exit 1
fi
if [ -f "$DATOS/activos.jsonl" ]; then
if ! "$PY" -c "
import datetime as dt, sys
sys.path.insert(0, sys.argv[1])
from cartera.datos import leer
from cartera.vista import resumen
resumen(leer(sys.argv[2]), dt.date.today())" "$codigo_nuevo" "$PWD/$DATOS"; then
echo "✗ La versión nueva no puede leer tus datos: no se aplica nada."
pausa; exit 1
fi
fi
echo "✓ Pruebas superadas y tus datos se leen bien con la versión nueva."
echo
read -r -p "¿Aplicar la actualización? (s/N) " respuesta
case "$respuesta" in
s|S|si|sí|Si|Sí|SI) ;;
*) echo "No se ha cambiado nada."; pausa; exit 0 ;;
esac
mkdir -p "$COPIAS"
git rev-parse HEAD > "$COPIAS/app_version_anterior"
if [ -d "$DATOS" ]; then
tar -czf "$COPIAS/datos-$(date +%Y%m%d-%H%M%S).tar.gz" --exclude=.cerrojo --exclude=.ultima_sesion.json --exclude=./adjuntos -C "$DATOS" . 2>/dev/null
fi
if git merge --ff-only --quiet origin/main; then
echo "✓ Actualizada a: $(git log -1 --format='%h %s')"
echo " Si algo va mal: bash actualizar_app.sh --volver"
else
echo "✗ No se pudo aplicar."
fi
pausa