adwaita-icon-theme b3:429aef43 + hicolor-icon-theme. No es cosmética: con el cursor por SOFTWARE —obligatorio en virtio-gpu— mutter dibuja la imagen que le da el tema, y sin tema el puntero se movía INVISIBLE. Ahora se ve en la captura, y la notificación del shell tiene su icono. Colores distintos 582 → 618. hicolor arrastrada por `Inherits=hicolor` del index.theme de Adwaita: la cadena de fallback tiene que terminar en algo que sea un TEMA (con su index.theme), no sólo un directorio. No trae un solo icono propio — es el contrato, no el contenido. Dos gotchas medidos: - **hicolor 0.18 pasó de autotools a meson**: su tarball ya no trae `configure` (127). - adwaita declara `gtk-update-icon-cache` como `required: true` para un `add_install_script` que **su propio autor marcó `skip_if_destdir: true`** — exige un binario que en un build empaquetado no puede ejecutar. Se borran los dos bloques. `required: false` NO alcanza: meson no propaga el disabler dentro de add_install_script y revienta con «Unhandled python exception». Se descartó declarar gtk4 como dep: acoplaría el hash de un paquete de DATOS al del toolkit. **El setuid del launch-helper es la causa raíz de dos síntomas, no de uno.** El `dbus-daemon-launch-helper` comprueba sus propios permisos antes de activar nada y se niega si no es setuid root — de ahí el «The permission of the setuid helper is not correct» de colord. Sin eso NINGUNA activación por bus de sistema funciona, que es también por qué UPower timeouteaba a los 25s. La imagen ahora lo deja root:messagebus 4750. Y `gnome-start` lanza upowerd, pero **verificando**: la primera versión decía «lanzado» y el shell seguía esperando 25s. Un pid no es un servicio. Ahora comprueba que siga vivo y, si murió, vuelca su log. Además crea los directorios de estado que upower deriva de --prefix y sin los cuales se muere en silencio. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
128 lines
6.2 KiB
Bash
Executable File
128 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# hydrate-gnome.sh — proyecta al FHS el cierre de runtime de una receta GNOME, desde artefactos
|
|
# SELLADOS del store, sin rebuild ni reproduce (`hammer hydrate <hash> --into`).
|
|
#
|
|
# DIFERENCIA CON scripts/kde/hydrate-from-store.sh, y por qué importa: aquél resuelve el cierre desde
|
|
# un `index.json` de repo y elige el artefacto por MTIME con un CUTOFF ("el más nuevo anterior a hoy").
|
|
# Eso es una heurística: si dos artefactos del mismo paquete conviven en el store, la fecha no dice
|
|
# cuál corresponde a la receta VIGENTE. Acá el cierre sale del GRAFO REAL de recetas (`[deps].build`,
|
|
# resolución hermano→padre, la misma que usa hammer) y el artefacto se elige por `hammer hash`, que
|
|
# calcula el ArtifactHash de la receta de HOY sin construir. O sea: cero ambigüedad, y si falta algo
|
|
# el reporte dice exactamente qué receta y con qué hash lo buscaba.
|
|
#
|
|
# Uso: scripts/gnome/hydrate-gnome.sh [receta.toml ...]
|
|
# Env: RFS (def work/gnome-rootfs) destino
|
|
# STORE (def ./store)
|
|
# LINK (def static) static=hardlink | dynamic=patchelf
|
|
# KEEP (def 0) 1 = no borrar el RFS previo
|
|
set -uo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
|
RFS="${RFS:-work/gnome-rootfs}"; STORE="${STORE:-./store}"; LINK="${LINK:-static}"
|
|
HAMMER="${HAMMER:-./target/release/hammer}"; KEEP="${KEEP:-0}"
|
|
# Por defecto se hidratan DOS raíces, no una. accountsservice no es dep de build de gnome-shell —no
|
|
# aparece en su meson.build ni en su cierre— sino dep de RUNTIME: la capa JS del shell hace
|
|
# `imports.gi.AccountsService` y gjs resuelve el typelib al arrancar. Todo lo que el shell carga por
|
|
# `imports.gi.*` es invisible al grafo de deps, así que hay que nombrarlo acá o no entra al rootfs.
|
|
# El cierre de BUILD no es el cierre de RUNTIME; ésta es la lista de las raíces que faltan.
|
|
# (no `${@:-...}`: con dos valores por defecto y comillas, bash los pasaría como UN solo argumento)
|
|
if [ $# -gt 0 ]; then
|
|
TARGETS=("$@")
|
|
else
|
|
TARGETS=(
|
|
recipes/incoming-gnome/gnome-shell.toml
|
|
recipes/incoming-gnome/accountsservice.toml # imports.gi.AccountsService
|
|
recipes/incoming-gnome/gi-foreign-typelibs.toml # DBus-1.0/cairo-1.0, que Gdk y Atspi incluyen
|
|
# El resto sale de `js/misc/dependencies.js` del shell — la lista donde DECLARA qué typelibs
|
|
# exige al arrancar. Cerrarlas de una evita el bucle de «arrancar, ver qué falta, rehacer imagen».
|
|
recipes/incoming-gnome/libgdm.toml # imports.gi.Gdm
|
|
recipes/incoming-gnome/geoclue.toml # imports.gi.Geoclue
|
|
recipes/incoming-gnome/libgweather.toml # imports.gi.GWeather
|
|
recipes/incoming-gnome/upower.toml # imports.gi.UPowerGlib
|
|
recipes/incoming-gnome/librsvg.toml # imports.gi.Rsvg
|
|
recipes/incoming-gnome/ibus.toml # imports.gi.IBus
|
|
# Y ésta NO sale de la lista del shell: la pide el propio gjs desde su JS embebido
|
|
# (`imports.gi.versions.GIRepository = '2.0'`). Dep de runtime del INTÉRPRETE.
|
|
recipes/incoming-gnome/gi-girepository-typelib.toml
|
|
# Ni typelib ni librería: los GSCHEMAS de gnome-settings-daemon. El demonio está aparcado
|
|
# (GTK3/X11) pero el shell lee sus esquemas al construir los quick settings, y si faltan la
|
|
# excepción ocurre DENTRO de Main.start() ⇒ el panel no se arma y la pantalla queda negra.
|
|
recipes/incoming-gnome/gsd-schemas.toml
|
|
# Ni typelib ni esquema: DATOS. `adwaita-icon-theme` trae los iconos y —lo que importa para que
|
|
# el escritorio sea usable— los CURSORES. Con el cursor por software (obligatorio en virtio-gpu)
|
|
# y sin tema, el puntero se mueve invisible. Arrastra hicolor-icon-theme por `Inherits=hicolor`.
|
|
recipes/incoming-gnome/adwaita-icon-theme.toml
|
|
)
|
|
fi
|
|
|
|
# ── cierre transitivo por el grafo de recetas, en orden topológico ──────────────────────────────
|
|
PLAN=$(python3 - "${TARGETS[@]}" <<'PY'
|
|
import sys, tomllib
|
|
from pathlib import Path
|
|
|
|
def resolve(base_dir: Path, dep: str) -> Path | None:
|
|
"""Misma regla que hammer_build::resolve_dep_path: HERMANO primero, luego el catálogo PADRE.
|
|
Nunca de reojo a otra cola — por eso icu4c hubo que copiarla a incoming-gnome/."""
|
|
sib = base_dir / f"{dep}.toml"
|
|
if sib.exists():
|
|
return sib
|
|
par = base_dir.parent / f"{dep}.toml"
|
|
return par if par.exists() else None
|
|
|
|
seen, order, missing = set(), [], []
|
|
|
|
def visit(path: Path):
|
|
p = path.resolve()
|
|
if p in seen:
|
|
return
|
|
seen.add(p)
|
|
try:
|
|
r = tomllib.loads(p.read_text())
|
|
except Exception as e:
|
|
print(f"!PARSE\t{p}\t{e}", file=sys.stderr)
|
|
return
|
|
for d in r.get("deps", {}).get("build", []):
|
|
q = resolve(p.parent, d)
|
|
if q is None:
|
|
missing.append((p.name, d))
|
|
else:
|
|
visit(q)
|
|
order.append((p, r.get("name", p.stem)))
|
|
|
|
for t in sys.argv[1:]:
|
|
visit(Path(t))
|
|
|
|
for recipe, dep in missing:
|
|
print(f"!NORECIPE\t{recipe}\t{dep}", file=sys.stderr)
|
|
for p, name in order:
|
|
print(f"{p}\t{name}")
|
|
PY
|
|
)
|
|
|
|
[ "$KEEP" = 1 ] || rm -rf "$RFS"
|
|
mkdir -p "$RFS"
|
|
total=$(printf '%s\n' "$PLAN" | grep -c . || true)
|
|
echo "==> cierre de ${TARGETS[*]}: $total recetas → $RFS (link=$LINK)"
|
|
|
|
ok=0; miss=0; MISSING=""
|
|
while IFS=$'\t' read -r path name; do
|
|
[ -n "$path" ] || continue
|
|
h=$("$HAMMER" --store "$STORE" hash "$path" 2>/dev/null | tail -1)
|
|
if [ -z "$h" ]; then
|
|
printf " ✗ %-28s (hash falló)\n" "$name"; miss=$((miss+1)); MISSING="$MISSING $name"; continue
|
|
fi
|
|
hex="${h#b3:}"
|
|
if [ ! -d "$STORE/$hex-$name" ]; then
|
|
printf " ✗ %-28s %s NO-SELLADO\n" "$name" "${hex:0:12}"; miss=$((miss+1)); MISSING="$MISSING $name"; continue
|
|
fi
|
|
if "$HAMMER" --store "$STORE" hydrate "$hex" --into "$RFS" --link "$LINK" >/dev/null 2>&1; then
|
|
ok=$((ok+1))
|
|
else
|
|
printf " ✗ %-28s %s (hydrate falló)\n" "$name" "${hex:0:12}"; miss=$((miss+1)); MISSING="$MISSING $name"
|
|
fi
|
|
done <<< "$PLAN"
|
|
|
|
echo "==> $ok proyectados · $miss faltantes"
|
|
[ -n "$MISSING" ] && echo " faltan:$MISSING"
|
|
echo " binarios: $(find "$RFS" -type f -perm -u+x 2>/dev/null | wc -l) · .so: $(find "$RFS" -name '*.so*' 2>/dev/null | wc -l) · typelibs: $(find "$RFS" -name '*.typelib' 2>/dev/null | wc -l)"
|
|
[ "$miss" = 0 ]
|