Files
hammer/scripts/cosmic/hydrate-cosmic.sh
T
sergioandClaude Opus 5 b51f90ffea 🛍 cosmic: cosmic-store — sella (b3:a06437f7), y BoringSSL cruza a musl sin cmake
La quinta aplicación, y la primera de la suite que choca con que hammer es
OTRA distro: una tienda es la cara de un gestor de paquetes y el de abajo no
es el suyo. De los cuatro backends de `src/backend/`:

  flatpak     pide libflatpak (GObject) ⇒ la cadena glib COMPARTIDA más
              ostree/libsoup/gpgme: la torre de C que esta campaña no tiene
  packagekit  Rust puro (packagekit-zbus) pero necesita el DEMONIO en el bus
  rpm-ostree  irrelevante
  pkgar       el único que arranca: ni demonio ni enlace, lee el AppStream
              del sistema — o sea los .metainfo.xml que instalan las recetas

ALCANCE HONESTO: con pkgar NAVEGA, no INSTALA. Ninguna operación está
cableada al .swm de hammer (Etapa F). El camino para arreglarlo quedó
identificado y no cuesta un solo .so de C: servir
`org.freedesktop.PackageKit` sobre .swm, mismo patrón que
arje-logind-compat.

HALLAZGO REUTILIZABLE: `aws-lc-sys` (BoringSSL, C + ensamblador) compiló
bajo zig-cc/musl SIN cmake y SIN perl — ninguno de los dos está en los 182
binarios de work/builder-rootfs/usr/bin. Tomó el camino de bindings
pregenerados (`cargo:rustc-cfg=universal`) y compiló los 21 MB de
libaws_lc_crypto.a con el crate `cc`. El `Compiling cmake v0.1.58` del log
es el crate ayudante, que se compila aunque el binario no se invoque. Esto
destraba cualquier receta futura que entre con rustls por defecto, que hoy
es casi todo lo que use reqwest.

NEEDED: libxkbcommon.so.0 y libc.so, igual que cosmic-edit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 22:42:53 -04:00

