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.
68 lines
3.0 KiB
Python
Executable File
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}")
|