Con `atk` arreglado, atuq llegó más lejos y murió igual, ahora con Pango:
GLib-GObject-CRITICAL: cannot register existing type 'PangoFontMap'
… decenas de líneas … tipo '<invalid>'
MISMO CUADRO, CULPABLE DISTINTO Y MÁS GRANDE. `gtk3` produce DOS objetos compartidos —libgtk-3.so y
libgdk-3.so— y libxul declara NEEDED las dos, así que se cargan siempre juntas. Con las variantes
ESTÁTICAS de sus deps, cada una se llevaba adentro su propia copia. Medido con el mismo instrumento
que cazó a atk, `nm -D --defined-only`, preguntando quién DEFINE cada símbolo:
pango_font_map_get_type → libgdk-3.so, libgtk-3.so, libgailutil-3.so
cairo_create → libgdk-3.so, libgtk-3.so
gdk_pixbuf_get_type → libgdk-3.so, libgtk-3.so
hb_buffer_create → libgdk-3.so, libgtk-3.so, libgailutil-3.so
Y se comprobó el otro lado: libxul NO embebe ninguna —enlaza libgtk-3/libgdk-3 como debe—, así que
la duplicación es toda interna del par GTK3.
Cuatro variantes nuevas: harfbuzz-shared, cairo-shared, gdk-pixbuf-shared, pango-shared. Sólo cambia
el modo de librería; se conservan todos los switches del canónico para no arrastrar deps nuevas.
DOS DEUDAS ANOTADAS, NO OLVIDADAS: `fribidi` y `pixman` siguen estáticos —no existe variante— pero
quedan embebidos en UNA sola .so cada uno, así que no hay copia que colisione; y `libepoxy` sí queda
en las dos, y se deja porque no registra tipos de GObject ni mantiene estado global. Si algún día
otra .so del mismo proceso los embebe, vuelve el cuadro.
`firefox` swapea las mismas cuatro: declarar las ESTÁTICAS junto a un gtk3 que trae las compartidas
son dos artefactos peleando por el mismo `pango.pc`, que es la otra forma conocida de este fallo.
Y `xkeyboard-config` SUBE AL CORPUS. Existía idéntica en las cuatro colas de escritorio (un solo md5
entre las cuatro, verificado antes de mover) y atuq, que vive en el corpus, no podía alcanzar
ninguna: sibling-first y después el catálogo padre, nunca una cola hermana. Sin sus datos el
navegador ni pinta («xkbcommon: failed to add default include path /usr/share/X11/xkb»). Mismo hash
en el corpus que en las colas ⇒ cero rebuilds, y las copias de las colas se quedan donde están.
109 lines
6.2 KiB
Bash
Executable File
109 lines
6.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# atuq-nested.sh — hidrata `atuq` con su cierre de runtime y lo abre como VENTANA ANIDADA en el
|
|
# compositor que ya tenés delante (waypipe, mirada, sway…). No toca la GPU como master: atuq es un
|
|
# cliente wayland más.
|
|
#
|
|
# scripts/atuq-nested.sh # abre atuq y lo deja corriendo SECS segundos
|
|
# SECS=60 scripts/atuq-nested.sh
|
|
#
|
|
# ── POR QUÉ HIDRATAR Y NO EJECUTAR DESDE EL STORE ──────────────────────────────────────────────
|
|
# El binario es musl y el host es glibc: no hay `/lib/ld-musl-x86_64.so.1` afuera. Un artefacto que
|
|
# no arranca desde la ruta del store NO está roto — corre HIDRATADO, y ésa es la prueba que vale.
|
|
#
|
|
# ── LAS FUENTES NO SON OPCIONALES ──────────────────────────────────────────────────────────────
|
|
# Un navegador sin una sola fuente arranca, pinta y muestra cuadraditos. Es el modo de fallo que ya
|
|
# nos costó una tarde en GNOME: la clausura decía 100% y la pantalla decía otra cosa. `dejavu-fonts`
|
|
# va en la lista de raíces por eso, no por completismo.
|
|
set -eu
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT"
|
|
H="$ROOT/target/release/hammer"
|
|
|
|
# ── EL ROOTFS VA EN EL MISMO MOUNT QUE EL STORE, Y NO ES UN CAPRICHO ───────────────────────────
|
|
# `hydrate` proyecta con HARDLINKS, y `linkat()` rechaza cruzar un punto de montaje aunque los dos
|
|
# lados sean el mismo filesystem. Acá el store es `/dev/sdb` bind-monteado en `hammer/store`
|
|
# mientras `work/` vive en `/dev/sdc`: hidratar a `work/…` muere con
|
|
# «Invalid cross-device link (os error 18)» — medido, no supuesto.
|
|
# El volumen entero está montado en /mnt/cosecha, así que store y destino comparten mount ahí.
|
|
# Se comprueba con `findmnt -T`, NUNCA con `stat -c %d` (que dice el device, no el mount).
|
|
STORE="${STORE:-/mnt/cosecha/store}"
|
|
RFS="${RFS:-/mnt/cosecha/escritorios/atuq-rootfs}"
|
|
ALPINE="$ROOT/.dev-fs/alpine"
|
|
SECS="${SECS:-25}"
|
|
URL="${URL:-about:support}"
|
|
|
|
# Las raíces: atuq y lo que su motor abre en RUNTIME. `wayland-protocols` y compañía no están —son
|
|
# de build— y meterlas engordaría el rootfs sin cambiar nada de lo que se ve.
|
|
RAICES="atuq gtk3 atk gdk-pixbuf pango cairo libepoxy glib-shared pcre2-shared libffi-shared
|
|
zlib-shared harfbuzz fribidi freetype-shared fontconfig-shared pixman libpng-shared
|
|
libjpeg-turbo-shared wayland libxkbcommon mesa libdrm dbus pipewire pulseaudio alsa-lib
|
|
libxml2-shared dejavu-fonts
|
|
xkeyboard-config"
|
|
# `xkeyboard-config` son DATOS, no una librería, y sin ellos el navegador ni pinta:
|
|
# xkbcommon: ERROR: failed to add default include path /usr/share/X11/xkb
|
|
# Es el mismo modo de fallo silencioso que las fuentes: nada en la clausura lo ve venir.
|
|
|
|
# ── EL ROOTFS SE REVALIDA POR HASH, NO POR EXISTENCIA ──────────────────────────────────────────
|
|
# «Ya está hidratado» es la pregunta equivocada: tras cualquier re-hash del corpus el directorio
|
|
# sigue ahí, con los artefactos VIEJOS, y el script abriría contento la versión que acabás de
|
|
# arreglar. Es la misma forma del cache-hit que congela regresiones. La pregunta correcta es si los
|
|
# hashes VIGENTES son los que están puestos, así que se anota la lista resuelta y se compara.
|
|
VIGENTES=""
|
|
faltan=""
|
|
for r in $RAICES; do
|
|
h="$("$H" --store "$STORE" hash "recipes/$r.toml" 2>/dev/null | tail -1 | sed 's/^b3://')"
|
|
if [ -z "$h" ] || [ ! -d "$STORE/$h-$r" ]; then faltan="$faltan $r"; continue; fi
|
|
VIGENTES="$VIGENTES$h-$r
|
|
"
|
|
done
|
|
# Un nodo sin artefacto NO se saltea en silencio: un rootfs al que le faltan tres paquetes arranca
|
|
# y falla tres capas más abajo.
|
|
[ -z "$faltan" ] || { echo "✗ faltan artefactos:$faltan" >&2; exit 1; }
|
|
|
|
SELLO="$RFS/.raices"
|
|
if [ "${REHIDRATAR:-0}" = "1" ] || [ ! -f "$SELLO" ] || [ "$VIGENTES" != "$(cat "$SELLO")" ]; then
|
|
# Nada de `diff <(...)`: esto es /bin/sh, y la sustitución de proceso es de bash. Un script que
|
|
# sólo funciona cuando /bin/sh resulta ser bash es una trampa que salta en otra máquina.
|
|
[ -f "$SELLO" ] && echo "==> el rootfs está DESACTUALIZADO — se rehidrata"
|
|
echo "==> hidratando $(echo $RAICES | wc -w) raíces en $RFS"
|
|
rm -rf "$RFS"; mkdir -p "$RFS"
|
|
echo "$VIGENTES" | while read -r d; do
|
|
[ -n "$d" ] && "$H" --store "$STORE" hydrate "${d%%-*}" --into "$RFS" >/dev/null
|
|
done
|
|
printf '%s' "$VIGENTES" > "$SELLO"
|
|
echo "==> hidratado: $(find "$RFS" -type f | wc -l) ficheros"
|
|
else
|
|
echo "==> rootfs al día ($(echo "$VIGENTES" | grep -c . ) raíces, hashes vigentes)"
|
|
fi
|
|
|
|
[ -n "${WAYLAND_DISPLAY:-}" ] || { echo "✗ no hay WAYLAND_DISPLAY — esto necesita una pantalla" >&2; exit 1; }
|
|
SOCK="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/$WAYLAND_DISPLAY"
|
|
[ -S "$SOCK" ] || { echo "✗ no existe el socket $SOCK" >&2; exit 1; }
|
|
echo "==> pantalla: $SOCK"
|
|
|
|
exec bwrap --overlay-src "$ALPINE" --overlay-src "$RFS" --tmp-overlay / \
|
|
--dev-bind /dev /dev --proc /proc --bind /sys /sys --tmpfs /tmp --tmpfs /run \
|
|
--ro-bind "$SOCK" /run/wayland-0 \
|
|
--uid 0 --gid 0 \
|
|
--setenv PATH /usr/bin:/bin:/usr/sbin:/sbin \
|
|
--setenv LD_LIBRARY_PATH /usr/lib:/lib \
|
|
--setenv XDG_RUNTIME_DIR /run --setenv WAYLAND_DISPLAY wayland-0 \
|
|
--setenv XDG_DATA_DIRS /usr/share --setenv HOME /root \
|
|
--setenv GDK_BACKEND wayland --setenv MOZ_ENABLE_WAYLAND 1 \
|
|
--setenv LIBGL_DRIVERS_PATH /usr/lib/dri \
|
|
--setenv MOZ_LOG_FILE /tmp/atuq-moz.log \
|
|
sh -c '
|
|
mkdir -p /root /run/cache /etc
|
|
[ -s /etc/machine-id ] || tr -d - < /proc/sys/kernel/random/uuid > /etc/machine-id
|
|
echo "=== identidad del artefacto ==="
|
|
sed -n "/^\[App\]/,/^$/p" /usr/lib/atuq/application.ini
|
|
echo "=== fuentes visibles ==="
|
|
fc-list 2>/dev/null | wc -l
|
|
timeout '"$SECS"' /usr/bin/atuq --no-remote '"$URL"' >/tmp/atuq.log 2>&1 &
|
|
PID=$!
|
|
sleep 8
|
|
echo "=== ¿vive? ==="
|
|
if kill -0 $PID 2>/dev/null; then echo " ✓ atuq corriendo (PID $PID) — mirá tu pantalla"; else echo " ✗ murió"; fi
|
|
echo "=== log ==="; tail -25 /tmp/atuq.log
|
|
wait $PID 2>/dev/null || true
|
|
'
|