#!/usr/bin/env bash
# licencias-desambiguar.sh — resuelve `-only` vs `-or-later` en los SPDX obsoletos, CON LA CITA.
#
# ── EL PROBLEMA QUE CIERRA ─────────────────────────────────────────────────────────────────────
# La API de licencias de GitHub devuelve identificadores obsoletos (`GPL-2.0`, `GPL-3.0`, `LGPL-2.1`,
# `AGPL-3.0`). SPDX los declaró obsoletos **porque son ambiguos**: no dicen si el proyecto concede
# «sólo esta versión» o «ésta o cualquier posterior». La diferencia no es cosmética — decide con qué
# se puede combinar el paquete y bajo qué términos puede redistribuirlo quien lo reciba.
#
# ── POR QUÉ NO SE PUEDE MIRAR EL COPYING (la trampa) ───────────────────────────────────────────
# El fichero COPYING de la GPL es **idéntico** en los dos casos: es el texto de la licencia, no la
# concesión. Y encima su apéndice «cómo aplicar la licencia a tus programas» contiene literalmente la
# frase «or (at your option) any later version» ⇒ buscarla en el COPYING da SIEMPRE positivo y
# parecería evidencia siendo texto de plantilla. Es la misma trampa que la regla del `.a` no-PIC,
# donde `grep R_X86_64_32` contaba reubicaciones de `.debug_*` y mentía.
#
# La concesión vive en las **cabeceras de los fuentes** y en el README. Por eso acá se busca la frase
# en TODO el repo y se **descartan explícitamente** COPYING/LICENSE/LICENCE: si sólo aparece ahí, no
# hay evidencia y el paquete se deja para el humano.
#
# ── SE GUARDA LA CITA, NO SÓLO EL VEREDICTO ────────────────────────────────────────────────────
# Cada línea de salida lleva el fichero y la frase exacta que decidió. Una licencia es una afirmación
# legal: quien la revise tiene que poder ver POR QUÉ dice lo que dice sin repetir el trabajo. Un
# veredicto sin su prueba obliga a confiar; con la prueba, se audita en diez segundos.
#
# Ejemplo real (htop): yo lo habría puesto `-only` de memoria. `htop.c` dice «Released under the GNU
# GPLv2+» y el README «version 2 (GPL-2.0) or, at your option, any later version» ⇒ es `-or-later`.
# La memoria se equivoca; la cita no.
#
# Uso:  scripts/licencias-desambiguar.sh     (escribe docs/licencias-desambiguadas.tsv)
set -uo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
SALIDA="${SALIDA:-docs/licencias-desambiguadas.tsv}"
command -v gh >/dev/null && gh auth status >/dev/null 2>&1 || { echo "!!  'gh' ausente o sin auth"; exit 1; }
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT

