use super::*;
pub(crate) fn load_dotenv(
config: &Config,
settings: &Settings,
working_directory: &Path,
) -> RunResult<'static, BTreeMap<String, String>> {
let dotenv_filename = config
.dotenv_filename
.as_ref()
.or(settings.dotenv_filename.as_ref());
let dotenv_path = config
.dotenv_path
.as_ref()
.or(settings.dotenv_path.as_ref());
if !settings.dotenv_load
&& !settings.dotenv_override
&& !settings.dotenv_required
&& dotenv_filename.is_none()
&& dotenv_path.is_none()
{
return Ok(BTreeMap::new());
}
if let Some(path) = dotenv_path {
let path = working_directory.join(path);
if let Some(map) = load_from_file(&path, settings)? {
return Ok(map);
}
}
let filename = dotenv_filename.map_or(".env", |s| s.as_str());
for directory in working_directory.ancestors() {
let path = directory.join(filename);
if let Some(map) = load_from_file(&path, settings)? {
return Ok(map);
}
}
if settings.dotenv_required {
Err(Error::DotenvRequired)
} else {
Ok(BTreeMap::new())
}
}
fn load_from_file(
path: &Path,
settings: &Settings,
) -> RunResult<'static, Option<BTreeMap<String, String>>> {
if path.is_dir() {
return Ok(None);
}
let file = match File::open(path) {
Ok(file) => file,
Err(source) => {
if source.kind() == io::ErrorKind::NotFound {
return Ok(None);
}
return Err(Error::FilesystemIo {
path: path.into(),
source,
});
}
};
let mut dotenv = BTreeMap::new();
for result in dotenvy::from_read_iter(file) {
let (key, value) = result.map_err(|dotenv_error| Error::Dotenv {
dotenv_error,
path: path.into(),
})?;
if settings.dotenv_override || env::var_os(&key).is_none() {
dotenv.insert(key, value);
}
}
Ok(Some(dotenv))
}