From 1c3e1851679d11c589554b4e94a94af320dc2b3b Mon Sep 17 00:00:00 2001 From: Sergio Date: Wed, 9 Sep 2026 19:14:49 +0000 Subject: [PATCH] takana: las variables de entorno leen las dos formas, gana la nueva MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TAKANA_X con caída a HAMMER_X (ADR 0016). No es un sed: estas variables son contrato de usuario —knobs del instalador, el entorno del worker, mirror-env.sh— y viven en perfiles de shell y units FUERA del repo, así que un renombre duro no falla ruidosamente: la variable no aparece, se toma el default y el build se comporta distinto sin que nada lo diga. Rust: takana_core::env::{var,var_os} toma el nombre canónico y deriva el viejo cambiando el prefijo — se le pasa TAKANA_* para que un grep del nombre nuevo encuentre todas las lecturas. 5 tests, con DOS controles negativos: sin ninguna de las dos no hay valor, y un nombre sin prefijo no inventa una caída. Migrados los 17 sitios directos y los indirectos que el grep no mostraba (bases_de_mirror, las constantes de kernel_cmd, ROOT_ENV de qorpa, env_path de recover). takana-recover lleva la caída inline: es un mini-binario que se copia a /usr/sbin y no vale arrastrarle una dep entera por dos líneas. Scripts: 30 lecturas pasan a default, manteniendo el nombre INTERNO de la variable para no tocar sus 190 usos. Y donde el script EXPORTA en vez de leer, se ponen LAS DOS (mirror-env.sh y el fragmento in-VM de bootstrap): ahí el lector puede ser un binario viejo —worker sin recompilar, el /usr/bin/hammer pinado del baseline— que sólo conoce HAMMER_*. La caída sirve para lectores nuevos; los viejos necesitan que la vieja siga puesta. Verificado de punta a punta con el binario, no sólo con unit tests: HAMMER_LAB sigue surtiendo efecto, TAKANA_LAB hace lo mismo, y con las dos gana TAKANA_LAB. 605 tests en verde y el hash de zlib sigue en b3:dc363f26… , intacto. Cambio de comportamiento que va aparte y hay que decir: el hostname por defecto de una instalación nueva pasa de 'hammer' a 'takana' (sólo si no se fija ninguna de las dos variables). NO se tocan: las rutas /var/lib/hammer de sistemas instalados, el volid HAMMER_LIVE del ISO, ni el namespace HARKAQ_*, que es de otro subsistema. --- crates/hammerd/tests/bus_e2e.rs | 2 +- crates/takana-agent/src/translator_claude.rs | 14 ++-- crates/takana-bootstrap/src/lib.rs | 8 ++- crates/takana-build/src/config.rs | 18 ++--- crates/takana-build/src/fetch.rs | 20 +++--- crates/takana-build/src/hydrate.rs | 4 +- crates/takana-build/src/lib.rs | 2 +- crates/takana-build/tests/end_to_end_grep.rs | 6 +- crates/takana-cli/src/kernel_cmd.rs | 12 ++-- crates/takana-cli/src/main.rs | 2 +- crates/takana-cli/src/qorpa.rs | 8 +-- crates/takana-cli/tests/swm_roundtrip.rs | 2 +- crates/takana-core/src/env.rs | 72 ++++++++++++++++++++ crates/takana-core/src/lab.rs | 2 +- crates/takana-core/src/lib.rs | 1 + crates/takana-core/src/query.rs | 8 +-- crates/takana-overlay/tests/overlayfs_e2e.rs | 14 ++-- crates/takana-recover/src/main.rs | 24 +++++-- scripts/alpine-import.sh | 2 +- scripts/build-farm.sh | 2 +- scripts/cosmic/hydrate-cosmic.sh | 2 +- scripts/farm/build-timed.sh | 2 +- scripts/farm/campana-deuda.sh | 4 +- scripts/farm/cosecha-cron.sh | 2 +- scripts/farm/farm-worker-loop.sh | 2 +- scripts/farm/harkaq-campana-vol.sh | 2 +- scripts/farm/harkaq-campana.sh | 2 +- scripts/farm/harvest-go.sh | 2 +- scripts/farm/migra-zig.sh | 2 +- scripts/farm/saldar-deuda-static.sh | 2 +- scripts/farm/tandas.sh | 2 +- scripts/farm/vps-setup.sh | 2 +- scripts/fuentes/mirror-env.sh | 12 +++- scripts/gnome/hydrate-gnome.sh | 2 +- scripts/hammer-live-install.sh | 17 ++--- scripts/harkaq/harkaq-trace-build.sh | 2 +- scripts/install-image-efi.sh | 2 +- scripts/kde/complete-closure.sh | 2 +- scripts/kde/hydrate-fhs.sh | 2 +- scripts/kde/hydrate-from-store.sh | 2 +- scripts/mirada-usb.sh | 2 +- scripts/nix-import.sh | 2 +- scripts/pin-recipes.sh | 2 +- scripts/qorpa/evidence-probe.sh | 2 +- scripts/qorpa/pressure-vessel-probe.sh | 2 +- scripts/reconstruir-corpus.sh | 2 +- scripts/selfhost-verify.sh | 2 +- scripts/static-audit.sh | 2 +- scripts/store-gc.sh | 2 +- scripts/verificar-repro.sh | 2 +- 50 files changed, 203 insertions(+), 107 deletions(-) create mode 100644 crates/takana-core/src/env.rs diff --git a/crates/hammerd/tests/bus_e2e.rs b/crates/hammerd/tests/bus_e2e.rs index 1eae79bb..1cc5b29b 100644 --- a/crates/hammerd/tests/bus_e2e.rs +++ b/crates/hammerd/tests/bus_e2e.rs @@ -4,7 +4,7 @@ //! cliente, completamos el handshake y ejercitamos los caminos no-pesados (`query`, errores). //! //! `compile` real no se ejercita aquí — depende del lab + red, ya cubierto por el e2e de -//! grep gated en `HAMMER_NETWORK_TESTS`. Lo que sí verificamos es que un `compile` SIN la +//! grep gated en `TAKANA_NETWORK_TESTS`. Lo que sí verificamos es que un `compile` SIN la //! capacidad devuelve `Error{code:"no_cap"}`, lo que prueba el dispatcher + el gate. // El binario no expone una API pública; importamos sus módulos privados desde diff --git a/crates/takana-agent/src/translator_claude.rs b/crates/takana-agent/src/translator_claude.rs index f2118456..bb95c1fc 100644 --- a/crates/takana-agent/src/translator_claude.rs +++ b/crates/takana-agent/src/translator_claude.rs @@ -78,8 +78,8 @@ pub struct ClaudeConfig { } impl ClaudeConfig { - /// Construye desde env vars: `ANTHROPIC_API_KEY` (obligatoria), `HAMMER_LLM_MODEL`, - /// `HAMMER_LLM_BASE_URL`, `HAMMER_LLM_EFFORT`. + /// Construye desde env vars: `ANTHROPIC_API_KEY` (obligatoria), `TAKANA_LLM_MODEL`, + /// `TAKANA_LLM_BASE_URL`, `TAKANA_LLM_EFFORT`. pub fn from_env() -> Result { let api_key = std::env::var("ANTHROPIC_API_KEY").map_err(|_| { TranslateError::Model( @@ -89,12 +89,12 @@ impl ClaudeConfig { })?; Ok(Self { api_key, - model: std::env::var("HAMMER_LLM_MODEL") - .unwrap_or_else(|_| "claude-opus-4-8".into()), + model: takana_core::env::var("TAKANA_LLM_MODEL") + .unwrap_or_else(|| "claude-opus-4-8".into()), max_tokens: 8192, - base_url: std::env::var("HAMMER_LLM_BASE_URL") - .unwrap_or_else(|_| "https://api.anthropic.com".into()), - effort: std::env::var("HAMMER_LLM_EFFORT").unwrap_or_else(|_| "high".into()), + base_url: takana_core::env::var("TAKANA_LLM_BASE_URL") + .unwrap_or_else(|| "https://api.anthropic.com".into()), + effort: takana_core::env::var("TAKANA_LLM_EFFORT").unwrap_or_else(|| "high".into()), }) } } diff --git a/crates/takana-bootstrap/src/lib.rs b/crates/takana-bootstrap/src/lib.rs index b13ddb88..d899bf45 100644 --- a/crates/takana-bootstrap/src/lib.rs +++ b/crates/takana-bootstrap/src/lib.rs @@ -1324,7 +1324,13 @@ fi # NOTA: el initramfs debe empaquetarse con `cpio --owner=root:root`. Si los ficheros del toolchain # quedan con el uid del que armó el builder (p. ej. 1000), ese uid no está mapeado en el userns de # bwrap (que mapea sólo 0→0) y el copy-up de overlay falla con EACCES al crear /opt/zig. Ver §8c. -export HAMMER_ROOTFS=/toolchain # el sandbox de build: el toolchain (variante a, desde Alpine) +# Se exportan LAS DOS formas a propósito (ADR 0016): el binario que corre acá adentro es +# `/usr/bin/hammer`, que puede ser el pinado del baseline y sólo conoce los nombres viejos. +# Un lector nuevo prefiere TAKANA_*; uno viejo usa HAMMER_*. Las dos se retiran en la etapa 6. +export TAKANA_ROOTFS=/toolchain # el sandbox de build: el toolchain (variante a, desde Alpine) +export TAKANA_WORK=/work +export TAKANA_CACHE= +export HAMMER_ROOTFS=/toolchain export HAMMER_WORK=/work export HAMMER_CACHE= echo ">> rebuild stage1 (toolchain in-rootfs, semilla $SEED_HASH)" diff --git a/crates/takana-build/src/config.rs b/crates/takana-build/src/config.rs index 918c8466..f681d79b 100644 --- a/crates/takana-build/src/config.rs +++ b/crates/takana-build/src/config.rs @@ -32,7 +32,7 @@ fn find_lab_upward(start: &Path) -> Option { /// Resuelve dónde vive el lab SIN atarlo a dónde vive el store. /// /// Orden, de más explícito a más adivinado: -/// 1. `HAMMER_LAB` — el operador manda. +/// 1. `TAKANA_LAB` — el operador manda. /// 2. Hermano del store (`/../.dev-fs`) **si existe**. Preserva exactamente el /// comportamiento histórico en la topología normal (lab y store en la raíz del proyecto). /// 3. Hacia arriba desde el CWD. Ésta es la que desacopla: cubre el caso en que el store fue @@ -40,7 +40,7 @@ fn find_lab_upward(start: &Path) -> Option { /// 4. `None` ⇒ el llamador cae al default histórico, para que los mensajes de error sigan /// apuntando a un lugar previsible en vez de a la nada. fn resolve_lab_dir(store_root: &Path) -> Option { - if let Some(v) = std::env::var_os("HAMMER_LAB") { + if let Some(v) = takana_core::env::var_os("TAKANA_LAB") { return Some(PathBuf::from(v)); } if let Some(parent) = store_root.parent() { @@ -92,27 +92,27 @@ impl BuildConfig { } } - /// Lee overrides desde entorno (`HAMMER_LAB`, `HAMMER_ROOTFS`, `HAMMER_ZIG`, `HAMMER_WORK`, - /// `HAMMER_CACHE`). `HAMMER_CACHE=""` (vacío) desactiva la caché. + /// Lee overrides desde entorno (`TAKANA_LAB`, `TAKANA_ROOTFS`, `TAKANA_ZIG`, `TAKANA_WORK`, + /// `TAKANA_CACHE`). `TAKANA_CACHE=""` (vacío) desactiva la caché. /// /// Es el constructor que HUELE EL ENTORNO (env + CWD); `defaults_for_store` se mantiene pura. - /// `HAMMER_LAB` mueve el lab entero de una; los `HAMMER_ROOTFS`/`HAMMER_ZIG`/`HAMMER_CACHE` + /// `TAKANA_LAB` mueve el lab entero de una; los `TAKANA_ROOTFS`/`TAKANA_ZIG`/`TAKANA_CACHE` /// siguen pisando pieza por pieza y ganan sobre él. pub fn from_env_or_defaults(store_root: &Path) -> Self { let mut cfg = match resolve_lab_dir(store_root) { Some(lab) => Self::defaults_for_store_with_lab(store_root, &lab), None => Self::defaults_for_store(store_root), }; - if let Ok(v) = std::env::var("HAMMER_ROOTFS") { + if let Some(v) = takana_core::env::var("TAKANA_ROOTFS") { cfg.rootfs = PathBuf::from(v); } - if let Ok(v) = std::env::var("HAMMER_ZIG") { + if let Some(v) = takana_core::env::var("TAKANA_ZIG") { cfg.zig_dir = PathBuf::from(v); } - if let Ok(v) = std::env::var("HAMMER_WORK") { + if let Some(v) = takana_core::env::var("TAKANA_WORK") { cfg.work_root = PathBuf::from(v); } - if let Ok(v) = std::env::var("HAMMER_CACHE") { + if let Some(v) = takana_core::env::var("TAKANA_CACHE") { cfg.cache_root = if v.is_empty() { None } else { Some(PathBuf::from(v)) }; } cfg diff --git a/crates/takana-build/src/fetch.rs b/crates/takana-build/src/fetch.rs index 167dada0..884a5466 100644 --- a/crates/takana-build/src/fetch.rs +++ b/crates/takana-build/src/fetch.rs @@ -387,7 +387,7 @@ fn salida_git(args: &[&str], cwd: &Path) -> takana_core::Result { /// /// # Por qué una lista y no una URL (ADR 0014) /// -/// El ADR 0013 dejó `HAMMER_MIRROR` con un solo valor y con eso el mecanismo que existe para no +/// El ADR 0013 dejó `TAKANA_MIRROR` con un solo valor y con eso el mecanismo que existe para no /// depender de 79 servidores ajenos pasaba a depender de **uno nuestro**: el mismo fallo, con /// nuestro nombre encima. La identidad del objeto es su `sha256`/`commit`, así que un origen de más /// no añade confianza que verificar — sólo un sitio más donde mirar. Añadirlos es gratis y no @@ -402,9 +402,9 @@ fn salida_git(args: &[&str], cwd: &Path) -> takana_core::Result { /// se reproduce y se depura — pero objetos distintos se reparten entre todos, así que una tanda del /// corpus **ejercita la lista entera**. Tras el elegido se recorren los demás como respaldo. fn bases_de_mirror(var: &str, clave: &str) -> Vec { - match std::env::var(var) { - Ok(raw) => rotar_bases(&raw, clave), - Err(_) => Vec::new(), + match takana_core::env::var(var) { + Some(raw) => rotar_bases(&raw, clave), + None => Vec::new(), } } @@ -466,10 +466,10 @@ fn rotar_bases(raw: &str, clave: &str) -> Vec { /// La verificación sigue siendo criptográfica: git comprueba cada objeto contra su SHA al /// desempaquetar, y el commit de la receta es la identidad. Un bundle alterado no pasa. fn hidratar_desde_bundle(commit: &str, destino: &Path) -> bool { - // `HAMMER_MIRROR_GIT` es una LISTA (ADR 0014): se prueban todos los orígenes antes de rendirse + // `TAKANA_MIRROR_GIT` es una LISTA (ADR 0014): se prueban todos los orígenes antes de rendirse // y caer a upstream. Un bundle que no está en uno puede estar en otro, y la verificación la // hace git contra el SHA venga de donde venga. - bases_de_mirror("HAMMER_MIRROR_GIT", commit) + bases_de_mirror("TAKANA_MIRROR_GIT", commit) .iter() .any(|base| hidratar_desde_bundle_en(base, commit, destino)) } @@ -623,13 +623,13 @@ fn fetch_tarball( /// Un mirror silencioso **con** vigía separado detecta el bit-rot; uno silencioso **sin** vigía lo /// entierra, que es como el grafo de wlr pasó 17 días anunciando un 121/121 que ya era falso. /// -/// `HAMMER_MIRROR` es una **lista** de prefijos de URL separada por comas, de cualquier esquema que +/// `TAKANA_MIRROR` es una **lista** de prefijos de URL separada por comas, de cualquier esquema que /// curl entienda (`file://`, `https://`, `sftp://`…); el objeto se busca por contenido en /// `{base}/{sha256}.tar` en cada uno, en el orden que dicta [`bases_de_mirror`]. -/// `HAMMER_MIRROR_KEY`, si está, se pasa como `--key` (Storage Box por sftp). Sin `HAMMER_MIRROR` +/// `TAKANA_MIRROR_KEY`, si está, se pasa como `--key` (Storage Box por sftp). Sin `TAKANA_MIRROR` /// el comportamiento es el de siempre: derecho a upstream. fn fetch_con_mirror(url: &str, sha256: &str, dst: &Path) -> takana_core::Result<()> { - for base in bases_de_mirror("HAMMER_MIRROR", sha256) { + for base in bases_de_mirror("TAKANA_MIRROR", sha256) { let espejo = format!("{base}/{sha256}.tar"); // Un fallo acá NO es un error: es el caso normal la primera vez que se ve una fuente, y // también el caso normal cuando un origen de la lista todavía no tiene ese objeto. Se @@ -649,7 +649,7 @@ fn descargar(url: &str, dst: &Path) -> takana_core::Result<()> { let mut cmd = Command::new("curl"); cmd.args(["-fL", "--retry", "3", "--connect-timeout", "30"]); // Clave para el mirror por sftp (Storage Box). Inocua para http/file. - if let Ok(key) = std::env::var("HAMMER_MIRROR_KEY") { + if let Some(key) = takana_core::env::var("TAKANA_MIRROR_KEY") { if !key.is_empty() { cmd.arg("--key").arg(&key); } diff --git a/crates/takana-build/src/hydrate.rs b/crates/takana-build/src/hydrate.rs index 21785b4a..c3fb7ea0 100644 --- a/crates/takana-build/src/hydrate.rs +++ b/crates/takana-build/src/hydrate.rs @@ -453,10 +453,10 @@ mod tests { } /// Camino feliz real: requiere patchelf + un ELF de verdad. Gated como el resto de tests - /// dependientes del host (`HAMMER_HOST_ELF_TESTS=1`). + /// dependientes del host (`TAKANA_HOST_ELF_TESTS=1`). #[test] fn hydrate_dynamic_patchea_elf_real() { - if std::env::var("HAMMER_HOST_ELF_TESTS").is_err() { + if takana_core::env::var("TAKANA_HOST_ELF_TESTS").is_none() { return; } let host_bin = std::path::Path::new("/bin/sh"); diff --git a/crates/takana-build/src/lib.rs b/crates/takana-build/src/lib.rs index dad124d6..a2d8d05a 100644 --- a/crates/takana-build/src/lib.rs +++ b/crates/takana-build/src/lib.rs @@ -197,7 +197,7 @@ pub fn build( // `docs/state/lab-toolchain.lock` ni de una ruta derivada del store. Derivarla del padre del // store ya mordió una vez (ver `BuildConfig::defaults_for_store_with_lab`): al anclar el store // de un worker a un volumen, el lab se buscaba donde no estaba. `cfg.rootfs` respeta - // `HAMMER_LAB`/`HAMMER_ROOTFS` y es la única fuente que no puede desincronizarse del build. + // `TAKANA_LAB`/`TAKANA_ROOTFS` y es la única fuente que no puede desincronizarse del build. let lab = takana_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; let h = artifact_hash(recipe, store, &lab)?; if store.has(&h, &recipe.name) { diff --git a/crates/takana-build/tests/end_to_end_grep.rs b/crates/takana-build/tests/end_to_end_grep.rs index 1983f654..50088718 100644 --- a/crates/takana-build/tests/end_to_end_grep.rs +++ b/crates/takana-build/tests/end_to_end_grep.rs @@ -3,7 +3,7 @@ //! //! Doblemente gateado para no penalizar `cargo test` por defecto: //! - Requiere `.dev-fs/` bootstrapeado (rootfs Alpine + zig + cache). -//! - Requiere `HAMMER_NETWORK_TESTS=1` (descarga ~3 MB del tarball de GNU). +//! - Requiere `TAKANA_NETWORK_TESTS=1` (descarga ~3 MB del tarball de GNU). //! //! Comparte la dev cache (`.dev-fs/cache`) para que la segunda corrida en una máquina dada //! reuse los objetos de musl y termine en segundos. @@ -44,9 +44,9 @@ fn skip_with_reason(reason: &str) -> bool { } fn should_skip(cfg: &BuildConfig) -> bool { - if std::env::var("HAMMER_NETWORK_TESTS").ok().as_deref() != Some("1") { + if takana_core::env::var("TAKANA_NETWORK_TESTS").as_deref() != Some("1") { return skip_with_reason( - "HAMMER_NETWORK_TESTS != 1 (este test descarga ~3 MB de ftp.gnu.org y compila ~30s).", + "TAKANA_NETWORK_TESTS != 1 (este test descarga ~3 MB de ftp.gnu.org y compila ~30s).", ); } if !cfg.rootfs.join("bin/busybox").is_file() { diff --git a/crates/takana-cli/src/kernel_cmd.rs b/crates/takana-cli/src/kernel_cmd.rs index 6226d961..81890c34 100644 --- a/crates/takana-cli/src/kernel_cmd.rs +++ b/crates/takana-cli/src/kernel_cmd.rs @@ -13,11 +13,11 @@ use takana_core::kernel::KernelConfig; use serde::Serialize; /// Dónde busca el árbol de Kconfig si no se pasa `--kconfig`. -const KCONFIG_ENV: &str = "HAMMER_KCONFIG_ROOT"; +const KCONFIG_ENV: &str = "TAKANA_KCONFIG_ROOT"; /// Ídem para el catálogo de bundles. -const CATALOG_ENV: &str = "HAMMER_KERNEL_BUNDLES"; +const CATALOG_ENV: &str = "TAKANA_KERNEL_BUNDLES"; /// Ídem para el contrato de capacidades (SDD 25 §4). -const CONTRACT_ENV: &str = "HAMMER_KERNEL_CONTRACT"; +const CONTRACT_ENV: &str = "TAKANA_KERNEL_CONTRACT"; /// Sitios donde buscarlo sin que nadie diga nada: el del repo y el del sistema instalado. const CATALOG_DEFAULTS: &[&str] = &[ "docs/state/kernel-bundles.toml", @@ -316,7 +316,7 @@ fn kconfig_root(flag: Option) -> Result { if let Some(p) = flag { return Ok(p); } - match std::env::var_os(KCONFIG_ENV) { + match takana_core::env::var_os(KCONFIG_ENV) { Some(v) => Ok(PathBuf::from(v)), None => anyhow::bail!( "falta el árbol de fuentes del kernel: pasá --kconfig o exportá {KCONFIG_ENV}" @@ -329,7 +329,7 @@ fn catalog_path(flag: Option) -> Result { if let Some(p) = flag { return Ok(p); } - if let Some(v) = std::env::var_os(CATALOG_ENV) { + if let Some(v) = takana_core::env::var_os(CATALOG_ENV) { return Ok(PathBuf::from(v)); } for c in CATALOG_DEFAULTS { @@ -348,7 +348,7 @@ fn contract_path(flag: Option) -> Result { if let Some(p) = flag { return Ok(p); } - if let Some(v) = std::env::var_os(CONTRACT_ENV) { + if let Some(v) = takana_core::env::var_os(CONTRACT_ENV) { return Ok(PathBuf::from(v)); } for c in CONTRACT_DEFAULTS { diff --git a/crates/takana-cli/src/main.rs b/crates/takana-cli/src/main.rs index 866c2a6a..9e831729 100644 --- a/crates/takana-cli/src/main.rs +++ b/crates/takana-cli/src/main.rs @@ -358,7 +358,7 @@ enum Cmd { catalog: Option, /// Activa el traductor LLM real (Claude API). Requiere `ANTHROPIC_API_KEY` en el env /// y un binario compilado con `--features llm-claude`. Modelo por defecto: - /// `claude-opus-4-8` (sobreescribible con `HAMMER_LLM_MODEL`). + /// `claude-opus-4-8` (sobreescribible con `TAKANA_LLM_MODEL`). #[arg(long)] llm: bool, /// Re-rootea las mutaciones bajo este prefix en vez de abrir overlay. Útil para diff --git a/crates/takana-cli/src/qorpa.rs b/crates/takana-cli/src/qorpa.rs index 114fe734..4d9bbc22 100644 --- a/crates/takana-cli/src/qorpa.rs +++ b/crates/takana-cli/src/qorpa.rs @@ -25,8 +25,8 @@ use serde::{Deserialize, Serialize}; /// Raíz del espacio de nombres de qorpa. Deliberadamente **fuera** del store. pub const DEFAULT_ROOT: &str = "/var/lib/hammer/qorpa"; -/// Para correr sin root (tests, laptop). Mismo patrón que `HAMMER_KCONFIG_ROOT`. -pub const ROOT_ENV: &str = "HAMMER_QORPA_ROOT"; +/// Para correr sin root (tests, laptop). Mismo patrón que `TAKANA_KCONFIG_ROOT`. +pub const ROOT_ENV: &str = "TAKANA_QORPA_ROOT"; /// El manifiesto de la imagen. No confundir con `instancia.toml`, que describe una INSTANCIA. const IMAGE_MANIFEST: &str = "image.toml"; /// El árbol desempacado dentro del directorio de la imagen. @@ -56,7 +56,7 @@ pub enum QorpaCmd { /// Dónde está el rootfs DENTRO del archivo, si la detección automática no acierta. #[arg(long)] subdir: Option, - /// Raíz de qorpa (default: `$HAMMER_QORPA_ROOT` o `/var/lib/hammer/qorpa`). + /// Raíz de qorpa (default: `$TAKANA_QORPA_ROOT` o `/var/lib/hammer/qorpa`). #[arg(long)] root: Option, }, @@ -226,7 +226,7 @@ pub fn run(cmd: QorpaCmd, store: &Path) -> Result<()> { } fn resolve_root(flag: Option) -> PathBuf { - flag.or_else(|| std::env::var_os(ROOT_ENV).map(PathBuf::from)) + flag.or_else(|| takana_core::env::var_os(ROOT_ENV).map(PathBuf::from)) .unwrap_or_else(|| PathBuf::from(DEFAULT_ROOT)) } diff --git a/crates/takana-cli/tests/swm_roundtrip.rs b/crates/takana-cli/tests/swm_roundtrip.rs index 50435858..2d7be243 100644 --- a/crates/takana-cli/tests/swm_roundtrip.rs +++ b/crates/takana-cli/tests/swm_roundtrip.rs @@ -3,7 +3,7 @@ //! coinciden con lo esperado. //! //! NO ejercitamos `source_patch` porque arrastra todo el lab (red + sandbox); para esos -//! casos existen los tests gated en `HAMMER_NETWORK_TESTS`. Aquí cubrimos los caminos puros +//! casos existen los tests gated en `TAKANA_NETWORK_TESTS`. Aquí cubrimos los caminos puros //! de hammer-core: `verify_schema`, `verify_base`, `apply_config_edit`, `apply_file_drop`. use std::collections::BTreeMap; diff --git a/crates/takana-core/src/env.rs b/crates/takana-core/src/env.rs new file mode 100644 index 00000000..7036b1a8 --- /dev/null +++ b/crates/takana-core/src/env.rs @@ -0,0 +1,72 @@ +//! Lectura de variables de entorno del proyecto durante el renombre `hammer` → `takana`. +//! +//! # Por qué existe esto en vez de un `sed` +//! +//! Las variables de entorno del proyecto **no son superficie interna**: son contrato de usuario, +//! del mismo tipo que un verbo de CLI. Hay knobs del instalador entre ellas (`HAMMER_TZ`, +//! `HAMMER_KEYMAP`, `HAMMER_HOSTNAME`), el entorno del worker las trae puestas desde perfiles de +//! shell y units de systemd que **viven fuera del repo**, y `mirror-env.sh` exporta las del espejo. +//! Un renombre duro no falla ruidosamente: la variable simplemente no aparece, se toma el valor por +//! defecto y el build se comporta distinto sin que nada lo diga. +//! +//! Por eso valen las dos formas: **`TAKANA_X` gana; si no está, se cae a `HAMMER_X`** (ADR 0016). +//! La caída se retira en la etapa 6 del renombre, cuando no queden entornos con la forma vieja. + +/// Lee una variable aceptando el nombre nuevo y, si falta, el viejo. +/// +/// Se le pasa el nombre **canónico** (`TAKANA_…`) para que un `grep` del nombre nuevo encuentre +/// todas las lecturas; el nombre viejo se deriva cambiando el prefijo. +pub fn var(nombre: &str) -> Option { + con_caida(nombre, |n| std::env::var(n).ok()) +} + +/// Igual que [`var`], para valores que no tienen por qué ser UTF-8 (rutas). +pub fn var_os(nombre: &str) -> Option { + con_caida(nombre, |n: &str| std::env::var_os(n)) +} + +fn con_caida(nombre: &str, leer: impl Fn(&str) -> Option) -> Option { + if let Some(v) = leer(nombre) { + return Some(v); + } + let viejo = format!("HAMMER_{}", nombre.strip_prefix("TAKANA_")?); + leer(&viejo) +} + +#[cfg(test)] +mod tests { + // Cada test usa un nombre propio: el entorno del proceso es estado COMPARTIDO entre tests que + // corren en hilos, y reusar el mismo nombre los hace pisarse de forma intermitente. + #[test] + fn prefiere_el_nombre_nuevo_sobre_el_viejo() { + std::env::set_var("TAKANA_PRUEBA_A", "nuevo"); + std::env::set_var("HAMMER_PRUEBA_A", "viejo"); + assert_eq!(super::var("TAKANA_PRUEBA_A").as_deref(), Some("nuevo")); + } + + #[test] + fn cae_al_viejo_cuando_el_nuevo_no_esta() { + std::env::set_var("HAMMER_PRUEBA_B", "viejo"); + assert_eq!(super::var("TAKANA_PRUEBA_B").as_deref(), Some("viejo")); + } + + #[test] + fn sin_ninguna_de_las_dos_no_hay_valor() { + assert_eq!(super::var("TAKANA_PRUEBA_C_QUE_NO_EXISTE"), None); + } + + #[test] + fn un_nombre_sin_prefijo_no_inventa_una_caida() { + std::env::set_var("HAMMER_PRUEBA_D", "viejo"); + assert_eq!(super::var("PRUEBA_D"), None); + } + + #[test] + fn var_os_tambien_cae() { + std::env::set_var("HAMMER_PRUEBA_E", "viejo"); + assert_eq!( + super::var_os("TAKANA_PRUEBA_E").as_deref(), + Some(std::ffi::OsStr::new("viejo")) + ); + } +} diff --git a/crates/takana-core/src/lab.rs b/crates/takana-core/src/lab.rs index 4e3a7df3..1c8ade70 100644 --- a/crates/takana-core/src/lab.rs +++ b/crates/takana-core/src/lab.rs @@ -118,7 +118,7 @@ impl LabFingerprint { crate::Error::Other(anyhow::anyhow!( "no pude leer el apk db del lab en {}: {e}. \ El toolchain entra en el ArtifactHash, así que sin rootfs no se puede calcular \ - un hash comparable (corré scripts/bootstrap-devfs.sh, o apuntá HAMMER_ROOTFS)", + un hash comparable (corré scripts/bootstrap-devfs.sh, o apuntá TAKANA_ROOTFS)", db.display() )) })?; diff --git a/crates/takana-core/src/lib.rs b/crates/takana-core/src/lib.rs index e9b64c4c..5c02f2d4 100644 --- a/crates/takana-core/src/lib.rs +++ b/crates/takana-core/src/lib.rs @@ -8,6 +8,7 @@ pub mod apply; pub mod caps; pub mod compat; pub mod differs; +pub mod env; pub mod hash; pub mod installed; pub mod kernel; diff --git a/crates/takana-core/src/query.rs b/crates/takana-core/src/query.rs index 91aaaadb..17ea5a7d 100644 --- a/crates/takana-core/src/query.rs +++ b/crates/takana-core/src/query.rs @@ -693,10 +693,10 @@ mod tests { } /// Sanity con un binario real del host: `/bin/sh` casi seguro existe y es ELF. - /// Gated por `HAMMER_HOST_ELF_TESTS=1` para no acoplar el suite a Linux/Alpine. + /// Gated por `TAKANA_HOST_ELF_TESTS=1` para no acoplar el suite a Linux/Alpine. #[test] fn parse_elf_real_host_binary() { - if std::env::var("HAMMER_HOST_ELF_TESTS").is_err() { + if crate::env::var("TAKANA_HOST_ELF_TESTS").is_none() { return; } let candidates = ["/bin/sh", "/usr/bin/sh", "/bin/ls", "/usr/bin/ls"]; @@ -715,10 +715,10 @@ mod tests { } /// Exports sobre una librería compartida real del host (una `.so` con `.dynsym`). Gated - /// igual que arriba: pide `HAMMER_HOST_ELF_TESTS=1`. Verifica que extraemos ≥1 símbolo. + /// igual que arriba: pide `TAKANA_HOST_ELF_TESTS=1`. Verifica que extraemos ≥1 símbolo. #[test] fn parse_exports_real_host_lib() { - if std::env::var("HAMMER_HOST_ELF_TESTS").is_err() { + if crate::env::var("TAKANA_HOST_ELF_TESTS").is_none() { return; } let candidates = [ diff --git a/crates/takana-overlay/tests/overlayfs_e2e.rs b/crates/takana-overlay/tests/overlayfs_e2e.rs index 06305b46..13b2459d 100644 --- a/crates/takana-overlay/tests/overlayfs_e2e.rs +++ b/crates/takana-overlay/tests/overlayfs_e2e.rs @@ -7,7 +7,7 @@ //! en distros con AppArmor; algunos kernels también requieren la opción `userxattr` en el //! mount). Por eso este test está doblemente gateado: //! - Requiere `bwrap` y overlayfs en el kernel. -//! - Requiere `HAMMER_OVERLAY_TESTS=1` — el dev confirma que su entorno admite el +//! - Requiere `TAKANA_OVERLAY_TESTS=1` — el dev confirma que su entorno admite el //! mount unprivilegiado, o corre el test bajo `sudo`. //! //! Sin esos requisitos el test salta limpio; los aspectos puros (layout, slug, parsing del @@ -36,13 +36,13 @@ fn overlayfs_supported() -> bool { /// reenviando los args originales. Si ya estamos dentro del sandbox (env marker set), /// no re-anidamos. fn run_inside_userns_or_skip(phase: &str, scratch: &Path) -> bool { - if std::env::var("HAMMER_OVERLAY_IN_SANDBOX").is_ok() { + if takana_core::env::var("TAKANA_OVERLAY_IN_SANDBOX").is_some() { // Ya estamos dentro — el caller ejecuta la lógica real. return false; } - if std::env::var("HAMMER_OVERLAY_TESTS").ok().as_deref() != Some("1") { + if takana_core::env::var("TAKANA_OVERLAY_TESTS").as_deref() != Some("1") { eprintln!( - "SKIP: HAMMER_OVERLAY_TESTS != 1 (overlayfs en user-ns suele estar denegado por \ + "SKIP: TAKANA_OVERLAY_TESTS != 1 (overlayfs en user-ns suele estar denegado por \ el kernel; setea la var cuando tu host lo permita o corre con sudo)." ); return true; @@ -72,7 +72,7 @@ fn run_inside_userns_or_skip(phase: &str, scratch: &Path) -> bool { .arg(scratch) .arg(scratch) .arg("--setenv") - .arg("HAMMER_OVERLAY_IN_SANDBOX") + .arg("TAKANA_OVERLAY_IN_SANDBOX") .arg("1") .arg("--setenv") .arg("OVERLAY_TEST_SCRATCH") @@ -154,7 +154,7 @@ fn body_try_commit_discard() { #[test] fn overlay_try_commit_discard_inside_userns() { - if std::env::var("HAMMER_OVERLAY_IN_SANDBOX").is_ok() { + if takana_core::env::var("TAKANA_OVERLAY_IN_SANDBOX").is_some() { body_try_commit_discard(); return; } @@ -220,7 +220,7 @@ fn body_nested_stack() { #[test] fn overlay_nested_stack_inside_userns() { - if std::env::var("HAMMER_OVERLAY_IN_SANDBOX").is_ok() { + if takana_core::env::var("TAKANA_OVERLAY_IN_SANDBOX").is_some() { body_nested_stack(); return; } diff --git a/crates/takana-recover/src/main.rs b/crates/takana-recover/src/main.rs index 19826bf0..3874e77c 100644 --- a/crates/takana-recover/src/main.rs +++ b/crates/takana-recover/src/main.rs @@ -14,8 +14,8 @@ //! generaciones tipo NixOS que seleccionar, sino una reparación determinista del estado a medias. //! //! Paths del producto (overridables por entorno para tests): -//! `HAMMER_RECOVER_ROOT=/` `HAMMER_RECOVER_STORE=/store` -//! `HAMMER_RECOVER_STATE=/var/lib/hammer/upgrades` `HAMMER_RECOVER_JOURNAL=/var/lib/hammer/journal` +//! `TAKANA_RECOVER_ROOT=/` `TAKANA_RECOVER_STORE=/store` +//! `TAKANA_RECOVER_STATE=/var/lib/hammer/upgrades` `TAKANA_RECOVER_JOURNAL=/var/lib/hammer/journal` //! Flag: `--rollback` fuerza deshacer en vez de completar. //! //! NUNCA sale con código ≠0 por un fallo de recuperación: es un hook de arranque, no debe abortar el @@ -23,16 +23,26 @@ use std::path::PathBuf; +/// Lee la variable aceptando el nombre nuevo y, si falta, el viejo (ADR 0016). +/// +/// La caída va inline y no por `takana_core::env`: este es un mini-binario que se copia a +/// `/usr/sbin` de los sistemas instalados, y no vale la pena arrastrarle una dep entera por +/// dos líneas. Se retira junto con el resto de las caídas en la etapa 6. fn env_path(key: &str, default: &str) -> PathBuf { - std::env::var(key).map(PathBuf::from).unwrap_or_else(|_| PathBuf::from(default)) + let viejo = key.strip_prefix("TAKANA_").map(|s| format!("HAMMER_{s}")); + std::env::var(key) + .ok() + .or_else(|| viejo.and_then(|v| std::env::var(v).ok())) + .map(PathBuf::from) + .unwrap_or_else(|| PathBuf::from(default)) } fn main() { let force_rollback = std::env::args().skip(1).any(|a| a == "--rollback"); - let root = env_path("HAMMER_RECOVER_ROOT", "/"); - let store = env_path("HAMMER_RECOVER_STORE", "/store"); - let state = env_path("HAMMER_RECOVER_STATE", "/var/lib/hammer/upgrades"); - let journal_dir = env_path("HAMMER_RECOVER_JOURNAL", "/var/lib/hammer/journal"); + let root = env_path("TAKANA_RECOVER_ROOT", "/"); + let store = env_path("TAKANA_RECOVER_STORE", "/store"); + let state = env_path("TAKANA_RECOVER_STATE", "/var/lib/hammer/upgrades"); + let journal_dir = env_path("TAKANA_RECOVER_JOURNAL", "/var/lib/hammer/journal"); match takana_upgrade::pending(&state) { Ok(None) => { diff --git a/scripts/alpine-import.sh b/scripts/alpine-import.sh index 156b9076..87c6f467 100755 --- a/scripts/alpine-import.sh +++ b/scripts/alpine-import.sh @@ -12,7 +12,7 @@ PKG="${1:?uso: alpine-import.sh [main|community]}" REPO="${2:-main}" BRANCH="${ALPINE_BRANCH:-master}" OUTDIR="${OUTDIR:-.}" -HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" +HAMMER="${TAKANA:-${HAMMER:-cargo run -q -p takana-cli --}}" BASE="https://gitlab.alpinelinux.org/alpine/aports/-/raw/${BRANCH}/${REPO}/${PKG}" apk=$(curl -fsSL "${BASE}/APKBUILD") || { echo "no encontré ${REPO}/${PKG} en aports@${BRANCH}" >&2; exit 1; } diff --git a/scripts/build-farm.sh b/scripts/build-farm.sh index 05dfac88..17a7ca55 100755 --- a/scripts/build-farm.sh +++ b/scripts/build-farm.sh @@ -23,7 +23,7 @@ STORE="${STORE:-./store}" REPO="${REPO:-$ROOT/dist/repo}" KEY="${KEY:-$ROOT/dist/keys/release.ed25519}" DISTRO="${DISTRO:-dev}" -HAMMER="${HAMMER:-$ROOT/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$ROOT/target/release/takana}}" PROMOTE="${PROMOTE:-1}" JOBS="${JOBS:-$(( $(nproc) - 2 ))}"; [ "$JOBS" -ge 1 ] || JOBS=1 diff --git a/scripts/cosmic/hydrate-cosmic.sh b/scripts/cosmic/hydrate-cosmic.sh index 6b6d1905..497cbb9e 100755 --- a/scripts/cosmic/hydrate-cosmic.sh +++ b/scripts/cosmic/hydrate-cosmic.sh @@ -21,7 +21,7 @@ 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/takana}"; KEEP="${KEEP:-0}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}"; KEEP="${KEEP:-0}" if [ $# -gt 0 ]; then TARGETS=("$@") diff --git a/scripts/farm/build-timed.sh b/scripts/farm/build-timed.sh index 6e25d6ac..5290dc0f 100755 --- a/scripts/farm/build-timed.sh +++ b/scripts/farm/build-timed.sh @@ -19,7 +19,7 @@ # # Sale con el MISMO código que `hammer build` (transparente para el llamador). set -u -HAMMER="${HAMMER:-./target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}" STORE="${STORE:-./store}" UMBRAL="${UMBRAL_TIEMPO:-3}" f="${1:?uso: build-timed.sh }" diff --git a/scripts/farm/campana-deuda.sh b/scripts/farm/campana-deuda.sh index e94f2446..f5ac82a7 100755 --- a/scripts/farm/campana-deuda.sh +++ b/scripts/farm/campana-deuda.sh @@ -25,12 +25,12 @@ # /opt/hammer/scripts/farm/campana-deuda.sh ' # ssh root@ 'journalctl -u campana-deuda -f' set -u -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" # Ruta absoluta a MÍ MISMO antes del `cd`: acá el `cd` va a HAMMER_DIR, que ni siquiera tiene por # qué contener a este script, así que un `$0` relativo se pierde seguro. YO="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")" cd "$HAMMER_DIR" -HAMMER="${HAMMER:-$HAMMER_DIR/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$HAMMER_DIR/target/release/takana}}" STORE="${STORE:-$HAMMER_DIR/store}" LOG="${LOG:-/var/log/campana-deuda.log}" diff --git a/scripts/farm/cosecha-cron.sh b/scripts/farm/cosecha-cron.sh index 942ca0d4..bd3969d0 100755 --- a/scripts/farm/cosecha-cron.sh +++ b/scripts/farm/cosecha-cron.sh @@ -78,7 +78,7 @@ if [ -s "$FLEET_FIJA" ]; then { grep -vE '^[[:space:]]*(#|$)' "$FLEET_FIJA" || true; cat "$FLEET" 2>/dev/null || true; } \ | awk 'NF && !visto[$1]++' > "$FLEET.seed" && mv "$FLEET.seed" "$FLEET" fi -HAMMER="${HAMMER:-$ROOT/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$ROOT/target/release/takana}}" # Workers efímeros reciclan IPs ⇒ no fijar known_hosts (hub-and-spoke, worker sin secretos). SSH="ssh -i $SSH_KEY -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o BatchMode=yes -o LogLevel=ERROR -o ConnectTimeout=15" diff --git a/scripts/farm/farm-worker-loop.sh b/scripts/farm/farm-worker-loop.sh index 79a88dd5..3ea57c34 100755 --- a/scripts/farm/farm-worker-loop.sh +++ b/scripts/farm/farm-worker-loop.sh @@ -9,7 +9,7 @@ # # Lo lanza systemd (hammer-farm.service). Manual: JOBS=2 ./scripts/farm/farm-worker-loop.sh set -uo pipefail -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" cd "$HAMMER_DIR" . "$HOME/.cargo/env" 2>/dev/null || true # JOBS=1 MIENTRAS EL ADR 0012 ESTÉ SIN DECIDIR (2026-07-22). `build-farm.sh` usa `xargs -P$JOBS`, y diff --git a/scripts/farm/harkaq-campana-vol.sh b/scripts/farm/harkaq-campana-vol.sh index 4c48666f..8a08633a 100755 --- a/scripts/farm/harkaq-campana-vol.sh +++ b/scripts/farm/harkaq-campana-vol.sh @@ -10,7 +10,7 @@ set -u MI_NOMBRE="${1:?uso: harkaq-campana-vol.sh }" -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" cd "$HAMMER_DIR" LISTA="${LISTA:-work/harkaq-cola.txt}" VOL_OUT="/mnt/cosecha" diff --git a/scripts/farm/harkaq-campana.sh b/scripts/farm/harkaq-campana.sh index 3364b6c4..82c8ed34 100755 --- a/scripts/farm/harkaq-campana.sh +++ b/scripts/farm/harkaq-campana.sh @@ -18,7 +18,7 @@ # script existe para no tener. set -u -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" cd "$HAMMER_DIR" LISTA="${1:-work/harkaq-cola.txt}" OUT="work/harkaq-campana" diff --git a/scripts/farm/harvest-go.sh b/scripts/farm/harvest-go.sh index c8f6ad4f..e20df91a 100755 --- a/scripts/farm/harvest-go.sh +++ b/scripts/farm/harvest-go.sh @@ -29,7 +29,7 @@ STORE="${STORE:-$ROOT/store}" REPO="${REPO:-$ROOT/dist/repo}" KEY="${KEY:-$ROOT/dist/keys/release.ed25519}" DISTRO="${DISTRO:-dev}" -HAMMER="${HAMMER:-$ROOT/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$ROOT/target/release/takana}}" SEAL_TIMEOUT="${SEAL_TIMEOUT:-60}" QUEUE="recipes/incoming-go" REVIEW="tandas/needs-review-weekend" diff --git a/scripts/farm/migra-zig.sh b/scripts/farm/migra-zig.sh index 2afba48b..3f9c911e 100755 --- a/scripts/farm/migra-zig.sh +++ b/scripts/farm/migra-zig.sh @@ -13,7 +13,7 @@ # Salidas: work/migra-zig/{migrable,matraca}.txt set -u cd "$(dirname "$0")/../.." -HAMMER="${HAMMER:-./target/debug/hammer}" +HAMMER="${TAKANA:-${HAMMER:-./target/debug/hammer}}" OUT="work/migra-zig"; mkdir -p "$OUT" # ACUMULA entre corridas (no trunca): probar las 47 no cabe en un timeout, así que se corre por # lotes y cada lote SUMA. `reg` evita duplicar una receta ya clasificada en una corrida previa. diff --git a/scripts/farm/saldar-deuda-static.sh b/scripts/farm/saldar-deuda-static.sh index 027c1de0..6c2aca33 100755 --- a/scripts/farm/saldar-deuda-static.sh +++ b/scripts/farm/saldar-deuda-static.sh @@ -27,7 +27,7 @@ set -u ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" -HAMMER="${HAMMER:-$ROOT/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$ROOT/target/release/takana}}" STORE="${STORE:-$ROOT/store}" DRY="${DRY:-0}" # El stack GUI no construye en el laptop (zig-skew rompe cairo). Default: saltarlo salvo que se pida. diff --git a/scripts/farm/tandas.sh b/scripts/farm/tandas.sh index e0fa0c68..4af7093a 100755 --- a/scripts/farm/tandas.sh +++ b/scripts/farm/tandas.sh @@ -21,7 +21,7 @@ # /opt/hammer/scripts/farm/tandas.sh "gui:pixman,cairo" …' # ssh root@ 'tail -f /var/log/tandas.log' set -u -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" cd "$HAMMER_DIR" LOG="${LOG:-/var/log/tandas.log}" ESPERA="${ESPERA:-30}" diff --git a/scripts/farm/vps-setup.sh b/scripts/farm/vps-setup.sh index f2dbd6a4..89f75df5 100755 --- a/scripts/farm/vps-setup.sh +++ b/scripts/farm/vps-setup.sh @@ -41,7 +41,7 @@ # evita el zig-skew: el worker usa EXACTAMENTE las versiones del hub. set -euo pipefail -HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" +HAMMER_DIR="${TAKANA_DIR:-${HAMMER_DIR:-/opt/hammer}}" cd "$HAMMER_DIR" # ── detección de familia ──────────────────────────────────────────────────────────────────── diff --git a/scripts/fuentes/mirror-env.sh b/scripts/fuentes/mirror-env.sh index 99aef38c..a6e2ea45 100644 --- a/scripts/fuentes/mirror-env.sh +++ b/scripts/fuentes/mirror-env.sh @@ -20,8 +20,14 @@ # La ruta lleva `/~/` a propósito. curl interpreta lo que sigue al host en una URL `sftp://` como # ruta ABSOLUTA del servidor, así que `…:23/hammer/fuentes` busca en la raíz y devuelve # «(78) Could not open remote file for reading» aunque el fichero exista. `/~/` lo ancla al home. -export HAMMER_MIRROR="${HAMMER_MIRROR:-sftp://u647150@u647150.your-storagebox.de:23/~/hammer/fuentes}" +# ADR 0016: se exportan las DOS formas. Se acepta la vieja como entrada (hay entornos que la +# traen puesta desde perfiles y units fuera del repo) y se deja también puesta, porque un +# binario viejo —worker sin recompilar, imagen pinada— sólo conoce ésa. +export TAKANA_MIRROR="${TAKANA_MIRROR:-${HAMMER_MIRROR:-sftp://u647150@u647150.your-storagebox.de:23/~/hammer/fuentes}}" +export HAMMER_MIRROR="$TAKANA_MIRROR" # Fuentes git: bundles shallow por commit. Variable APARTE de HAMMER_MIRROR porque son dos espacios # de nombres distintos —`{sha256}.tar` vs `{commit}.bundle`— y se pueblan y se pierden por separado. -export HAMMER_MIRROR_GIT="${HAMMER_MIRROR_GIT:-sftp://u647150@u647150.your-storagebox.de:23/~/hammer/fuentes-git}" -export HAMMER_MIRROR_KEY="${HAMMER_MIRROR_KEY:-$HOME/.ssh/github5}" +export TAKANA_MIRROR_GIT="${TAKANA_MIRROR_GIT:-${HAMMER_MIRROR_GIT:-sftp://u647150@u647150.your-storagebox.de:23/~/hammer/fuentes-git}}" +export HAMMER_MIRROR_GIT="$TAKANA_MIRROR_GIT" +export TAKANA_MIRROR_KEY="${TAKANA_MIRROR_KEY:-${HAMMER_MIRROR_KEY:-$HOME/.ssh/github5}}" +export HAMMER_MIRROR_KEY="$TAKANA_MIRROR_KEY" diff --git a/scripts/gnome/hydrate-gnome.sh b/scripts/gnome/hydrate-gnome.sh index c2178a78..57c7e017 100755 --- a/scripts/gnome/hydrate-gnome.sh +++ b/scripts/gnome/hydrate-gnome.sh @@ -18,7 +18,7 @@ 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/takana}"; KEEP="${KEEP:-0}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}"; 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 diff --git a/scripts/hammer-live-install.sh b/scripts/hammer-live-install.sh index 491f9426..da7c1950 100755 --- a/scripts/hammer-live-install.sh +++ b/scripts/hammer-live-install.sh @@ -25,7 +25,8 @@ # particiona+instala. Es la cara humana del instalador (el /init del ISO installer lo lanza). # DESATENDIDO (con device): hammer-install /dev/vdb [ROOT_MB] [STORE_MB] # Autoinstalador (lo usa iso-install-test.sh con AUTO_INSTALL). La config sale de env: -# HAMMER_HOSTNAME / HAMMER_ROOT_PW / HAMMER_ROOT_AUTHKEYS / HAMMER_TZ / HAMMER_KEYMAP. +# TAKANA_HOSTNAME / TAKANA_ROOT_PW / TAKANA_ROOT_AUTHKEYS / TAKANA_TZ / TAKANA_KEYMAP. +# Los nombres viejos HAMMER_* se siguen aceptando (ADR 0016); gana el nuevo si están los dos. set -eu DEV="${1:-}" @@ -132,11 +133,11 @@ apply_post_install_config() { } # ---- recolección de config: interactiva (TUI) o desde env (desatendido) ---- -CFG_HOSTNAME="${HAMMER_HOSTNAME:-hammer}" -CFG_ROOT_AUTHKEYS="${HAMMER_ROOT_AUTHKEYS:-}" -CFG_ROOT_HASH="${HAMMER_ROOT_HASH:-}" -CFG_TZ="${HAMMER_TZ:-}" -CFG_KEYMAP="${HAMMER_KEYMAP:-us}" +CFG_HOSTNAME="${TAKANA_HOSTNAME:-${HAMMER_HOSTNAME:-takana}}" +CFG_ROOT_AUTHKEYS="${TAKANA_ROOT_AUTHKEYS:-${HAMMER_ROOT_AUTHKEYS:-}}" +CFG_ROOT_HASH="${TAKANA_ROOT_HASH:-${HAMMER_ROOT_HASH:-}}" +CFG_TZ="${TAKANA_TZ:-${HAMMER_TZ:-}}" +CFG_KEYMAP="${TAKANA_KEYMAP:-${HAMMER_KEYMAP:-us}}" interactive_setup() { echo @@ -250,8 +251,8 @@ fi ROOT_MB="${ROOT_MB:-1500}" STORE_MB="${STORE_MB:-400}" # En modo desatendido con contraseña por env, derivar el hash acá (interactivo ya lo hizo). -if [ -z "$CFG_ROOT_HASH" ] && [ -n "${HAMMER_ROOT_PW:-}" ] && have_cryptpw; then - CFG_ROOT_HASH=$(printf '%s' "$HAMMER_ROOT_PW" | bb cryptpw -m sha512 2>/dev/null || true) +if [ -z "$CFG_ROOT_HASH" ] && [ -n "${TAKANA_ROOT_PW:-${HAMMER_ROOT_PW:-}}" ] && have_cryptpw; then + CFG_ROOT_HASH=$(printf '%s' "${TAKANA_ROOT_PW:-$HAMMER_ROOT_PW}" | bb cryptpw -m sha512 2>/dev/null || true) fi # --- gancho de prueba: valida TUI + config sin tocar disco (HAMMER_INSTALL_DRYRUN=1) --- diff --git a/scripts/harkaq/harkaq-trace-build.sh b/scripts/harkaq/harkaq-trace-build.sh index 03089f03..c2854206 100644 --- a/scripts/harkaq/harkaq-trace-build.sh +++ b/scripts/harkaq/harkaq-trace-build.sh @@ -23,7 +23,7 @@ set -euo pipefail RECETA="${1:?uso: harkaq-trace-build.sh [store] [outdir]}" STORE="${2:-./store}" OUT="${3:-/tmp/harkaq-trace-pilot}" -HAMMER="${HAMMER:-./target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}" TRACE="${TRACE:-/tmp/harkaq-trace}" NORM="${NORM:-scripts/harkaq/harkaq-trace-norm.py}" mkdir -p "$OUT"; rm -f "$OUT"/traza-fase-*.txt "$OUT"/canonica.txt "$OUT"/resumen.txt diff --git a/scripts/install-image-efi.sh b/scripts/install-image-efi.sh index c2bbbf32..13fe7a0c 100755 --- a/scripts/install-image-efi.sh +++ b/scripts/install-image-efi.sh @@ -144,7 +144,7 @@ mkdir -p "$ROOT_TREE/store" "$ROOT_TREE/var/lib/hammer" # CLI `hammer` (static musl) para el menú de arranque por grafo (ADR 0010): el hook de init lo invoca # como `hammer boot menu`. El producto trae arje-zero/hammerd pero NO el CLI ⇒ lo inyectamos acá si # está compilado (igual patrón que hammer-recover). Opcional: sin él, el wrapper saltea el menú. -HAMMER_MUSL="${HAMMER_MUSL:-$ROOT/target/x86_64-unknown-linux-musl/release/hammer}" +HAMMER_MUSL="${TAKANA_MUSL:-${HAMMER_MUSL:-$ROOT/target/x86_64-unknown-linux-musl/release/hammer}}" if [ -x "$HAMMER_MUSL" ]; then cp "$HAMMER_MUSL" "$ROOT_TREE/usr/bin/hammer"; chmod 0755 "$ROOT_TREE/usr/bin/hammer" echo " + CLI hammer (static musl) para el menú de arranque por grafo" diff --git a/scripts/kde/complete-closure.sh b/scripts/kde/complete-closure.sh index 706b4fae..d9813b53 100644 --- a/scripts/kde/complete-closure.sh +++ b/scripts/kde/complete-closure.sh @@ -9,7 +9,7 @@ set -uo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" STORE="${STORE:-./store}"; RFS="${RFS:-work/kde-store-rootfs}"; LINK="${LINK:-static}" -HAMMER="${HAMMER:-./target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}" CUTOFF="${CUTOFF:-$(date -d 'today 00:00' +%s 2>/dev/null || echo 9999999999)}" # sonames provistos por la base (no soberanos aún / runtime del sistema): no hidratar. BASE_SONAMES="libc.so libc.musl-x86_64.so.1 ld-musl-x86_64.so.1 libc.so.6 ld-linux-x86-64.so.2 libm.so.6 libdl.so.2 libpthread.so.0 librt.so.1 libresolv.so.2" diff --git a/scripts/kde/hydrate-fhs.sh b/scripts/kde/hydrate-fhs.sh index eff790ef..b6d222d3 100644 --- a/scripts/kde/hydrate-fhs.sh +++ b/scripts/kde/hydrate-fhs.sh @@ -16,7 +16,7 @@ REPO="${REPO:-work/repo-kde}"; TRUST="${TRUST:-dist/keys}"; STORE="${STORE:-./st RFS="${RFS:-work/kde-rootfs}" # TARGETS = uno o varios paquetes tope (unión de cierres). TARGET (singular) sigue soportado. TARGETS="${TARGETS:-${TARGET:-qt6-qtdeclarative}}" -HAMMER="${HAMMER:-./target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}" DB="$RFS/var/lib/hammer/installed.json" # cierre transitivo de TODOS los targets, leído del índice (deps + aliases ya resuelven). Excluimos diff --git a/scripts/kde/hydrate-from-store.sh b/scripts/kde/hydrate-from-store.sh index 422fef5d..a1de1e72 100644 --- a/scripts/kde/hydrate-from-store.sh +++ b/scripts/kde/hydrate-from-store.sh @@ -15,7 +15,7 @@ set -uo pipefail ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT" REPO="${REPO:-work/repo-kde}"; STORE="${STORE:-./store}"; LINK="${LINK:-static}" -RFS="${RFS:-work/kde-store-rootfs}"; HAMMER="${HAMMER:-./target/release/takana}" +RFS="${RFS:-work/kde-store-rootfs}"; HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}" TARGETS="${TARGETS:-${TARGET:-qt6-qtdeclarative}}" # CUTOFF: por defecto medianoche de hoy (excluye rebuilds de la sesión). Pasá 9999999999 para no filtrar. CUTOFF="${CUTOFF:-$(date -d 'today 00:00' +%s 2>/dev/null || echo 9999999999)}" diff --git a/scripts/mirada-usb.sh b/scripts/mirada-usb.sh index 1451e347..73ddce5e 100644 --- a/scripts/mirada-usb.sh +++ b/scripts/mirada-usb.sh @@ -23,7 +23,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" STORE="${STORE:-./store}" DEVFS="${DEVFS:-.dev-fs/alpine}" RFS="${RFS:-work/mirada-rootfs}" -HAMMER="${HAMMER:-target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-target/release/takana}}" PACKAGE="${PACKAGE:-1}" [ -d "$DEVFS" ] || { echo "no existe $DEVFS (corré scripts/bootstrap-devfs.sh)" >&2; exit 1; } diff --git a/scripts/nix-import.sh b/scripts/nix-import.sh index 74f0969c..678e4f08 100755 --- a/scripts/nix-import.sh +++ b/scripts/nix-import.sh @@ -9,7 +9,7 @@ set -eu ATTR="${1:?uso: nix-import.sh (ej: hello, jq, ripgrep)}" NIXPKGS="${NIXPKGS:-nixpkgs}" -HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" +HAMMER="${TAKANA:-${HAMMER:-cargo run -q -p takana-cli --}}" # NIX_STORE: si el /nix/store del sistema no es escribible (install single-user incompleta), apuntá # a un store local, p.ej. NIX_STORE="local?root=$HOME/.nixstore". STORE_OPT="" diff --git a/scripts/pin-recipes.sh b/scripts/pin-recipes.sh index 645bfae3..717aa080 100755 --- a/scripts/pin-recipes.sh +++ b/scripts/pin-recipes.sh @@ -6,7 +6,7 @@ # # Ej: scripts/pin-recipes.sh recipes/*.toml | find recipes -name '*.toml' | xargs scripts/pin-recipes.sh set -eu -HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" +HAMMER="${TAKANA:-${HAMMER:-cargo run -q -p takana-cli --}}" [ "$#" -gt 0 ] || { echo "uso: pin-recipes.sh " >&2; exit 1; } pinned=0; skipped=0; failed="" diff --git a/scripts/qorpa/evidence-probe.sh b/scripts/qorpa/evidence-probe.sh index e05a04cc..1193d209 100755 --- a/scripts/qorpa/evidence-probe.sh +++ b/scripts/qorpa/evidence-probe.sh @@ -18,7 +18,7 @@ set -eu QORPA_ROOT="${HAMMER_QORPA_ROOT:-/var/lib/hammer/qorpa}" -HAMMER="${HAMMER_BIN:-./target/release/takana}" +HAMMER="${TAKANA_BIN:-${HAMMER_BIN:-./target/release/takana}}" ID="${1:-arch-probe}" export HAMMER_QORPA_ROOT="$QORPA_ROOT" diff --git a/scripts/qorpa/pressure-vessel-probe.sh b/scripts/qorpa/pressure-vessel-probe.sh index cffa6243..906d6631 100755 --- a/scripts/qorpa/pressure-vessel-probe.sh +++ b/scripts/qorpa/pressure-vessel-probe.sh @@ -21,7 +21,7 @@ set -eu QORPA_ROOT="${HAMMER_QORPA_ROOT:-/var/lib/hammer/qorpa}" -HAMMER="${HAMMER_BIN:-./target/release/takana}" +HAMMER="${TAKANA_BIN:-${HAMMER_BIN:-./target/release/takana}}" ID="${1:-sniper-probe}" UBUNTU_URL="https://cdimage.ubuntu.com/ubuntu-base/releases/24.04/release/ubuntu-base-24.04.3-base-amd64.tar.gz" diff --git a/scripts/reconstruir-corpus.sh b/scripts/reconstruir-corpus.sh index d62109c2..6a279e4c 100755 --- a/scripts/reconstruir-corpus.sh +++ b/scripts/reconstruir-corpus.sh @@ -31,7 +31,7 @@ set -uo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" -HAMMER="${HAMMER:-$ROOT/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$ROOT/target/release/takana}}" STORE="${STORE:-./store}" LOCK="$ROOT/work/.farm-build.lock" LOG="${LOG:-$ROOT/work/reconstruccion.log}" diff --git a/scripts/selfhost-verify.sh b/scripts/selfhost-verify.sh index 65be2570..61af6072 100755 --- a/scripts/selfhost-verify.sh +++ b/scripts/selfhost-verify.sh @@ -241,7 +241,7 @@ fi # kernel): un /init PID1 que copia el rootfs a un tmpfs y hace `switch_root`, dejando `/` como un # mount tmpfs real (pivotable). El kernel debe arrancar con rdinit=/init (ver APPEND abajo). Off por # defecto ⇒ el camino del kernel host queda intacto (rdinit=/sbin/init directo). -if [[ "${HAMMER_KERNEL:-0}" == 1 ]]; then +if [[ "${TAKANA_KERNEL:-${HAMMER_KERNEL:-0}}" == 1 ]]; then say "HAMMER_KERNEL: inyectar /init wrapper (copy-to-tmpfs + switch_root, escapa del rootfs)" cat > work/builder-rootfs/init <<'INIT' #!/bin/sh diff --git a/scripts/static-audit.sh b/scripts/static-audit.sh index 5808182a..6bcd7676 100755 --- a/scripts/static-audit.sh +++ b/scripts/static-audit.sh @@ -37,7 +37,7 @@ set -eu HUB="$(cd "$(dirname "$0")/.." && pwd)" cd "$HUB" STORE="${STORE:-$PWD/store}" -HAMMER="${HAMMER:-$HUB/target/release/takana}" +HAMMER="${TAKANA:-${HAMMER:-$HUB/target/release/takana}}" if [ $# -gt 0 ]; then recetas="" diff --git a/scripts/store-gc.sh b/scripts/store-gc.sh index eadc39e4..5663fd23 100755 --- a/scripts/store-gc.sh +++ b/scripts/store-gc.sh @@ -38,7 +38,7 @@ # Env: STORE (def ./store) HAMMER (def ./target/release/takana) JOBS (def 8) set -uo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" -STORE="${STORE:-./store}"; HAMMER="${HAMMER:-./target/release/takana}"; JOBS="${JOBS:-8}" +STORE="${STORE:-./store}"; HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}"; JOBS="${JOBS:-8}" APLICAR=0; HUERFANOS=0 for a in "$@"; do case "$a" in diff --git a/scripts/verificar-repro.sh b/scripts/verificar-repro.sh index 098dfeee..d89f6587 100755 --- a/scripts/verificar-repro.sh +++ b/scripts/verificar-repro.sh @@ -48,7 +48,7 @@ # Env: STORE (def ./store) N (def 30, tamaño de la muestra) set -uo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$ROOT" -STORE="${STORE:-./store}"; HAMMER="${HAMMER:-./target/release/takana}"; N="${N:-30}" +STORE="${STORE:-./store}"; HAMMER="${TAKANA:-${HAMMER:-./target/release/takana}}"; N="${N:-30}" # ── EL LOCK LO TOMA EL SCRIPT, Y ANTES DE TOCAR NADA ─────────────────────────────────────────── # Este script llama a `hammer build`, y la regla 1 del repo es que todo build va envuelto en el