Skip to main content

lexe_common/
dotenv.rs

1use std::env;
2
3/// A version of [`dotenvy::dotenv`] which only loads whitelisted keys.
4///
5/// # Safety
6///
7/// This fn calls [`std::env::set_var`] under-the-hood, which is not
8/// threadsafe on some platforms (ex: glibc Linux). The caller must ensure that
9/// this fn is called very early in the program lifetime, before any threads are
10/// spawned.
11pub unsafe fn dotenv_filtered(
12    filter_keys: &[&str],
13) -> Result<(), dotenvy::Error> {
14    // `dotenv_iter` finds an .env file in the current directory (or parents),
15    // then returns an iterator over it without loading the variables within.
16    for try_kv in dotenvy::dotenv_iter()? {
17        let (key, value) = try_kv?;
18        if filter_keys.contains(&key.as_str()) {
19            // Like dotenvy::dotenv(), do not override existing keys.
20            if env::var(&key).is_err() {
21                // See SAFETY
22                unsafe {
23                    env::set_var(&key, value);
24                }
25            }
26        }
27    }
28
29    Ok(())
30}
31
32/// Fetches the given key from env or `.env`, but without loading any of the
33/// keys in `.env` into our env (including the requested key).
34/// In other words, it is a "pure" version of [`dotenvy::var`].
35pub fn var_pure(given_key: &str) -> Result<String, dotenvy::Error> {
36    // Early return if the key already existed in env.
37    if let Ok(value) = env::var(given_key) {
38        return Ok(value);
39    }
40
41    // Look for the key in .env. We do not set the key in env if it was found.
42    for try_kv in dotenvy::dotenv_iter()? {
43        let (key, value) = try_kv?;
44        if key == given_key {
45            return Ok(value);
46        }
47    }
48
49    Err(dotenvy::Error::EnvVar(env::VarError::NotPresent))
50}