#!/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