1use super::*;
2
3pub fn load_dotenv(
4 config: &Config,
5 settings: &Settings,
6 working_directory: &Path,
7) -> RunResult<'static, BTreeMap<String, String>> {
8 let dotenv_filename = config
9 .dotenv_filename
10 .as_ref()
11 .or(settings.dotenv_filename.as_ref());
12
13 let dotenv_path = config
14 .dotenv_path
15 .as_ref()
16 .or(settings.dotenv_path.as_ref());
17
18 if !settings.dotenv_load
19 && dotenv_filename.is_none()
20 && dotenv_path.is_none()
21 && !settings.dotenv_required
22 {
23 return Ok(BTreeMap::new());
24 }
25
26 if let Some(path) = dotenv_path {
27 let path = working_directory.join(path);
28 if path.is_file() {
29 return load_from_file(&path);
30 }
31 }
32
33 let filename = dotenv_filename.map_or(".env", |s| s.as_str());
34
35 for directory in working_directory.ancestors() {
36 let path = directory.join(filename);
37 if path.is_file() {
38 return load_from_file(&path);
39 }
40 }
41
42 if settings.dotenv_required {
43 Err(Error::DotenvRequired)
44 } else {
45 Ok(BTreeMap::new())
46 }
47}
48
49fn load_from_file(path: &Path) -> RunResult<'static, BTreeMap<String, String>> {
50 let iter = dotenvy::from_path_iter(path)?;
51 let mut dotenv = BTreeMap::new();
52 for result in iter {
53 let (key, value) = result?;
54 if env::var_os(&key).is_none() {
55 dotenv.insert(key, value);
56 }
57 }
58 Ok(dotenv)
59}