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…
takana etapa 5d: comentarios de crates, CLAUDE.md y el skill de granja
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}