tawasuyu

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 604Rust 56Shell 36Markdown 281227 Definiciones

⎇ 593c6691772f651da43d5f0a9ce614f716a82f4f scripts/atribuir-fallos.py Python · 67 líneas · 3.0 KB Historia Quién tocó qué crudo

takana etapa 5c: comentarios de scripts, MOTD, y un BUG que introdujo la etapa 4 476168bb0 · Sergio ·

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