#!/usr/bin/bash
# Publica la cadena de Simplot sin usar binarios compilados en el anfitrion.
# Compara las fuentes versionadas, sube la revision Debian cuando cambiaron,
# prueba la construccion en ubuntu2204 y publica cada proyecto como estable.
set -euo pipefail

AQUI=$(cd "$(dirname "$0")" && pwd)
SUMMAPACK=$(cd "$AQUI/.." && pwd)
SIRU=$(cd "$SUMMAPACK/.." && pwd)
BASE=$SUMMAPACK/distros/salida/ubuntu2204
ORDEN=(summapack unidades slex exprtk tabular2 simplot)
PRUEBA=0
if [ "${1:-}" = --prueba ]; then PRUEBA=1; shift; fi
[ "$#" -eq 0 ] || { echo 'uso: publicar-cadena [--prueba]' >&2; exit 2; }

for orden in svn dpkg-parsechangelog python3 podman cmp; do
    command -v "$orden" >/dev/null || { echo "falta $orden" >&2; exit 1; }
done
temporal=$(mktemp -d "${TMPDIR:-/tmp}/publicar-cadena.XXXXXX")
trap 'rm -rf "$temporal"' EXIT

version_de() { sed -n 's/^VERSION="\([^"]*\)"$/\1/p' "$1/$2.summa" | head -1; }
paquetes_de() { sed -n 's/^PACKAGES="\([^"]*\)"$/\1/p' "$1/$2.summa" | head -1; }

cambiar_version() {
    local proyecto=$1 vieja=$2 nueva=$3 directorio=$SIRU/$1
    PROYECTO=$proyecto VIEJA=$vieja NUEVA=$nueva DIRECTORIO=$directorio python3 - <<'PY'
import os
from datetime import datetime
from email.utils import format_datetime
from pathlib import Path
from zoneinfo import ZoneInfo

p = os.environ['PROYECTO']
old = os.environ['VIEJA']
new = os.environ['NUEVA']
root = Path(os.environ['DIRECTORIO'])
manifest = root / f'{p}.summa'
changelog = root / 'debian/changelog'
m = manifest.read_text()
c = changelog.read_text()
assert m.count(f'VERSION="{old}"') == 1, manifest
assert c.startswith(f'{p} ({old}) '), changelog
manifest.write_text(m.replace(f'VERSION="{old}"', f'VERSION="{new}"', 1))
date = format_datetime(datetime.now(ZoneInfo('America/Argentina/Salta')))
entry = (f'{p} ({new}) noble; urgency=medium\n\n'
         '  * Reconstruir fuentes y binarios compatibles; verificar los paquetes\n'
         '    de la entrega en las distribuciones destinatarias.\n\n'
         f' -- Diego Saravia <dsa@unsa.edu.ar>  {date}\n\n')
changelog.write_text(entry + c)
PY
    svn commit "$directorio/$proyecto.summa" "$directorio/debian/changelog" \
        -m "Preparar $proyecto $nueva para publicacion reproducible" 
}