175 lines
9.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# hydrate-cosmic.sh — proyecta al FHS el cierre de runtime de COSMIC desde artefactos SELLADOS del
# store, sin rebuild ni reproduce (`hammer hydrate <hash> --into`).
#
# Es el hermano de scripts/gnome/hydrate-gnome.sh y comparte con él lo que importa: 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` —el ArtifactHash de la receta de HOY, sin construir—, no por
# el más reciente del store. Con dos artefactos del mismo paquete conviviendo, la fecha miente.
#
# ── POR QUÉ LAS RAÍCES SE NOMBRAN A MANO ────────────────────────────────────────────────────────
# Porque el cierre de BUILD no es el cierre de RUNTIME, y en COSMIC la brecha es enorme: cosmic-session
# lanza a sus componentes por PATH, por nombre, con `start_component("cosmic-panel", …)`. Ninguno es
# dep de build de ningún otro, así que el grafo no los ve. La lista autoritativa es
# `cosmic-session/src/main.rs`, no una intuición sobre qué hace falta.
#
# Uso: scripts/cosmic/hydrate-cosmic.sh [receta.toml ...]
# Env: RFS (def work/cosmic-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/cosmic-rootfs}"; STORE="${STORE:-./store}"; LINK="${LINK:-static}"
HAMMER="${HAMMER:-./target/release/hammer}"; KEEP="${KEEP:-0}"
if [ $# -gt 0 ]; then
TARGETS=("$@")
else
TARGETS=(
# El compositor: la única raíz que el grafo sí explica sola (smithay enlaza sus backends).
recipes/incoming-cosmic/cosmic-comp.toml
# El gestor de sesión y su `start-cosmic`. Lanza al resto POR NOMBRE ⇒ nada de lo de abajo es
# alcanzable desde el grafo de deps.
recipes/incoming-cosmic/cosmic-session.toml
# Componentes que `cosmic-session/src/main.rs` levanta, en el orden en que los levanta.
recipes/incoming-cosmic/cosmic-bg.toml
recipes/incoming-cosmic/cosmic-idle.toml
recipes/incoming-cosmic/cosmic-panel.toml
recipes/incoming-cosmic/cosmic-osd.toml
# Los dos que —con el panel— hacen que `cosmic-session` no panickee. Son TRES los obligatorios;
# ver la tabla de `.expect` del runbook.
recipes/incoming-cosmic/cosmic-settings-daemon.toml
recipes/incoming-cosmic/cosmic-notifications.toml
# Los que el PANEL spawnea (no cosmic-session): un binario multiplexado en veinte symlinks, más
# los tres botones. Sin ellos el panel arranca, dice «Done spawning applets» y NO SE DIBUJA —
# nada que medir, nada que pintar. Invisibles para el grafo por la misma razón que los de arriba:
# se invocan por AppID.
recipes/incoming-cosmic/cosmic-applets.toml
# Los tres que esos botones abren al hacer clic. No matan la sesión si faltan (el botón queda
# muerto), pero un escritorio sin lanzador ni biblioteca de apps no se puede usar.
recipes/incoming-cosmic/cosmic-launcher.toml
# …y su MOTOR, que es otro binario y de otro repo: cosmic-launcher sólo dibuja, `pop-launcher`
# busca. Lo lanza como proceso hijo por PATH, así que —otra vez— ningún grafo de deps lo ve.
recipes/incoming-cosmic/pop-launcher.toml
# …y `qalc`, que es a lo que el plugin `calc` del lanzador le pasa la expresión. Tercer nivel de
# hijo invisible para el grafo: sesión → lanzador → pop-launcher → qalc, todos por PATH.
recipes/incoming-cosmic/libqalculate.toml
# La PRIMERA aplicación con ventana del catálogo. A diferencia de todo lo de arriba, ésta sí es
# alcanzable «desde el escritorio»: su `.desktop` no es `NoDisplay`, así que aparece en la
# biblioteca. Sigue siendo raíz a mano porque nadie la declara como dep de nada.
recipes/incoming-cosmic/cosmic-term.toml
# …y el gestor de ficheros, la segunda. Su `.desktop` tampoco es `NoDisplay`.
recipes/incoming-cosmic/cosmic-files.toml
# …y el panel de control, la tercera. Instala 32 `.desktop`: uno por página (Pantalla, Sonido,
# Red…), así que la biblioteca lista cada sección como entrada propia.
recipes/incoming-cosmic/cosmic-settings.toml
# …y el editor de texto, la cuarta. Su `.desktop` declara `MimeType=text/plain`, así que además
# de aparecer en la biblioteca es a quien el gestor de ficheros abre un `.txt`.
recipes/incoming-cosmic/cosmic-edit.toml
# …y la tienda, la quinta. Con el backend `pkgar` NAVEGA pero no INSTALA: lee el AppStream del
# sistema, o sea los `.metainfo.xml` que instalan las recetas de acá arriba.
recipes/incoming-cosmic/cosmic-store.toml
recipes/incoming-cosmic/cosmic-app-library.toml
recipes/incoming-cosmic/cosmic-workspaces-epoch.toml
# Ni binario ni librería: DATOS. El tema de iconos de COSMIC — sin él el escritorio no se ve
# «sin iconos», se ve roto, y con el cursor por software ni siquiera hay puntero.
recipes/incoming-cosmic/cosmic-icons.toml
# …y el tema del que HEREDA (`Inherits=hicolor` en su index.theme). Que un tema herede de otro es
# una relación declarada en un fichero de datos, invisible para cualquier grafo de deps.
recipes/incoming-cosmic/hicolor-icon-theme.toml
# ── LO QUE PIDE `start-cosmic`, Y NO LO PIDE NINGÚN `[deps]` ────────────────────────────────
# bash de verdad: el script usa `mapfile`, `[[ ]]` y expansión indirecta `${!var}`, así que con el
# busybox de la base metal no arranca. Y termina en `exec dbus-run-session -- cosmic-session`,
# o sea que el bus de SESIÓN es parte del arranque, no un extra.
recipes/bash.toml
recipes/dbus.toml
# ── DATOS QUE UNA LIBRERÍA DEL CIERRE NECESITA EN RUNTIME ───────────────────────────────────
# libxkbcommon entra por el grafo (la enlazan comp y clientes) pero sus TABLAS no: sin
# `/usr/share/X11/xkb` no puede compilar un keymap y el escritorio queda sin teclado. Es el mismo
# patrón que los gschemas en GNOME — la librería es la interfaz, los datos son otro paquete.
recipes/incoming-cosmic/xkeyboard-config.toml
# Idem tipografías: nada del cierre trae una sola fuente, y sin fuentes el panel sale con tofu.
recipes/incoming-cosmic/dejavu-fonts.toml
# zlib COMPARTIDA. El corpus trae `zlib` estática, que le sirve a todo el cierre de COSMIC… y no
# al driver de mesa: `kms_swrast_dri.so` es un .so que se abre con dlopen y NEEDea `libz.so.1`.
# Sin ella mesa no carga NINGÚN driver de software, GBM falla, y el compositor arranca igual y
# deja la pantalla NEGRA — el fallo aparece a tres capas de distancia de la causa.
recipes/incoming-cosmic/zlib-shared.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 libdisplay-info y nasm hubo que copiarlas a incoming-cosmic/."""
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[@]} raíces: $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)"
[ "$miss" = 0 ]