manaconf/sources/
env_var_source.rs

1use std::env::{VarError, var};
2
3use crate::helpers::join;
4use crate::{Source, Key, Value};
5
6/// A config value source that fetches values from environment variables
7///
8/// The source can be supplied with a prefix for environment variables
9/// by using `with_prefix`.
10///
11/// Environment variable names, are thus then constructed as
12/// `PREFIX_COMPONENT_COMPONENT_COMPONENT`
13///
14/// If there is no prefix then it's just `COMPONENT_COMPONENT_COMPONENT`
15///
16/// i.e. If the source has a prefix of `MYCONFIG` and you requested a value
17/// with the key `database::connection_string`. The environment variable
18/// that is looked up would be `MYCONFIG_DATABASE_CONNECTION_STRING`
19///
20/// It is worth noting, however, that this scheme may cause conflicts as
21/// the key `database::connection_string` and `database::connection::string`
22/// would result in the same environment variable `DATABASE_CONNECTION_STRING`.
23pub struct EnvVarSource {
24    prefix: Option<String>,
25}
26
27impl EnvVarSource {
28    /// Creates an environment variable source
29    pub fn new() -> Self {
30        Self { prefix: None }
31    }
32
33    /// Creates an environment source with a given prefix to the environment
34    /// variables name.
35    pub fn with_prefix<T: Into<String>>(prefix: T) -> Self {
36        Self::_with_prefix(prefix.into())
37    }
38
39    fn _with_prefix(mut prefix: String) -> Self {
40        if !prefix.ends_with('_') {
41            prefix.push('_');
42        }
43
44        Self {
45            prefix: Some(prefix),
46        }
47    }
48}
49
50impl Source for EnvVarSource {
51    type Error = VarError;
52
53    fn get_value(&self, key: &Key) -> Result<Option<Value>, Self::Error> {
54        let key_with_env_seperator = join(key.components(), "_");
55
56        let mut env_key = self.prefix.clone().unwrap_or_default();
57        env_key.push_str(&key_with_env_seperator);
58
59        match var(env_key.to_uppercase()) {
60            Ok(v) => Ok(Some(Value::String(v))),
61            Err(std::env::VarError::NotPresent) => Ok(None),
62            Err(e) => Err(e),
63        }
64    }
65}