gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 699Rust 56Shell 36Markdown 281227 Definitions

⎇ main scripts/licencias-cargo.sh Shell · 81 lines · 5.2 KB History raw

licencias: la declaración del autor manda — y arreglo 5 recetas que ROMPÍ y commiteé c8d1357f0 · sergio ·

1#!/usr/bin/env bash
2# licencias-cargo.sh — lee la licencia que el AUTOR declara en su `Cargo.toml`, al tag exacto que la
3# receta pinea. Es la fuente más autoritativa de las tres que usamos, y corrige a las otras dos.
4#
5# ── LA JERARQUÍA DE EVIDENCIA, DE PEOR A MEJOR ──────────────────────────────────────────────────
6#   1. El nombre de la receta ......... NO es evidencia. Prohibido (ver docs/licencias-conocidas.tsv).
7#   2. La familia / URL de fuente ..... buena para agrupar (X.Org=MIT, KDE Frameworks=LGPL doble).
8#   3. La API de licencias de GitHub .. detecta el fichero LICENSE real, pero con DOS pérdidas:
9#      devuelve identificadores obsoletos y ambiguos (`GPL-3.0` sin decir -only/-or-later) y
10#      **colapsa las licencias dobles a una sola**.
11#   4. El `Cargo.toml` del autor ...... ← ESTO. Una expresión SPDX escrita por quien tiene la potestad
12#      de licenciar, sin ambigüedad y sin colapsar. Corrige los dos defectos de (3) de una vez.
13#
14# Ejemplo medido: la API dejó `fd` como `Apache-2.0`; su Cargo.toml dice `MIT OR Apache-2.0`. No era
15# falso —cumplir Apache-2.0 basta— pero perdía una opción que el autor concedió. Con esto se recupera.
16#
17# ── SE PIDE AL TAG QUE LA RECETA PINEA, NO A HEAD ───────────────────────────────────────────────
18# Ésa era la limitación registrada de la detección por API (mira la rama por defecto, no la versión
19# que empaquetamos). Acá se prueba `?ref=v<version>` y `?ref=<version>` antes de caer a HEAD, y se
20# ANOTA con qué ref se resolvió cada una, para que la tercera columna diga si el dato es exacto o
21# aproximado. Un dato con su procedencia se puede auditar; uno sin ella hay que creerlo.
22#
23# ── LO QUE NO HACE ──────────────────────────────────────────────────────────────────────────────
24# `license.workspace = true` (la licencia vive en el workspace padre) y `license-file` (licencia a
25# medida, sin SPDX) se DESCARTAN en vez de adivinarse. Y no toca las recetas que no son Cargo: los
26# módulos Go no tienen un campo equivalente en `go.mod`, así que ésos siguen dependiendo de (2) y (3).
27#
28# Uso:  scripts/licencias-cargo.sh                (escribe docs/licencias-cargo.tsv)
29#       FORZAR=1 TABLA=docs/licencias-cargo.tsv scripts/licencias.sh --sembrar
30set -uo pipefail
31ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
32SALIDA="${SALIDA:-docs/licencias-cargo.tsv}"
33JOBS="${JOBS:-12}"
34
35command -v gh >/dev/null && gh auth status >/dev/null 2>&1 || { echo "!!  'gh' ausente o sin auth"; exit 1; }
36TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
37
38# Todas las recetas con fuente en GitHub (tengan licencia o no: éste CORRIGE, no sólo rellena).
39for f in recipes/*.toml recipes/incoming-*/*.toml; do
40  [ -f "$f" ] || continue
41  u=$(grep -m1 -E '^[[:space:]]*(tarball|repo)[[:space:]]*=' "$f" 2>/dev/null)
42  case "$u" in *github.com*) ;; *) continue ;; esac
43  n=$(basename "$f" .toml)
44  v=$(awk -F'"' '/^\[/{exit} /^[[:space:]]*version[[:space:]]*=/{print $2; exit}' "$f")
45  slug=$(printf '%s\n' "$u" | sed -E 's#.*github\.com[:/]+([^/"]+)/([^/"]+).*#\1/\2#; s/\.git$//')
46  case "$slug" in */*) printf '%s\t%s\t%s\n' "$n" "$slug" "${v:-}" ;; esac
47done | sort -u > "$TMP/obj.tsv"
48
49echo "==> recetas con fuente en GitHub: $(wc -l < "$TMP/obj.tsv")"
50
51export TMP
52xargs -P "$JOBS" -I{} sh -c '
53  n=$(printf "%s" "{}" | cut -f1); slug=$(printf "%s" "{}" | cut -f2); v=$(printf "%s" "{}" | cut -f3)
54  for ref in "v$v" "$v" ""; do
55    [ -z "$v" ] && [ -n "$ref" ] && continue
56    if [ -n "$ref" ]; then q="?ref=$ref"; etiq="$ref"; else q=""; etiq="HEAD(aprox)"; fi
57    c=$(gh api "repos/$slug/contents/Cargo.toml$q" --jq ".content" 2>/dev/null) || continue
58    [ -z "$c" ] && continue
59    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}")
60    case "$lic" in
61      ""|*workspace*|*true*) break ;;
62      *) printf "%s\t%s\t%s\n" "$n" "$lic" "$etiq" >> "$TMP/ok.tsv"; break ;;
63    esac
64  done
65' < "$TMP/obj.tsv"
66
67N=$(wc -l < "$TMP/ok.tsv" 2>/dev/null || echo 0)
68EXACT=$(grep -vc 'HEAD(aprox)' "$TMP/ok.tsv" 2>/dev/null || echo 0)
69{
70  echo "# licencias-cargo.tsv — GENERADO por scripts/licencias-cargo.sh. No editar a mano."
71  echo "#"
72  echo "# La licencia que el AUTOR declara en su Cargo.toml: expresión SPDX escrita por quien tiene"
73  echo "# la potestad de licenciar. Sin ambigüedad -only/-or-later y SIN colapsar las dobles ⇒ manda"
74  echo "# sobre la detección por API de GitHub, que pierde ambas cosas. Sembrar con FORZAR=1."
75  echo "#"
76  echo "# Tercera columna = el ref con el que se resolvió. Un tag concreto significa que el dato es"
77  echo "# de la VERSIÓN QUE EMPAQUETAMOS; 'HEAD(aprox)' que no se halló el tag y puede diferir."
78  echo "# Total $N · al tag exacto $EXACT · aproximadas $((N-EXACT))"
79  sort "$TMP/ok.tsv" 2>/dev/null
80} > "$SALIDA"
81echo "==> $N licencias de Cargo.toml ($EXACT al tag exacto) → $SALIDA"