config-rs icon indicating copy to clipboard operation
config-rs copied to clipboard

Support dotenv file format

Open dtolnay opened this issue 8 years ago • 10 comments

dtolnay avatar Feb 11 '17 09:02 dtolnay

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.

mehcode avatar Feb 11 '17 17:02 mehcode

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.

dtolnay avatar Feb 12 '17 18:02 dtolnay

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.

mehcode avatar Feb 12 '17 18:02 mehcode

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).

mehcode avatar Feb 13 '17 01:02 mehcode

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.

ghost avatar Feb 13 '17 11:02 ghost

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.

azzamsa avatar Oct 04 '20 00:10 azzamsa

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.

porfirioribeiro avatar Feb 28 '21 11:02 porfirioribeiro

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?

yerke avatar Jun 08 '21 07:06 yerke

I'd be more than happy to get a PR for that, yes!

Make sure to add extensive tests!

matthiasbeyer avatar Jun 08 '21 07:06 matthiasbeyer

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 dotenv from 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 $var with the env var: $VAR

What do y'all think?

odyslam avatar Jun 07 '23 16:06 odyslam