#!/bin/bash
# Reconstruir, publicar y estabilizar solo los proyectos que cambiaron.
# Se ejecuta desde el arbol SVN; --prueba no construye ni publica.
set -euo pipefail

AQUI=$(cd "$(dirname "$0")" && pwd)
SIRU=$(cd "$AQUI/.." && pwd)
CALCULA=$(cd "$SIRU/../calcula" && pwd)
SALIDA=$AQUI/distros/salida
ESTADO=${ACTUALIZAR_ESTADO:-$SALIDA/estado-publicado.tsv}
URL=${BAJAR_URL:-https://www.simusol.org/downloads}
PRUEBA=0
PEDIDOS=()
ORDEN=(summapack unidades slex exprtk tabular2 simplot dibuja calcula siru puyuspa)
declare -A SELECCION=()
declare -A DIRECTORIO=(
    [summapack]=$AQUI
    [unidades]=$SIRU/unidades
    [slex]=$SIRU/slex
    [exprtk]=$SIRU/exprtk
    [tabular2]=$SIRU/tabular2
    [simplot]=$SIRU/simplot
    [dibuja]=$SIRU/dibuja
    [calcula]=$CALCULA/calcula-6.0
    [siru]=$SIRU/siru
    [puyuspa]=$CALCULA/puyuspa-6.0
)

uso() {
    echo 'uso: actualizar-paquetes [--prueba] [PROYECTO...]'
    echo 'Sin proyectos, recorre todos. Requiere SVN limpio y una version nueva si cambio el contenido ya publicado.'
}
while [ $# -gt 0 ]; do
    case $1 in
        --prueba) PRUEBA=1 ;;
        -h|--help) uso; exit 0 ;;
        -*) echo "actualizar-paquetes: opcion desconocida: $1" >&2; exit 2 ;;
        *) [ -n "${DIRECTORIO[$1]:-}" ] || { echo "actualizar-paquetes: proyecto desconocido: $1" >&2; exit 2; }
           SELECCION[$1]=1 ;;
    esac
    shift
