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 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
//! [`dotenv`]: https://crates.io/crates/dotenv
//! A well-maintained fork of the [`dotenv`] crate
//!
//! This library loads environment variables from a *.env* file. This is convenient for dev environments.
mod errors;
mod find;
mod iter;
mod parse;
use std::env::{self, Vars};
use std::ffi::OsStr;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::sync::Once;
pub use crate::errors::*;
use crate::find::Finder;
use crate::iter::Iter;
static START: Once = Once::new();
/// Gets the value for an environment variable.
///
/// The value is `Ok(s)` if the environment variable is present and valid unicode.
///
/// Note: this function gets values from any visible environment variable key,
/// regardless of whether a *.env* file was loaded.
///
/// # Examples:
///
/// ```no_run
/// let value = dotenvy::var("HOME").unwrap();
/// println!("{value}"); // prints `/home/foo`
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String> {
START.call_once(|| {
dotenv().ok();
});
env::var(key).map_err(Error::EnvVar)
}
/// Returns an iterator of `(key, value)` pairs for all environment variables of the current process.
/// The returned iterator contains a snapshot of the process's environment variables at the time of invocation. Modifications to environment variables afterwards will not be reflected.
///
///
/// # Examples:
///
/// use std::io;
///
/// let result: Vec<(String, String)> = dotenvy::vars().collect();
/// ```
pub fn vars() -> Vars {
START.call_once(|| {
dotenv().ok();
});
env::vars()
}
/// Loads environment variables from the specified path.
///
/// # Examples
///
/// ```no_run
/// use dirs::home_dir;
///
/// let my_path = home_dir().map(|a| a.join("/absolute/path/.env")).unwrap();
/// dotenvy::from_path(my_path.as_path());
/// ```
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<()> {
let iter = Iter::new(File::open(path).map_err(Error::Io)?);
iter.load()
}
/// Returns an iterator over environment variables from the specified path.
///
/// # Examples
///
/// ```no_run
/// use dirs::home_dir;
///
/// let my_path = home_dir().map(|a| a.join("/absolute/path/.env")).unwrap();
///
/// for item in dotenvy::from_path_iter(my_path.as_path()).unwrap() {
/// let (key, val) = item.unwrap();
/// println!("{key}={val}");
/// }
/// ```
pub fn from_path_iter<P: AsRef<Path>>(path: P) -> Result<Iter<File>> {
Ok(Iter::new(File::open(path).map_err(Error::Io)?))
}
/// Loads environment variables from the specified file.
///
/// # Examples
/// ```no_run
/// dotenvy::from_filename("custom.env").unwrap();
/// ```
///
/// It is also possible to load from a typical *.env* file like so. However, using [dotenv] is preferred.
///
/// ```
/// dotenvy::from_filename(".env").unwrap();
/// ```
pub fn from_filename<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
let (path, iter) = Finder::new().filename(filename.as_ref()).find()?;
iter.load()?;
Ok(path)
}
/// Returns an iterator over environment variables from the specified file.
///
/// # Examples
/// ```no_run
/// for item in dotenvy::from_filename_iter("custom.env").unwrap() {
/// let (key, val) = item.unwrap();
/// println!("{key}={val}");
/// }
/// ```
pub fn from_filename_iter<P: AsRef<Path>>(filename: P) -> Result<Iter<File>> {
let (_, iter) = Finder::new().filename(filename.as_ref()).find()?;
Ok(iter)
}
/// Loads environment variables from [io::Read](std::io::Read).
///
/// This is useful for loading environment variables from from IPC or the network.
///
/// For regular files, use [from_path] or [from_filename].
///
/// # Examples
/// ```no_run
/// # #![cfg(unix)]
/// use std::io::Read;
/// use std::os::unix::net::UnixStream;
///
/// let mut stream = UnixStream::connect("/some/socket").unwrap();
/// dotenvy::from_read(stream).unwrap();
/// ```
pub fn from_read<R: io::Read>(reader: R) -> Result<()> {
let iter = Iter::new(reader);
iter.load()?;
Ok(())
}
/// Returns an iterator over environment variables from [io::Read](std::io::Read).
///
/// # Examples
///
/// ```no_run
/// # #![cfg(unix)]
/// use std::io::Read;
/// use std::os::unix::net::UnixStream;
///
/// let mut stream = UnixStream::connect("/some/socket").unwrap();
///
/// for item in dotenvy::from_read_iter(stream) {
/// let (key, val) = item.unwrap();
/// println!("{key}={val}");
/// }
/// ```
pub fn from_read_iter<R: io::Read>(reader: R) -> Iter<R> {
Iter::new(reader)
}
/// Loads the *.env* file from the current directory or parents. This is typically what you want.
///
/// An error will be returned if the file is not found.
/// # Examples
/// ```
/// dotenvy::dotenv().unwrap();
/// ```
pub fn dotenv() -> Result<PathBuf> {
let (path, iter) = Finder::new().find()?;
iter.load()?;
Ok(path)
}
/// Returns an iterator over environment variables.
///
/// # Examples
/// ```
/// for item in dotenvy::dotenv_iter().unwrap() {
/// let (key, val) = item.unwrap();
/// println!("{key}={val}");
/// }
/// ```
pub fn dotenv_iter() -> Result<iter::Iter<File>> {
let (_, iter) = Finder::new().find()?;
Ok(iter)
}