gioser

tawasuyu/brahman

Rust 566TOML 214Markdown 67JSON 198093 Sutichaykuna

⎇ c22d2480b93b7802be8e8ea5a0075b8175c4fedc crates/shared/ente-incarnate/src/env.rs Rust · 95 siq'ikuna · 3.1 KB Ñawpa willay Pi imata llamkarqan ch'uya

shell c22d2480b · sergio ·

1//! Construcción del entorno del hijo. Sin globals — toma EnvSpec por valor.
2
3use brahman_card::Card;
4use std::path::PathBuf;
5
6/// Var env para el path del bus interno (cuando aplica). Mismo nombre que
7/// usa ente-bus para que clientes existentes (`BusClient::from_env`) sigan
8/// funcionando sin cambios.
9pub const ENV_BUS_SOCK: &str = "ENTE_BUS_SOCK";
10
11/// Var env para el ULID de la Card encarnada.
12pub const ENV_ENTE_ID: &str = "ENTE_ID";
13
14#[derive(Debug, Clone, Default)]
15pub struct EnvSpec {
16    /// Si `Some`, se inyecta como ENTE_BUS_SOCK.
17    pub bus_sock: Option<PathBuf>,
18    /// Si `Some`, se inyecta como NOTIFY_SOCKET (legacy sd_notify).
19    pub notify_socket: Option<PathBuf>,
20    /// Vars adicionales que el caller quiere forzar.
21    pub extra: Vec<(String, String)>,
22}
23
24/// Hereda env del padre, aplica el envp explícito de la Card, y al final
25/// inyecta las vars del fractal según `EnvSpec`.
26pub fn build_env(card: &Card, base_envp: &[(String, String)], spec: &EnvSpec) -> Vec<(String, String)> {
27    let mut env: Vec<(String, String)> = std::env::vars().collect();
28
29    for (k, v) in base_envp {
30        env.retain(|(ek, _)| ek != k);
31        env.push((k.clone(), v.clone()));
32    }
33
34    if let Some(p) = &spec.bus_sock {
35        env.retain(|(k, _)| k != ENV_BUS_SOCK);
36        env.push((ENV_BUS_SOCK.into(), p.to_string_lossy().into_owned()));
37    }
38
39    env.retain(|(k, _)| k != ENV_ENTE_ID);
40    env.push((ENV_ENTE_ID.into(), card.id.to_string()));
41
42    if let Some(p) = &spec.notify_socket {
43        env.retain(|(k, _)| k != "NOTIFY_SOCKET");
44        env.push(("NOTIFY_SOCKET".into(), p.to_string_lossy().into_owned()));
45    }
46
47    for (k, v) in &spec.extra {
48        env.retain(|(ek, _)| ek != k);
49        env.push((k.clone(), v.clone()));
50    }
51
52    env
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use brahman_card::Card;
59
60    #[test]
61    fn env_id_and_bus_injected() {
62        let card = Card::new("test");
63        let spec = EnvSpec {
64            bus_sock: Some(PathBuf::from("/tmp/bus.sock")),
65            notify_socket: None,
66            extra: vec![],
67        };
68        let env = build_env(&card, &[], &spec);
69        assert!(env.iter().any(|(k, v)| k == ENV_ENTE_ID && v == &card.id.to_string()));
70        assert!(env.iter().any(|(k, v)| k == ENV_BUS_SOCK && v == "/tmp/bus.sock"));
71    }
72
73    #[test]
74    fn extra_overrides_inherited() {
75        let card = Card::new("test");
76        let spec = EnvSpec {
77            bus_sock: None,
78            notify_socket: None,
79            extra: vec![("PATH".into(), "/sandbox/bin".into())],
80        };
81        let env = build_env(&card, &[], &spec);
82        let path_count = env.iter().filter(|(k, _)| k == "PATH").count();
83        assert_eq!(path_count, 1);
84        assert_eq!(env.iter().find(|(k, _)| k == "PATH").unwrap().1, "/sandbox/bin");
85    }
86
87    #[test]
88    fn notify_socket_only_when_set() {
89        let card = Card::new("test");
90        let spec = EnvSpec::default();
91        let env = build_env(&card, &[], &spec);
92        assert!(!env.iter().any(|(k, _)| k == "NOTIFY_SOCKET"
93            && std::env::var("NOTIFY_SOCKET").is_err()));
94    }
95}