config-rs
config-rs copied to clipboard
Support dotenv file format
Didn't think someone would actually want this when I thought through it more. The dotenv lib could be used alongside this one easy enough.
Cool it's up to you. I just wanted to make sure this is tracked somewhere because you listed it in the roadmap but there was no ticket.
I'm still planning to do this. There are many tools out there that use "generic" .conf files and this would satisfy that. I don't want to call the format Dotenv though. Perhaps Shell.
Sorry for not being clear. I should have included that bit in my response. I just meant a thing "for reading .env files" is a bit odd when I think about it more.
And I just found a good use case for supporting specifically the .env file. Diesel will only support loading the database URL from the environment until #[proc_macro] stabilizes. For now I can keep just the DATABASE_URL in .env and load it into my configuration stack via:
c.merge(config::File::new(".env", config::FileFormat::Shell)).unwrap()
Remember that we don't support the above format yet. If anyone wants to work on it, follow this spec: https://github.com/bkeepers/dotenv#usage and use nom. Probably should be its own crate and with coordination from @slapresta, perhaps it can replace the hand-rolled parser in rust-dotenv (lots of TODOs in the parser so I'd guess @slapresta would be open to it).
Hi!
Improvements to the parser (which is basically a regex plus quote handling logic) are definitely welcome. Reading from a specific file should be feasible with dotenv'sfrom_file; the problem is that dotenv automatically adds those to the environment. It should be feasible to split the part that adds this to the environment to a separate function, and use the ParsedLines by themselves to construct your config structures.
Didn't think someone would actually want this when I thought through it more. The dotenv lib could be used alongside this one easy enough.
Any update about this decision?
Even though config-rs refuse to load .env to system environment. At least we should support reading from .env file (Currently we support JSON, TOML, YAML, HJSON, INI). So that we don't need dontenv alongside config-rs.
I needed this for myself so i created a little adapter to loading dotenv files Might be useful for someone, so I'm dropping it here:
#[derive(Debug, Clone)]
struct DotEnv;
impl config::Source for DotEnv {
fn clone_into_box(&self) -> Box<dyn config::Source + Send + Sync> {
Box::new((*self).clone())
}
fn collect(&self) -> Result<HashMap<String, config::Value>, config::ConfigError> {
let mut m = HashMap::new();
let uri: String = "the dotenv".into();
#[allow(deprecated)]
for item in dotenv::dotenv_iter().unwrap() {
let (key, value) = item.unwrap();
m.insert(
key.to_string().replace("_", ".").to_lowercase(),
config::Value::new(Some(&uri), value),
);
}
Ok(m)
}
}
That you can then merge into your config:
s.merge(DotEnv)?;
It should probably follow the Environment options.
Can I also add that it would be nice to support dotenv format? If you don't have time, would you be willing to accept a PR for that?
I'd be more than happy to get a PR for that, yes!
Make sure to add extensive tests!
I have been tackling this problem for a few days now, and I think that in a sufficiently complex config file, it's impossible to automatically derive the position of the variable from the env variable.
I think it's best to allow the user to interpolate any arbitrary env_variable in the config (e.g a = "$var") and then replace these with an env var (either VAR or PREFIX_VAR).
In my project, I approached this in the following way:
- load
dotenvfrom the same directory where the config file is located. - build the config (default config --> overwrite with config vars from config file --> overwrite with config vars from cli)
- replace all fields of form
$varwith the env var:$VAR
What do y'all think?