scripts: atribuir-fallos.py — 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 figuraban rotas (xdg-desktop-portal, gnome-desktop, gjs, gdm, gnome-session, gnome-settings-daemon, gnome-shell) 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 `fetch … name=X` y atribuir cada error al último fetch anterior. Ya destapó dos causas reales (gdk-pixbuf/gif y gtk4/PIC) y desinfló la lista de la frontera _ssl, donde `No module named` lo emite SÓLO spidermonkey.
This commit is contained in:
Executable
+62
@@ -0,0 +1,62 @@
|
||||
#!/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)
|
||||
if (m := re.search(r"hammer_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}")
|
||||
Reference in New Issue
Block a user