Medido sobre el corpus: **686 de 779 recetas son HOJAS** (cero dependientes transitivos) ⇒ el 88% se puede desplegar sin provocar UNA SOLA reconstrucción extra. Las caras son pocas y conocidas: make 416 · pkgconf 360 · go 359 · binutils 343 · zlib 315 · python3 287 · samurai 272 · meson 257. El orden alfabético anterior era activamente malo: la primera tanda de la etapa 4 tocó expat, zstd y ncurses —tres bibliotecas base— y dejó 54 recetas sin artefacto vigente, incluida la cadena wlroots/sway sellada la noche anterior. Sin este orden, cada tanda pequeña provoca una cascada grande y la campaña avanza hacia atrás. Hojas primero; las ~93 con dependientes, en una ola coordinada y con la granja arriba. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
113 lines
5.8 KiB
Bash
Executable File
113 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# desplegar-strip.sh — activa `strip_debug = true` por TANDAS. Etapa 4 del SDD 23.
|
|
#
|
|
# ── QUÉ HACE Y POR QUÉ POR TANDAS ──────────────────────────────────────────────────────────────
|
|
# Activar el split de debug re-hashea la receta A PROPÓSITO (cambia el contenido del artefacto), y
|
|
# re-hashea en cascada todo lo que dependa de ella. Hacerlo de golpe sobre 1161 recetas dejaría el
|
|
# corpus entero sin sellar a la vez: días de granja antes de poder verificar NADA, y el disco
|
|
# aguantando artefactos viejos y nuevos al mismo tiempo.
|
|
# Por tandas se puede medir, verificar y podar entre medias, que es lo que hace la campaña
|
|
# reversible en vez de un salto a ciegas.
|
|
#
|
|
# ── LA DEP DE `binutils` VA EXPLÍCITA, NO INYECTADA POR EL LAB ──────────────────────────────────
|
|
# El paso de strip usa `strip --strip-debug -D` de binutils. Se podría hacer que el lab lo
|
|
# materialice solo, sin tocar las recetas — pero entonces la VERSIÓN de binutils sería un input
|
|
# invisible: dos corridas con binutils distintos darían artefactos distintos con el mismo hash. Los
|
|
# `deps` SÍ entran en `hash_inputs`, así que declararlo es lo único que mantiene el invariante.
|
|
# Cuesta una edición mecánica por receta; el invariante no se negocia por comodidad.
|
|
#
|
|
# ── EXCLUSIONES, y por qué exactamente éstas ───────────────────────────────────────────────────
|
|
# `binutils` y `make`: binutils provee el `strip`, y depende de make. Si se les activara el split se
|
|
# necesitarían a sí mismos para construirse. No es una preferencia: es la circularidad.
|
|
#
|
|
# Uso: scripts/desplegar-strip.sh --tanda N [--aplicar]
|
|
# (sin --aplicar sólo lista lo que haría)
|
|
set -uo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
|
|
N="${N:-25}"; APLICAR=0
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--tanda) N="$2"; shift 2 ;;
|
|
--aplicar) APLICAR=1; shift ;;
|
|
*) echo "opción desconocida: $1" >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
EXCLUIDAS="binutils make"
|
|
|
|
# ── ORDEN POR IMPACTO EN EL GRAFO, NO ALFABÉTICO ───────────────────────────────────────────────
|
|
# Activar `strip_debug` re-hashea la receta Y, en cascada, todo lo que dependa de ella. La primera
|
|
# tanda de la etapa 4 lo aprendió caro: tocar `expat`, `zstd` y `ncurses` —tres bibliotecas BASE—
|
|
# dejó 54 recetas sin artefacto vigente, incluida la cadena wlroots/sway sellada la noche anterior.
|
|
#
|
|
# Medido sobre el corpus: **686 de 779 recetas son HOJAS** (cero dependientes transitivos) ⇒ el 88%
|
|
# se puede desplegar sin provocar UNA SOLA reconstrucción extra. Las caras son pocas y conocidas:
|
|
# make 416 · pkgconf 360 · go 359 · binutils 343 · zlib 315 · python3 287 · samurai 272 · meson 257
|
|
# ⇒ Hojas primero; las que tienen dependientes, en una ola coordinada y con la granja arriba.
|
|
# Sin este orden, cada tanda pequeña provoca una cascada grande y la campaña avanza hacia atrás.
|
|
CANDIDATAS_ORDENADAS=$(python3 - <<'PYEOF'
|
|
import glob, re, collections, sys
|
|
sys.setrecursionlimit(10000)
|
|
deps, name_of = {}, {}
|
|
for p in glob.glob('recipes/*.toml') + glob.glob('recipes/incoming-*/*.toml'):
|
|
s = open(p, encoding='utf-8', errors='replace').read()
|
|
m = re.search(r'^name\s*=\s*"([^"]+)"', s, re.M)
|
|
n = m.group(1) if m else p.split('/')[-1][:-5]
|
|
name_of[p] = n
|
|
d = set()
|
|
mb = re.search(r'^\[deps\](.*?)(?=^\[|\Z)', s, re.M | re.S)
|
|
if mb: d.update(re.findall(r'"([a-z0-9._+-]+)"', mb.group(1)))
|
|
deps.setdefault(n, set()).update(d)
|
|
rev = collections.defaultdict(set)
|
|
for n, ds in deps.items():
|
|
for d in ds: rev[d].add(n)
|
|
def trans(n, visto=None):
|
|
if visto is None: visto = set()
|
|
for x in rev.get(n, ()):
|
|
if x not in visto: visto.add(x); trans(x, visto)
|
|
return visto
|
|
filas = [(len(trans(n)), p) for p, n in name_of.items() if p.startswith('recipes/') and '/incoming-' not in p]
|
|
filas.sort()
|
|
print('\n'.join(p for _, p in filas))
|
|
PYEOF
|
|
)
|
|
|
|
candidatas=""
|
|
for f in $CANDIDATAS_ORDENADAS; do
|
|
[ -f "$f" ] || continue
|
|
n=$(basename "$f" .toml)
|
|
case " $EXCLUIDAS " in *" $n "*) continue ;; esac
|
|
grep -q 'strip_debug' "$f" && continue # ya desplegada
|
|
grep -q 'CERRADA POR DECISIÓN' "$f" && continue # no se toca lo cerrado
|
|
grep -qE '^link\s*=' "$f" || continue # sin línea link no sé dónde insertar
|
|
candidatas="$candidatas $f"
|
|
done
|
|
|
|
total=$(echo $candidatas | wc -w)
|
|
tanda=$(echo $candidatas | tr ' ' '\n' | head -"$N")
|
|
echo "==> candidatas totales: $total · esta tanda: $(echo $tanda | wc -w)"
|
|
[ "$APLICAR" = 1 ] || { echo "$tanda" | tr ' ' '\n' | head -10 | sed 's|^| |'; echo "==> DRY-RUN: nada tocado. Repetí con --aplicar."; exit 0; }
|
|
|
|
hechas=0
|
|
for f in $tanda; do
|
|
python3 - "$f" <<'PY'
|
|
import re, sys
|
|
p = sys.argv[1]; s = open(p).read()
|
|
m = re.search(r'^(link\s*=\s*"[a-z]+")\s*$', s, re.M)
|
|
if not m: sys.exit(0)
|
|
s = s[:m.end(1)] + '\n\n# Split de la info de depuración (SDD 23 etapa 4). Entra en `hash_inputs`: re-hashea a propósito.\nstrip_debug = true' + s[m.end(1):]
|
|
# binutils en deps: el paso de strip del lab usa su `strip --strip-debug -D`.
|
|
if '"binutils"' not in s:
|
|
if re.search(r'^build\s*=\s*\[', s, re.M):
|
|
s = re.sub(r'^build\s*=\s*\[', 'build = ["binutils", ', s, count=1, flags=re.M)
|
|
elif '[deps]' in s:
|
|
s = s.replace('[deps]', '[deps]\nbuild = ["binutils"]', 1)
|
|
else:
|
|
s = s.rstrip('\n') + '\n\n[deps]\nbuild = ["binutils"]\n'
|
|
open(p, 'w').write(s)
|
|
PY
|
|
hechas=$((hechas+1))
|
|
done
|
|
echo "==> $hechas recetas con strip_debug=true (+ dep binutils)"
|
|
echo "==> siguiente: construir la tanda en la granja y verificar con scripts/verificar-repro.sh"
|