dotenv/lib.rs
1#![doc = include_str!("../README.md")]
2
3mod dotenv;
4mod errors;
5mod parse;
6
7pub use crate::dotenv::Dotenv;
8pub use crate::errors::Error;
9pub type Result<T> = std::result::Result<T, Error>;
10
11use std::env;
12use std::ffi;
13use std::fs;
14use std::io;
15use std::io::Read;
16use std::path::Path;
17use std::path::PathBuf;
18use std::sync::Once;
19
20static LOAD: Once = Once::new();
21
22/// Get the value for an environment variable.
23///
24/// Automatically loads `.env` on first call (if present and not yet loaded).
25/// Values are read from the **current process environment**, not directly from
26/// the `.env` file — so any value set by a previous caller or the shell is visible.
27///
28/// # Errors
29///
30/// Returns [`Error::Env`] if the variable contains non-unicode data.
31///
32/// # Examples
33///
34/// ```no_run
35/// let value = dotenv::var("HOME").unwrap();
36/// println!("{}", value);
37/// ```
38pub fn var<K: AsRef<ffi::OsStr>>(key: K) -> Result<String> {
39 LOAD.call_once(|| {
40 load().ok();
41 });
42
43 env::var(key).map_err(Error::from)
44}
45
46/// Return an iterator of `(key, value)` pairs for all environment variables
47/// of the current process.
48///
49/// Automatically loads `.env` on first call. The returned iterator is a
50/// snapshot of the process environment at the time of invocation —
51/// subsequent modifications are not reflected.
52///
53/// # Examples
54///
55/// ```no_run
56/// use std::io;
57///
58/// for (key, value) in dotenv::vars() {
59/// println!("{key}={value}");
60/// }
61/// ```
62pub fn vars() -> env::Vars {
63 LOAD.call_once(|| {
64 load().ok();
65 });
66
67 env::vars()
68}
69
70fn find<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
71 let filename = filename.as_ref();
72 env::current_dir()?
73 .ancestors()
74 .map(|dir| dir.join(filename))
75 .find(|path| path.is_file())
76 .ok_or_else(Error::not_found)
77}
78
79/// Load the `.env` file from the current directory or its parents.
80///
81/// Searches upward from the current working directory until `.env` is found.
82/// The first call loads variables; subsequent calls are no-ops through
83/// [`Dotenv::load`] (existing variables are preserved).
84///
85/// # Errors
86///
87/// Returns [`Error::Io`] if no `.env` file is found or it cannot be read.
88///
89/// # Examples
90///
91/// ```no_run
92/// dotenv::load().ok();
93/// ```
94pub fn load() -> Result<PathBuf> {
95 let path = find(".env")?;
96 from_path(&path).map(|vars| {
97 vars.load();
98 path
99 })
100}
101
102/// Create [`Dotenv`] from the specified file.
103///
104/// Searches upward from the current working directory for the given filename.
105///
106/// # Errors
107///
108/// Returns [`Error::Io`] if the file is not found or cannot be read.
109pub fn from_filename<P: AsRef<Path>>(filename: P) -> Result<Dotenv> {
110 let path = find(filename)?;
111 from_path(path)
112}
113
114/// Create [`Dotenv`] from the specified path.
115///
116/// # Errors
117///
118/// Returns [`Error::Io`] if the file cannot be read.
119pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Dotenv> {
120 let file = fs::File::open(path)?;
121 from_read(file)
122}
123
124/// Create [`Dotenv`] from any [`Read`] implementor.
125///
126/// This is useful for loading environment variables from in-memory buffers,
127/// IPC streams, or network connections.
128///
129/// # Errors
130///
131/// Returns [`Error::Io`] if reading from the source fails.
132///
133/// # Examples
134///
135/// ```
136/// use std::io::Cursor;
137///
138/// let input = Cursor::new(b"FOO=bar\nBAZ=qux\n");
139/// let dotenv = dotenv::from_read(input).unwrap();
140/// for (key, value) in dotenv.iter() {
141/// println!("{key}={value}");
142/// }
143/// ```
144pub fn from_read<R: Read>(read: R) -> Result<Dotenv> {
145 let mut buf = String::new();
146 let mut reader = io::BufReader::new(read);
147 reader.read_to_string(&mut buf)?;
148
149 Ok(Dotenv::new(buf))
150}