declare -a CAMBIADOS=()
declare -A VERSIONES=()
for proyecto in "${ORDEN[@]}"; do
    directorio=$SIRU/$proyecto
    [ -f "$directorio/$proyecto.summa" ] || { echo "falta $directorio/$proyecto.summa" >&2; exit 1; }
    [ -z "$(svn status --quiet "$directorio")" ] || {
        echo "$proyecto tiene cambios versionados pendientes: no los mezclo con una entrega" >&2; exit 1;
    }
    version=$(version_de "$directorio" "$proyecto")
    [ -n "$version" ] || { echo "$proyecto no declara VERSION" >&2; exit 1; }
    mkdir -p "$temporal/$proyecto"
    "$AQUI/crear-fuentes" "$directorio" "$temporal/$proyecto" >/dev/null
    candidato=$temporal/$proyecto/${proyecto}_${version}.tar.gz
    anterior=$directorio/${proyecto}_${version}.tar.gz
    if [ -f "$anterior" ] && cmp -s "$candidato" "$anterior"; then
        echo "$proyecto $version: fuentes sin cambios"
        continue
    fi
    caso=${version##*-}
    [[ $caso =~ ^[0-9]+$ ]] || { echo "revision Debian no numerica: $version" >&2; exit 1; }
    nueva=${version%-*}-$((caso + 1))
    echo "$proyecto: fuentes distintas; $version -> $nueva"
    CAMBIADOS+=("$proyecto")
    VERSIONES[$proyecto]=$nueva
    [ "$PRUEBA" = 0 ] || continue
    cambiar_version "$proyecto" "$version" "$nueva"
    "$AQUI/crear-fuentes" "$directorio" "$directorio"
    archivo=$directorio/${proyecto}_${nueva}.tar.gz
    grep -qxF "$archivo" "$SIRU/subir.lista" 2>/dev/null || echo "$archivo" >> "$SIRU/subir.lista"
done

[ "${#CAMBIADOS[@]}" -gt 0 ] || { echo 'No hay fuentes distintas para publicar.'; exit 0; }
[ "$PRUEBA" = 0 ] || { echo 'Solo prueba: no se modificaron fuentes ni servidor.'; exit 0; }

# Un solo entorno antiguo produce los DEB, RPM y TGZ publicables. Su
# dpkg-buildpackage ejecuta las suites sobre las fuentes exactas del tar.
"$SUMMAPACK/distros/compilar" ubuntu2204 "${CAMBIADOS[@]}"

# Antes de publicar, instalar exactamente los paquetes de salida. Las
# comprobaciones de integracion se ejecutan dentro de las distribuciones.
declare -a DEBS=() RPMS=() TGZS=()
for proyecto in "${ORDEN[@]}"; do
    version=$(version_de "$SIRU/$proyecto" "$proyecto")
    for paquete in $(paquetes_de "$SIRU/$proyecto" "$proyecto"); do
        for formato in deb rpm tgz; do
            case $formato in
                deb) patron="$BASE/${paquete}_${version}_"*.deb ;;
                rpm) patron="$BASE/${paquete}-${version}."*.rpm ;;
                tgz) patron="$BASE/${paquete}_${version}_"*.tgz ;;
            esac
            # compgen no abre ni modifica archivos; los paquetes antiguos de
            # otra version no pueden satisfacer este patron.
            mapfile -t hallados < <(compgen -G "$patron" || true)
            [ "${#hallados[@]}" -eq 1 ] || {
                echo "falta o es ambiguo $paquete $version ($formato) en $BASE" >&2; exit 1;
            }
            case $formato in
                deb) DEBS+=("${hallados[0]}") ;;
                rpm) RPMS+=("${hallados[0]}") ;;
                tgz) TGZS+=("${hallados[0]}") ;;
            esac
        done
    done
done

probar_deb() {
    local imagen=$1
    echo "==> probar paquetes DEB publicables en $imagen"
    podman run --rm -v "$BASE":/paquetes:ro "$imagen" bash -ec '
        apt-get update -qq
        apt-get install -y /paquetes/simusol-*.deb "$@"
        command -v simplot
        simplot --help >/dev/null
    ' _ "${DEBS[@]/#${BASE}//paquetes}"
}
probar_rpm() {
    local imagen=$1 gestor=$2
    echo "==> probar paquetes RPM publicables en $imagen"
    podman run --rm -v "$BASE":/paquetes:ro "$imagen" bash -ec '
        gestor=$1; shift
        if [ "$gestor" = dnf ]; then dnf install -y /paquetes/simusol-*.rpm "$@"
        else zypper --non-interactive install --allow-unsigned-rpm /paquetes/simusol-*.rpm "$@"; fi
        command -v simplot
        simplot --help >/dev/null
    ' _ "$gestor" "${RPMS[@]/#${BASE}//paquetes}"
}
probar_deb localhost/siru-ubuntu2204:latest
probar_deb localhost/siru-ubuntu2404:latest
probar_deb localhost/siru-debian13:latest
probar_rpm localhost/siru-fedora:latest dnf
probar_rpm localhost/siru-suse:latest zypper

for proyecto in "${CAMBIADOS[@]}"; do
    version=${VERSIONES[$proyecto]}
    directorio=$SIRU/$proyecto
    manifiesto=$temporal/${proyecto}_${version}.summa
    cp "$directorio/$proyecto.summa" "$manifiesto"
    archivos=("$manifiesto" "$directorio/${proyecto}_${version}.tar.gz")
    for paquete in $(paquetes_de "$directorio" "$proyecto"); do
        for formato in deb rpm tgz; do
            case $formato in
                deb) patron="$BASE/${paquete}_${version}_"*.deb ;;
                rpm) patron="$BASE/${paquete}-${version}."*.rpm ;;
                tgz) patron="$BASE/${paquete}_${version}_"*.tgz ;;
            esac
            mapfile -t hallados < <(compgen -G "$patron" || true)
            archivos+=("${hallados[@]}")
        done
    done
    "$AQUI/subir-paquetes" "${archivos[@]}"
    "$AQUI/subir-paquetes" --estable "$proyecto"
done
echo 'Cadena publicada y promovida a estable.'
