diff --git a/recipes/incoming/bandwhich.toml b/recipes/bandwhich.toml similarity index 100% rename from recipes/incoming/bandwhich.toml rename to recipes/bandwhich.toml diff --git a/recipes/incoming/difftastic.toml b/recipes/difftastic.toml similarity index 100% rename from recipes/incoming/difftastic.toml rename to recipes/difftastic.toml diff --git a/recipes/incoming/fclones.toml b/recipes/fclones.toml similarity index 100% rename from recipes/incoming/fclones.toml rename to recipes/fclones.toml diff --git a/recipes/incoming/gping.toml b/recipes/gping.toml similarity index 100% rename from recipes/incoming/gping.toml rename to recipes/gping.toml diff --git a/recipes/incoming/grex.toml b/recipes/grex.toml similarity index 100% rename from recipes/incoming/grex.toml rename to recipes/grex.toml diff --git a/recipes/incoming/mcfly.toml b/recipes/mcfly.toml similarity index 100% rename from recipes/incoming/mcfly.toml rename to recipes/mcfly.toml diff --git a/recipes/incoming/miniserve.toml b/recipes/miniserve.toml similarity index 100% rename from recipes/incoming/miniserve.toml rename to recipes/miniserve.toml diff --git a/recipes/incoming/navi.toml b/recipes/navi.toml similarity index 100% rename from recipes/incoming/navi.toml rename to recipes/navi.toml diff --git a/recipes/incoming/onefetch.toml b/recipes/onefetch.toml similarity index 100% rename from recipes/incoming/onefetch.toml rename to recipes/onefetch.toml diff --git a/recipes/incoming/pastel.toml b/recipes/pastel.toml similarity index 100% rename from recipes/incoming/pastel.toml rename to recipes/pastel.toml diff --git a/recipes/incoming/viu.toml b/recipes/viu.toml similarity index 100% rename from recipes/incoming/viu.toml rename to recipes/viu.toml diff --git a/scripts/build-farm.sh b/scripts/build-farm.sh new file mode 100755 index 00000000..8a98983e --- /dev/null +++ b/scripts/build-farm.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# build-farm.sh — Etapa G: GRANJA de build paralela sobre la COLA DE STAGING (recipes/incoming/). +# El import escala (import-batch ~95% yield, cientos en minutos); el COMPILE es el cuello de botella +# (1-7 min c/u) pero es embarrassingly-parallel + cacheable por contenido (el store dedup global). Esta +# es la pieza que convierte "decenas por sesión serial" en "drenar la cola en paralelo": construye N a +# la vez, y lo que CONSTRUYE+sella lo PROMUEVE incoming/->recipes/ y lo publica al repo firmado; lo que +# falla queda staged con su motivo (MSRV, dep faltante, …) para revisión. +# +# Dos fases: (1) BUILD en paralelo (lo caro, worker pool de $JOBS) — escribe status por paquete; (2) +# PROMOTE+PUBLISH en SERIE (el index.json del repo es mutable compartido ⇒ no se paraleliza) + firma 1 vez. +# Idempotente: una receta ya sellada sale por cache-hit; re-correr sólo reintenta lo que falta. +# +# Uso: JOBS=4 scripts/build-farm.sh # drena recipes/incoming/*.toml +# JOBS=6 QUEUE=recipes/incoming scripts/build-farm.sh +# Env: JOBS (def: nproc-2), QUEUE (def recipes/incoming), STORE (def ./store), REPO (def dist/repo), +# KEY (clave de firma; def dist/keys/release.ed25519), DISTRO (def dev), HAMMER (cmd del cli), +# PROMOTE (def 1; =0 sólo construye+mide, no toca recipes/ ni el repo). +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" +QUEUE="${QUEUE:-recipes/incoming}" +STORE="${STORE:-./store}" +REPO="${REPO:-$ROOT/dist/repo}" +KEY="${KEY:-$ROOT/dist/keys/release.ed25519}" +DISTRO="${DISTRO:-dev}" +HAMMER="${HAMMER:-$ROOT/target/release/hammer}" +PROMOTE="${PROMOTE:-1}" +JOBS="${JOBS:-$(( $(nproc) - 2 ))}"; [ "$JOBS" -ge 1 ] || JOBS=1 + +FARM="$ROOT/work/farm" +rm -rf "$FARM"; mkdir -p "$FARM/log" "$FARM/status" + +queue=$(ls "$QUEUE"/*.toml 2>/dev/null || true) +[ -n "$queue" ] || { echo "cola vacía: $QUEUE/*.toml"; exit 0; } +n_total=$(printf '%s\n' "$queue" | wc -l | tr -d ' ') +echo "==> GRANJA: $n_total recetas en $QUEUE, $JOBS workers en paralelo" + +# ── Fase 1: BUILD en paralelo. Cada worker construye una receta y deja su status (.ok con hash | .fail +# con motivo). El store sella atómico y cada build usa sources/- + out/- propios +# ⇒ sin colisión entre recetas distintas. `xargs -P` es el pool. +printf '%s\n' "$queue" | xargs -P"$JOBS" -I '{}' sh -c ' + f="$1"; n=$(basename "$f" .toml); log="'"$FARM"'/log/$n.log" + H=$("'"$HAMMER"'" --store "'"$STORE"'" build "$f" 2>"$log" | tail -1 || true) + if [ "${H#b3:}" != "$H" ] && [ -n "$H" ]; then + echo "$H" > "'"$FARM"'/status/$n.ok"; printf " ✓ %-18s %s\n" "$n" "$H" + else + r=$(grep -oiE "requires rustc [0-9.]+|cannot find -l[a-z0-9]+|could not find .[a-z0-9_-]+.|error\[E[0-9]+\]|not found|unsupported|no such file" "$log" | head -1) + echo "${r:-fallo (ver log)}" > "'"$FARM"'/status/$n.fail"; printf " ✗ %-18s %s\n" "$n" "${r:-fallo}" + fi +' _ '{}' + +# ── Fase 2: PROMOTE + PUBLISH en serie (índice del repo = recurso mutable compartido). +ok=$(ls "$FARM"/status/*.ok 2>/dev/null | wc -l | tr -d ' ') +fail=$(ls "$FARM"/status/*.fail 2>/dev/null | wc -l | tr -d ' ') +echo "==> BUILD-YIELD: $ok/$n_total construyen ($fail fallan)" + +if [ "$PROMOTE" = 1 ] && [ "$ok" -gt 0 ]; then + echo "==> promoviendo + publicando $ok al repo firmado…" + for s in "$FARM"/status/*.ok; do + n=$(basename "$s" .ok) + [ -f "$QUEUE/$n.toml" ] && mv "$QUEUE/$n.toml" recipes/ + "$HAMMER" --store "$STORE" pack "recipes/$n.toml" --repo "$REPO" --distro-version "$DISTRO" --build >/dev/null 2>&1 \ + && printf " + %s\n" "$n" || printf " ! %s (pack falló)\n" "$n" + done + "$HAMMER" repo sign --repo "$REPO" --key "$KEY" >/dev/null 2>&1 && echo "==> release re-firmado" +fi + +# ── Reporte de fallos (motivo por paquete) para triage. +if [ "$fail" -gt 0 ]; then + echo "==> FALLARON ($fail) — quedan staged en $QUEUE:" + for s in "$FARM"/status/*.fail; do printf " ✗ %-18s %s\n" "$(basename "$s" .fail)" "$(cat "$s")"; done +fi +echo "==> granja: $ok promovidos, $fail staged. logs en $FARM/log/"