1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
//! It loads environment variables from a `.env` file, if available, and mashes
//! those with the environment variables provided by the operating system.
mod dotenv;
mod error;
#[cfg(test)]
mod tests;
use std::env;
use std::ffi::OsStr;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::sync::Once;
pub use crate::dotenv::Dotenv;
pub use crate::error::*;
static LOAD: Once = Once::new();
/// Load the `.env` file and fetch the environment variable key from the current process.
///
/// For more details, please visit [`load`] or [`std::env::var`].
///
/// # NOTE
///
/// - The `.env` file will be loaded once, so it's cheap to call [`var`] again and again.
/// - The error occurs in loading the `.env` file will be ignored.
///
/// # Examples
///
/// ```no_run
/// let var = dotenv::var("FOO").unwrap();
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String> {
LOAD.call_once(|| {
load().ok();
});
env::var(key).map_err(Error::from)
}
/// Load the `.env` file and return an iterator of (variable, value) pairs of strings,
/// for all the environment variables of the current process.
///
/// The returned iterator contains a snapshot of the process's environment variables at the
/// time of this invocation, modifications to environment variables afterwards will not be
/// reflected in the returned iterator.
///
/// For more details, please visit [`load`] or [`std::env::vars`].
///
/// # Examples
///
/// ```no_run
/// let vars: Vec<(String, String)> = dotenv::vars().collect();
/// ```
pub fn vars() -> env::Vars {
LOAD.call_once(|| {
load().ok();
});
env::vars()
}
/// Load file at the given `path` and then set environment variables.
///
/// # Examples
///
/// ```
/// use std::env;
///
/// let my_path = env::home_dir().map(|dir| dir.join(".env")).unwrap();
/// dotenv::load_path(my_path.as_path()).ok();
/// ```
pub fn load_path<P: AsRef<Path>>(path: P) -> Result<()> {
try_from_path(path).and_then(Dotenv::load)
}
/// Create a [`Dotenv`] instance from the given `path`.
///
/// # Examples
///
/// ```no_run
/// use std::env;
///
/// let my_path = env::home_dir().map(|dir| dir.join(".env")).unwrap();
/// for item in dotenv::try_from_path(my_path.as_path()).unwrap() {
/// let (key, val) = item.unwrap();
/// println!("{}={}", key, val);
/// }
/// ```
pub fn try_from_path<P: AsRef<Path>>(path: P) -> Result<Dotenv> {
Ok(Dotenv::new(File::open(path)?))
}
/// Load the given `filename` and then set environment variables.
///
/// It will search for the given `filename` in the current directory or its parents in sequence.
///
/// # Examples
///
/// ```
/// dotenv::load_filename(".env.local").ok();
/// ```
pub fn load_filename<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
search(filename.as_ref()).and_then(|path| load_path(&path).and(Ok(path)))
}
/// Create a [`Dotenv`] instance from the given `filename`
///
/// # Examples
///
/// ```no_run
/// let envs = dotenv::try_from_filename(".env.local").unwrap();
///
/// for (key, value) in envs.flatten() {
/// println!("{}={}", key, value);
/// }
/// ```
pub fn try_from_filename<P: AsRef<Path>>(filename: P) -> Result<Dotenv> {
search(filename.as_ref()).and_then(try_from_path)
}
/// Load `.env` file and then set environment variables.
///
/// It will search for `.env` file in the current directory or its parents in sequence.
///
/// # Examples
///
/// ```
/// dotenv::load().ok();
/// ```
pub fn load() -> Result<PathBuf> {
load_filename(".env")
}
/// Create a [`Dotenv`] instance from the `.env` file.
///
/// # Examples
///
/// ```no_run
/// for item in dotenv::try_init().unwrap() {
/// let (key, value) = item.unwrap();
/// println!("{}={}", key, value);
/// }
/// ```
pub fn try_init() -> Result<Dotenv> {
try_from_filename(".env")
}
/// Search for `filename` in the current directory or its parents in sequence.
fn search(filename: &Path) -> Result<PathBuf> {
let current_dir = env::current_dir()?;
fn path_not_found() -> Error {
std::io::Error::new(std::io::ErrorKind::NotFound, "path not found").into()
}
current_dir
.ancestors()
.map(|dir| dir.join(filename))
.find(|path| path.is_file())
.ok_or_else(path_not_found)
}