tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

⎇ main crates/takana-core/src/env.rs Rust · 72 lines · 2.8 KB History Who touched what raw

takana etapa 5d: comentarios de crates, CLAUDE.md y el skill de granja b818f5249 · Sergio ·

1//! Lectura de variables de entorno del proyecto durante el renombre `takana` → `takana`.
2//!
3//! # Por qué existe esto en vez de un `sed`
4//!
5//! Las variables de entorno del proyecto **no son superficie interna**: son contrato de usuario,
6//! del mismo tipo que un verbo de CLI. Hay knobs del instalador entre ellas (`HAMMER_TZ`,
7//! `HAMMER_KEYMAP`, `HAMMER_HOSTNAME`), el entorno del worker las trae puestas desde perfiles de
8//! shell y units de systemd que **viven fuera del repo**, y `mirror-env.sh` exporta las del espejo.
9//! Un renombre duro no falla ruidosamente: la variable simplemente no aparece, se toma el valor por
10//! defecto y el build se comporta distinto sin que nada lo diga.
11//!
12//! Por eso valen las dos formas: **`TAKANA_X` gana; si no está, se cae a `HAMMER_X`** (ADR 0016).
13//! La caída se retira en la etapa 6 del renombre, cuando no queden entornos con la forma vieja.
14
15/// Lee una variable aceptando el nombre nuevo y, si falta, el viejo.
16///
17/// Se le pasa el nombre **canónico** (`TAKANA_…`) para que un `grep` del nombre nuevo encuentre
18/// todas las lecturas; el nombre viejo se deriva cambiando el prefijo.
19pub fn var(nombre: &str) -> Option<String> {
20    con_caida(nombre, |n| std::env::var(n).ok())
21}
22
23/// Igual que [`var`], para valores que no tienen por qué ser UTF-8 (rutas).
24pub fn var_os(nombre: &str) -> Option<std::ffi::OsString> {
25    con_caida(nombre, |n: &str| std::env::var_os(n))
26}
27
28fn con_caida<T>(nombre: &str, leer: impl Fn(&str) -> Option<T>) -> Option<T> {
29    if let Some(v) = leer(nombre) {
30        return Some(v);
31    }
32    let viejo = format!("HAMMER_{}", nombre.strip_prefix("TAKANA_")?);
33    leer(&viejo)
34}
35
36#[cfg(test)]
37mod tests {
38    // Cada test usa un nombre propio: el entorno del proceso es estado COMPARTIDO entre tests que
39    // corren en hilos, y reusar el mismo nombre los hace pisarse de forma intermitente.
40    #[test]
41    fn prefiere_el_nombre_nuevo_sobre_el_viejo() {
42        std::env::set_var("TAKANA_PRUEBA_A", "nuevo");
43        std::env::set_var("HAMMER_PRUEBA_A", "viejo");
44        assert_eq!(super::var("TAKANA_PRUEBA_A").as_deref(), Some("nuevo"));
45    }
46
47    #[test]
48    fn cae_al_viejo_cuando_el_nuevo_no_esta() {
49        std::env::set_var("HAMMER_PRUEBA_B", "viejo");
50        assert_eq!(super::var("TAKANA_PRUEBA_B").as_deref(), Some("viejo"));
51    }
52
53    #[test]
54    fn sin_ninguna_de_las_dos_no_hay_valor() {
55        assert_eq!(super::var("TAKANA_PRUEBA_C_QUE_NO_EXISTE"), None);
56    }
57
58    #[test]
59    fn un_nombre_sin_prefijo_no_inventa_una_caida() {
60        std::env::set_var("HAMMER_PRUEBA_D", "viejo");
61        assert_eq!(super::var("PRUEBA_D"), None);
62    }
63
64    #[test]
65    fn var_os_tambien_cae() {
66        std::env::set_var("HAMMER_PRUEBA_E", "viejo");
67        assert_eq!(
68            super::var_os("TAKANA_PRUEBA_E").as_deref(),
69            Some(std::ffi::OsStr::new("viejo"))
70        );
71    }
72}