Files
takana/scripts/atribuir-fallos.py
T
Sergio 476168bb07 takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4
250 líneas de comentario en 151 scripts. Control verificado: el diff no toca
NI UNA línea que no empiece por #, y la sintaxis de los 151 pasa.

El barrido saltea heredocs y cadenas triples, y el guardián DISPARÓ 3 veces:
las tres eran el MOTD que el script escribe DENTRO de la imagen construida —
texto del producto, no comentario del script. Se cambiaron aparte y a
propósito, que es rebranding, no limpieza.

Y el hallazgo caro:  casaba contra ,
que es el TARGET de tracing — o sea el module_path!, o sea el nombre del crate.
La etapa 4 lo movió a  y el script quedó casando NADA. No fallaba:
imprimía cero atribuciones, indistinguible de un log sin problemas. Comprobado
con el binario (RUST_LOG=info sobre zlib), no deducido. Ahora acepta las dos, y
tiene que seguir aceptándolas porque los logs viejos en disco dicen la vieja.

Además 14 rutas de módulo  en docs, que el barrido anterior no tocó
porque  no es frontera de palabra.
2026-09-09 19:28:48 +00:00

68 lines
3.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""atribuir-fallos.py — dice QUÉ receta EMITE cada error, no cuál lo sufre.
El driver marca FALLA en la receta que invocó, pero `hammer build` construye deps
recursivamente: si una dep muere, la FALLA sale a nombre del dependiente. El 2026-08-27
siete recetas (xdg-desktop-portal, gnome-desktop, gjs, gdm, gnome-session,
gnome-settings-daemon, gnome-shell) figuraban como rotas y ninguna lo estaba: los 1978
errores los emitía `gdk-pixbuf`. Los tiempos de 2-10 s son la firma — demasiado rápido
para ser un build propio.
Método: quitar ANSI, partir el log por los marcadores `hammer_build: fetch … name=X` y
atribuir cada línea de error al último `fetch` anterior.
Uso: scripts/atribuir-fallos.py [work/reconstruccion-detalle.log] [--desde 2026-08-27T03:]
"""
import re, sys, bisect, collections
PATRONES = [
("PIC", r"recompile with -fPIC"),
("_ssl", r"No module named '_ssl'"),
("modulo", r"ModuleNotFoundError: No module named"),
("ninja", r"ninja: subcommand failed"),
("FAILED", r"^FAILED:"),
("fase", r"Error: build phase falló"),
("undef", r"undefined (?:reference|symbol)"),
("nospace", r"No space left on device"),
]
log = sys.argv[1] if len(sys.argv) > 1 and not sys.argv[1].startswith("--") else "work/reconstruccion-detalle.log"
desde = None
if "--desde" in sys.argv:
desde = sys.argv[sys.argv.index("--desde") + 1]
raw = re.sub(r"\x1b\[[0-9;]*m", "", open(log, encoding="utf-8", errors="replace").read())
lineas = raw.splitlines()
if desde:
ini = next((j for j, l in enumerate(lineas) if desde in l), 0)
lineas = lineas[ini:]
marcas = [(i, m.group(1)) for i, l in enumerate(lineas)
# Las DOS formas del target de tracing (ADR 0016): el target es el module_path!, o sea
# el nombre del crate, que pasó de `hammer_build` a `takana_build` en la etapa 4. Hay que
# aceptar las dos porque los logs VIEJOS que ya están en disco dicen la forma vieja — y
# porque este script no falla si no casa: atribuye cero fallos y se ve igual que un log
# sin problemas.
if (m := re.search(r"(?:hammer|takana)_build: fetch hash=\S+ name=(\S+)", l))]
if not marcas:
print("sin marcadores `fetch` en la ventana — ¿log equivocado o --desde muy tarde?")
sys.exit(1)
idx = [i for i, _ in marcas]
print(f"{len(marcas)} builds arrancados en la ventana\n")
tabla = collections.defaultdict(collections.Counter)
for etiqueta, pat in PATRONES:
rx = re.compile(pat)
for i, l in enumerate(lineas):
if rx.search(l):
k = bisect.bisect_right(idx, i) - 1
tabla[marcas[k][1] if k >= 0 else "(antes de la ventana)"][etiqueta] += 1
if not tabla:
print("ningún error reconocido")
else:
print(f"{'receta que EMITE':32} errores")
for receta, c in sorted(tabla.items(), key=lambda kv: -sum(kv[1].values())):
det = " ".join(f"{k}={v}" for k, v in c.most_common())
print(f" {receta:30} {det}")