#!/usr/bin/env bash # licencias-cargo.sh — lee la licencia que el AUTOR declara en su `Cargo.toml`, al tag exacto que la # receta pinea. Es la fuente más autoritativa de las tres que usamos, y corrige a las otras dos. # # ── LA JERARQUÍA DE EVIDENCIA, DE PEOR A MEJOR ────────────────────────────────────────────────── # 1. El nombre de la receta ......... NO es evidencia. Prohibido (ver docs/licencias-conocidas.tsv). # 2. La familia / URL de fuente ..... buena para agrupar (X.Org=MIT, KDE Frameworks=LGPL doble). # 3. La API de licencias de GitHub .. detecta el fichero LICENSE real, pero con DOS pérdidas: # devuelve identificadores obsoletos y ambiguos (`GPL-3.0` sin decir -only/-or-later) y # **colapsa las licencias dobles a una sola**. # 4. El `Cargo.toml` del autor ...... ← ESTO. Una expresión SPDX escrita por quien tiene la potestad # de licenciar, sin ambigüedad y sin colapsar. Corrige los dos defectos de (3) de una vez. # # Ejemplo medido: la API dejó `fd` como `Apache-2.0`; su Cargo.toml dice `MIT OR Apache-2.0`. No era # falso —cumplir Apache-2.0 basta— pero perdía una opción que el autor concedió. Con esto se recupera. # # ── SE PIDE AL TAG QUE LA RECETA PINEA, NO A HEAD ─────────────────────────────────────────────── # Ésa era la limitación registrada de la detección por API (mira la rama por defecto, no la versión # que empaquetamos). Acá se prueba `?ref=v` y `?ref=` antes de caer a HEAD, y se # ANOTA con qué ref se resolvió cada una, para que la tercera columna diga si el dato es exacto o # aproximado. Un dato con su procedencia se puede auditar; uno sin ella hay que creerlo. # # ── LO QUE NO HACE ────────────────────────────────────────────────────────────────────────────── # `license.workspace = true` (la licencia vive en el workspace padre) y `license-file` (licencia a # medida, sin SPDX) se DESCARTAN en vez de adivinarse. Y no toca las recetas que no son Cargo: los # módulos Go no tienen un campo equivalente en `go.mod`, así que ésos siguen dependiendo de (2) y (3). # # Uso: scripts/licencias-cargo.sh (escribe docs/licencias-cargo.tsv) # FORZAR=1 TABLA=docs/licencias-cargo.tsv scripts/licencias.sh --sembrar set -uo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" SALIDA="${SALIDA:-docs/licencias-cargo.tsv}" JOBS="${JOBS:-12}" 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 # Todas las recetas con fuente en GitHub (tengan licencia o no: éste CORRIGE, no sólo rellena). for f in recipes/*.toml recipes/incoming-*/*.toml; do [ -f "$f" ] || continue u=$(grep -m1 -E '^[[:space:]]*(tarball|repo)[[:space:]]*=' "$f" 2>/dev/null) case "$u" in *github.com*) ;; *) continue ;; esac n=$(basename "$f" .toml) v=$(awk -F'"' '/^\[/{exit} /^[[:space:]]*version[[:space:]]*=/{print $2; exit}' "$f") 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" "$slug" "${v:-}" ;; esac done | sort -u > "$TMP/obj.tsv" echo "==> recetas con fuente en GitHub: $(wc -l < "$TMP/obj.tsv")" export TMP xargs -P "$JOBS" -I{} sh -c ' n=$(printf "%s" "{}" | cut -f1); slug=$(printf "%s" "{}" | cut -f2); v=$(printf "%s" "{}" | cut -f3) for ref in "v$v" "$v" ""; do [ -z "$v" ] && [ -n "$ref" ] && continue if [ -n "$ref" ]; then q="?ref=$ref"; etiq="$ref"; else q=""; etiq="HEAD(aprox)"; fi c=$(gh api "repos/$slug/contents/Cargo.toml$q" --jq ".content" 2>/dev/null) || continue [ -z "$c" ] && continue lic=$(printf "%s" "$c" | base64 -d 2>/dev/null | awk -F\" "/^\[/{if(t)exit; if(\$0 ~ /^\[package\]/)t=1; next} t&&/^[[:space:]]*license[[:space:]]*=/{print \$2; exit}") case "$lic" in ""|*workspace*|*true*) break ;; *) printf "%s\t%s\t%s\n" "$n" "$lic" "$etiq" >> "$TMP/ok.tsv"; break ;; esac done ' < "$TMP/obj.tsv" N=$(wc -l < "$TMP/ok.tsv" 2>/dev/null || echo 0) EXACT=$(grep -vc 'HEAD(aprox)' "$TMP/ok.tsv" 2>/dev/null || echo 0) { echo "# licencias-cargo.tsv — GENERADO por scripts/licencias-cargo.sh. No editar a mano." echo "#" echo "# La licencia que el AUTOR declara en su Cargo.toml: expresión SPDX escrita por quien tiene" echo "# la potestad de licenciar. Sin ambigüedad -only/-or-later y SIN colapsar las dobles ⇒ manda" echo "# sobre la detección por API de GitHub, que pierde ambas cosas. Sembrar con FORZAR=1." echo "#" echo "# Tercera columna = el ref con el que se resolvió. Un tag concreto significa que el dato es" echo "# de la VERSIÓN QUE EMPAQUETAMOS; 'HEAD(aprox)' que no se halló el tag y puede diferir." echo "# Total $N · al tag exacto $EXACT · aproximadas $((N-EXACT))" sort "$TMP/ok.tsv" 2>/dev/null } > "$SALIDA" echo "==> $N licencias de Cargo.toml ($EXACT al tag exacto) → $SALIDA"