done
for p in "${ORDEN[@]}"; do
    [ ${#SELECCION[@]} -eq 0 ] || [ -n "${SELECCION[$p]:-}" ] || continue
    PEDIDOS+=("$p")
done
command -v svnversion >/dev/null || { echo 'actualizar-paquetes: falta svnversion' >&2; exit 1; }
command -v dpkg-parsechangelog >/dev/null || { echo 'actualizar-paquetes: falta dpkg-parsechangelog' >&2; exit 1; }
command -v curl >/dev/null || { echo 'actualizar-paquetes: falta curl' >&2; exit 1; }
command -v flock >/dev/null || { echo 'actualizar-paquetes: falta flock' >&2; exit 1; }

declare -A REV_ANTERIOR=() VERSION_ANTERIOR=() REVISION=() VERSION=() REMOTA=() CAMBIO=()
if [ -f "$ESTADO" ]; then
    while IFS=$'\t' read -r p rev ver; do
        [ -n "$p" ] || continue
        REV_ANTERIOR[$p]=$rev
        VERSION_ANTERIOR[$p]=$ver
    done < "$ESTADO"
fi

campo() { sed -n "s/^$2=\"\(.*\)\"$/\1/p" "$1" | tail -1; }
version_remota() {
    local p=$1 texto
    texto=$(curl -fsSL "$URL/$p.summa") || {
        echo "actualizar-paquetes: no se pudo consultar $URL/$p.summa; no se publicara a ciegas" >&2
        return 1
    }
    printf '%s\n' "$texto" | sed -n 's/^VERSION="\(.*\)"$/\1/p' | tail -1
}
registrar() {
    local p=$1 temporal
    mkdir -p "$(dirname "$ESTADO")"
    temporal=$(mktemp "$(dirname "$ESTADO")/.estado-publicado.XXXXXX")
    if [ -f "$ESTADO" ]; then
        while IFS=$'\t' read -r nombre rev ver; do
            [ "$nombre" = "$p" ] || printf '%s\t%s\t%s\n' "$nombre" "$rev" "$ver"
        done < "$ESTADO" > "$temporal"
    fi
    printf '%s\t%s\t%s\n' "$p" "${REVISION[$p]}" "${VERSION[$p]}" >> "$temporal"
    mv "$temporal" "$ESTADO"
}

# Resolver todo el plan antes de modificar un solo proyecto.
for p in "${PEDIDOS[@]}"; do
    dir=${DIRECTORIO[$p]}
    [ -x "$dir/hacer-pkg" ] || { echo "actualizar-paquetes: falta $dir/hacer-pkg" >&2; exit 1; }
    [ -f "$dir/$p.summa" ] || { echo "actualizar-paquetes: falta $dir/$p.summa" >&2; exit 1; }
    [ -z "$(svn status -q "$dir")" ] || {
        echo "actualizar-paquetes: $p tiene cambios sin registrar; comitearlos antes de producir" >&2
        exit 1
    }
    REVISION[$p]=$(svnversion "$dir")
    case ${REVISION[$p]} in *M*|*S*|*P*) echo "actualizar-paquetes: revision SVN no limpia de $p: ${REVISION[$p]}" >&2; exit 1 ;; esac
    VERSION[$p]=$(campo "$dir/$p.summa" VERSION)
    changelog=$(dpkg-parsechangelog -l "$dir/debian/changelog" -S Version)
    [ -n "${VERSION[$p]}" ] && [ "${VERSION[$p]}" = "$changelog" ] || {
        echo "actualizar-paquetes: VERSION de $p.summa y debian/changelog no coinciden (${VERSION[$p]:-vacia} / $changelog)" >&2
        exit 1
    }
    REMOTA[$p]=$(version_remota "$p")
    [ -n "${REMOTA[$p]}" ] || { echo "actualizar-paquetes: $p.summa remoto no tiene VERSION" >&2; exit 1; }
    dpkg --compare-versions "${VERSION[$p]}" ge "${REMOTA[$p]}" || {
        echo "actualizar-paquetes: $p local ${VERSION[$p]} es anterior al publicado ${REMOTA[$p]}" >&2; exit 1
    }
    if [ "${REV_ANTERIOR[$p]:-}" = "${REVISION[$p]}" ] &&
       [ "${VERSION_ANTERIOR[$p]:-}" = "${VERSION[$p]}" ] &&
       [ "${REMOTA[$p]}" = "${VERSION[$p]}" ]; then
        CAMBIO[$p]=0
        echo "$p: sin cambios (r${REVISION[$p]}, ${VERSION[$p]})"
    else
        CAMBIO[$p]=1
        echo "$p: revisar y, si corresponde, producir ${VERSION[$p]} (servidor: ${REMOTA[$p]}; SVN: ${REVISION[$p]})"
    fi
done

[ "$PRUEBA" = 0 ] || { echo 'Solo prueba: no se construyo ni publico nada.'; exit 0; }

# Una sola ejecucion a la vez; el estado se registra proyecto por proyecto
# solo despues de que --estable termina bien.
mkdir -p "$SALIDA"
exec 9>"$SALIDA/.actualizar-paquetes.lock"
flock -n 9 || { echo 'actualizar-paquetes: ya hay otra produccion en curso' >&2; exit 1; }

for p in "${PEDIDOS[@]}"; do
    [ "${CAMBIO[$p]}" = 1 ] || continue
    dir=${DIRECTORIO[$p]}
    version=${VERSION[$p]}
    echo "==> $p: generar fuentes y paquetes locales"
    "$dir/hacer-pkg"
    artefactos=$dir
    case $p in calcula|puyuspa) artefactos=$(dirname "$dir") ;; esac
    fuente="$artefactos/${p}_${version}.tar.gz"
    manifiesto="$artefactos/${p}_${version}.summa"
    [ -s "$fuente" ] && [ -s "$manifiesto" ] || {
        echo "actualizar-paquetes: $p no genero fuentes y .summa de $version" >&2; exit 1
    }
    if [ "$version" = "${REMOTA[$p]}" ]; then
        md5_remoto=$(curl -fsSL "$URL/$p/otros/${p}_${version}.tar.gz.md5" | cut -d' ' -f1) || {
            echo "actualizar-paquetes: no se pudo comprobar la fuente estable de $p" >&2; exit 1
        }
        md5_local=$(md5sum < "$fuente" | cut -d' ' -f1)
        if [ "$md5_local" != "$md5_remoto" ]; then
            echo "actualizar-paquetes: cambio $p pero conserva la version publicada $version; aumentar VERSION y debian/changelog" >&2
            exit 1
        fi
        echo "$p: las fuentes coinciden con el servidor; nada que publicar"
        registrar "$p"
        continue
    fi
    echo "==> $p: DEB, RPM y TGZ en Ubuntu 22.04"
    "$AQUI/distros/compilar" ubuntu2204 "$p"
    salida="$SALIDA/ubuntu2204"
    paquetes=$(campo "$manifiesto" PACKAGES)
    archivos=("$manifiesto" "$fuente")
    for q in $paquetes; do
        for tipo in deb rpm tgz; do
            case $tipo in
                rpm) patron="$salida/${q}-${version}."*.rpm ;;
                *) patron="$salida/${q}_${version}_"*.$tipo ;;
            esac
            compgen -G "$patron" > /dev/null || {
                echo "actualizar-paquetes: falta $tipo de $q $version; no se publica $p" >&2; exit 1
            }
            while IFS= read -r archivo; do archivos+=("$archivo"); done < <(compgen -G "$patron")
        done
    done
    echo "==> $p: subir ${#archivos[@]} archivos y marcar estable"
    "$AQUI/bin/subir-paquetes" "${archivos[@]}"
    "$AQUI/bin/subir-paquetes" --estable "$p"
    registrar "$p"
done
echo 'Produccion terminada.'