# Las ambiguas con fuente en GitHub. (La búsqueda de código de GitHub sólo funciona sobre GitHub;
# el resto se queda para el humano, y eso se dice al final en vez de disimularlo.)
./scripts/licencias.sh --revisar 2>/dev/null | while IFS=$'\t' read -r n lic; do
  [ -z "${n:-}" ] && continue
  f=$(ls "recipes/$n.toml" 2>/dev/null | head -1)
  [ -z "$f" ] && f=$(ls recipes/incoming-*/"$n.toml" 2>/dev/null | head -1)
  [ -z "$f" ] && continue
  u=$(grep -m1 -E '^[[:space:]]*(tarball|repo)[[:space:]]*=' "$f" 2>/dev/null)
  case "$u" in *github.com*) ;; *) continue ;; esac
  slug=$(printf '%s\n' "$u" | sed -E 's#.*github\.com[:/]+([^/"]+)/([^/"]+).*#\1/\2#; s/\.git$//')
  case "$slug" in */*) printf '%s\t%s\t%s\n' "$n" "$lic" "$slug" ;; esac
done | sort -u > "$TMP/obj.tsv"
echo "==> ambiguas con fuente en GitHub: $(wc -l < "$TMP/obj.tsv")"

# En SERIE: la búsqueda de código de GitHub va a 10 consultas por minuto. Paralelizar sólo consigue
# que devuelva 403 y que la mitad se pierda en silencio, que es peor que tardar.
: > "$TMP/ok.tsv"; : > "$TMP/no.tsv"
while IFS=$'\t' read -r n lic slug; do
  paths=$(gh api -X GET search/code -f q="repo:$slug \"any later version\"" \
            --jq '[.items[].path] | join(" ")' 2>/dev/null)
  # Tres clases de fichero que PARECEN evidencia y no lo son. Las tres aparecieron en la primera
  # corrida, y sólo se vieron porque guardamos la cita:
  #   · ficheros de licencia  → la frase es plantilla del propio COPYING (ver cabecera);
  #   · FIXTURES DE TEST      → `caligula` "probaba" ser GPL-3.0-or-later por una frase dentro de
  #                             `checks/headless/expected.iso`, una imagen de prueba;
  #   · CÓDIGO VENDORIZADO    → `libnl` citaba `include/linux-private/linux/seg6.h`, una cabecera del
  #                             KERNEL incrustada. La licencia del kernel no es la de libnl.
  util=""
  for p in $paths; do
    bn=$(basename "$p" | tr '[:upper:]' '[:lower:]')
    case "$bn" in copying*|license*|licence*|copyright) continue ;; esac
    case "$p" in
      *test*|*Test*|*fixture*|*checks/*|*testdata/*|*.iso|*.bin|*.img) continue ;;
      *vendor/*|*third_party/*|*3rdparty/*|*linux-private/*|*/deps/*|*external/*) continue ;;
    esac
    util="$p"; break
  done
  if [ -z "$util" ]; then printf '%s\t%s\t%s\n' "$n" "$lic" "$slug" >> "$TMP/no.tsv"; sleep 6; continue; fi
  cita=$(gh api "repos/$slug/contents/$util" --jq .content 2>/dev/null | base64 -d 2>/dev/null \
           | grep -m1 -i "any later version" | tr -s ' \t' ' ' | sed 's/^ *//' | cut -c1-120)
  # ── LA CITA TIENE QUE HABLAR DE LA MISMA VERSIÓN QUE LA LICENCIA DECLARADA ───────────────────
  # `lm-sensors` estaba declarado GPL-2.0 y su cita decía «version 2.1 of the License», que es la
  # LGPL: la frase era real pero NO sostenía lo que se le atribuía. Una evidencia que habla de otra
  # licencia no es evidencia de ésta.
  ver=$(printf '%s' "$lic" | sed -E 's/^A?L?GPL-([0-9.]+).*/\1/')
  case "$cita" in
    *"$ver"*) ;;
    *) printf '%s\t%s\t%s\n' "$n" "$lic" "$slug" >> "$TMP/no.tsv"; sleep 6; continue ;;
  esac
  nuevo=$(printf '%s' "$lic" | sed -E 's/^(A?L?GPL-[0-9.]+)$/\1-or-later/')
  printf '%s\t%s\t%s :: %s\n' "$n" "$nuevo" "$util" "${cita:-(sin cita legible)}" >> "$TMP/ok.tsv"
  sleep 6
done < "$TMP/obj.tsv"

N=$(wc -l < "$TMP/ok.tsv"); M=$(wc -l < "$TMP/no.tsv")
{
  echo "# licencias-desambiguadas.tsv — GENERADO por scripts/licencias-desambiguar.sh."
  echo "# Resuelve -only vs -or-later buscando la concesión FUERA del COPYING (donde la frase es"
  echo "# plantilla y daría siempre positivo). Tercera columna: fichero :: cita que lo decidió."
  echo "# Resueltas $N · sin evidencia (quedan para el humano) $M"
  sort "$TMP/ok.tsv"
} > "$SALIDA"
echo "==> resueltas $N · sin evidencia $M → $SALIDA"
[ "$M" -gt 0 ] && { echo "==> sin evidencia:"; cut -f1 "$TMP/no.tsv" | tr '\n' ' '; echo; }
