dotenvy/lib.rs
1//! [`dotenv`]: https://crates.io/crates/dotenv
2//! A well-maintained fork of the [`dotenv`] crate
3//!
4//! This library loads environment variables from a *.env* file. This is convenient for dev environments.
5
6mod errors;
7mod find;
8mod iter;
9mod parse;
10
11use std::env::{self, Vars};
12use std::ffi::OsStr;
13use std::fs::File;
14use std::io;
15use std::path::{Path, PathBuf};
16use std::sync::Once;
17
18pub use crate::errors::*;
19use crate::find::Finder;
20pub use crate::iter::Iter;
21
22static START: Once = Once::new();
23
24/// Gets the value for an environment variable.
25///
26/// The value is `Ok(s)` if the environment variable is present and valid unicode.
27///
28/// Note: this function gets values from any visible environment variable key,
29/// regardless of whether a *.env* file was loaded.
30///
31/// # Examples:
32///
33/// ```no_run
34/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
35/// let value = dotenvy::var("HOME")?;
36/// println!("{}", value); // prints `/home/foo`
37/// # Ok(())
38/// # }
39/// ```
40pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String> {
41 START.call_once(|| {
42 dotenv().ok();
43 });
44 env::var(key).map_err(Error::EnvVar)
45}
46
47/// Returns an iterator of `(key, value)` pairs for all environment variables of the current process.
48/// 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.
49///
50/// # Examples:
51///
52/// ```no_run
53/// use std::io;
54///
55/// let result: Vec<(String, String)> = dotenvy::vars().collect();
56/// ```
57pub fn vars() -> Vars {
58 START.call_once(|| {
59 dotenv().ok();
60 });
61 env::vars()
62}
63
64/// Loads environment variables from the specified path.
65///
66/// If variables with the same names already exist in the environment, then their values will be
67/// preserved.
68///
69/// Where multiple declarations for the same environment variable exist in your *.env*
70/// file, the *first one* is applied.
71///
72/// If you wish to ensure all variables are loaded from your *.env* file, ignoring variables
73/// already existing in the environment, then use [`from_path_override`] instead.
74///
75/// # Examples
76///
77/// ```no_run
78/// use std::path::Path;
79///
80/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
81/// dotenvy::from_path(Path::new("path/to/.env"))?;
82/// # Ok(())
83/// # }
84/// ```
85pub fn from_path<P: AsRef<Path>>(path: P) -> Result<()> {
86 let iter = Iter::new(File::open(path).map_err(Error::Io)?);
87 iter.load()
88}
89
90/// Loads environment variables from the specified path,
91/// overriding existing environment variables.
92///
93/// Where multiple declarations for the same environment variable exist in your *.env* file, the
94/// *last one* is applied.
95///
96/// If you want the existing environment to take precedence,
97/// or if you want to be able to override environment variables on the command line,
98/// then use [`from_path`] instead.
99///
100/// # Examples
101///
102/// ```no_run
103/// use std::path::Path;
104///
105/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
106/// dotenvy::from_path_override(Path::new("path/to/.env"))?;
107/// # Ok(())
108/// # }
109/// ```
110pub fn from_path_override<P: AsRef<Path>>(path: P) -> Result<()> {
111 let iter = Iter::new(File::open(path).map_err(Error::Io)?);
112 iter.load_override()
113}
114
115/// Returns an iterator over environment variables from the specified path.
116///
117/// # Examples
118///
119/// ```no_run
120/// use std::path::Path;
121///
122/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
123/// for item in dotenvy::from_path_iter(Path::new("path/to/.env"))? {
124/// let (key, val) = item?;
125/// println!("{}={}", key, val);
126/// }
127/// # Ok(())
128/// # }
129/// ```
130pub fn from_path_iter<P: AsRef<Path>>(path: P) -> Result<Iter<File>> {
131 Ok(Iter::new(File::open(path).map_err(Error::Io)?))
132}
133
134/// Loads environment variables from the specified file.
135///
136/// If variables with the same names already exist in the environment, then their values will be
137/// preserved.
138///
139/// Where multiple declarations for the same environment variable exist in your *.env*
140/// file, the *first one* is applied.
141///
142/// If you wish to ensure all variables are loaded from your *.env* file, ignoring variables
143/// already existing in the environment, then use [`from_filename_override`] instead.
144///
145/// # Examples
146/// ```no_run
147/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
148/// dotenvy::from_filename("custom.env")?;
149/// # Ok(())
150/// # }
151/// ```
152///
153/// It is also possible to load from a typical *.env* file like so. However, using [`dotenv`] is preferred.
154///
155/// ```
156/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
157/// dotenvy::from_filename(".env")?;
158/// # Ok(())
159/// # }
160/// ```
161pub fn from_filename<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
162 let (path, iter) = Finder::new().filename(filename.as_ref()).find()?;
163 iter.load()?;
164 Ok(path)
165}
166
167/// Loads environment variables from the specified file,
168/// overriding existing environment variables.
169///
170/// Where multiple declarations for the same environment variable exist in your *.env* file, the
171/// *last one* is applied.
172///
173/// If you want the existing environment to take precedence,
174/// or if you want to be able to override environment variables on the command line,
175/// then use [`from_filename`] instead.
176///
177/// # Examples
178/// ```no_run
179/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
180/// dotenvy::from_filename_override("custom.env")?;
181/// # Ok(())
182/// # }
183/// ```
184///
185/// It is also possible to load from a typical *.env* file like so. However, using [`dotenv_override`] is preferred.
186///
187/// ```
188/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
189/// dotenvy::from_filename_override(".env")?;
190/// # Ok(())
191/// # }
192/// ```
193pub fn from_filename_override<P: AsRef<Path>>(filename: P) -> Result<PathBuf> {
194 let (path, iter) = Finder::new().filename(filename.as_ref()).find()?;
195 iter.load_override()?;
196 Ok(path)
197}
198
199/// Returns an iterator over environment variables from the specified file.
200///
201/// # Examples
202///
203/// ```no_run
204/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
205/// for item in dotenvy::from_filename_iter("custom.env")? {
206/// let (key, val) = item?;
207/// println!("{}={}", key, val);
208/// }
209/// # Ok(())
210/// # }
211/// ```
212
213pub fn from_filename_iter<P: AsRef<Path>>(filename: P) -> Result<Iter<File>> {
214 let (_, iter) = Finder::new().filename(filename.as_ref()).find()?;
215 Ok(iter)
216}
217
218/// Loads environment variables from [`io::Read`](std::io::Read).
219///
220/// This is useful for loading environment variables from IPC or the network.
221///
222/// If variables with the same names already exist in the environment, then their values will be
223/// preserved.
224///
225/// Where multiple declarations for the same environment variable exist in your `reader`,
226/// the *first one* is applied.
227///
228/// If you wish to ensure all variables are loaded from your `reader`, ignoring variables
229/// already existing in the environment, then use [`from_read_override`] instead.
230///
231/// For regular files, use [`from_path`] or [`from_filename`].
232///
233/// # Examples
234///
235/// ```no_run
236/// # #![cfg(unix)]
237/// use std::io::Read;
238/// use std::os::unix::net::UnixStream;
239///
240/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
241/// let mut stream = UnixStream::connect("/some/socket")?;
242/// dotenvy::from_read(stream)?;
243/// # Ok(())
244/// # }
245/// ```
246pub fn from_read<R: io::Read>(reader: R) -> Result<()> {
247 let iter = Iter::new(reader);
248 iter.load()?;
249 Ok(())
250}
251
252/// Loads environment variables from [`io::Read`](std::io::Read),
253/// overriding existing environment variables.
254///
255/// This is useful for loading environment variables from IPC or the network.
256///
257/// Where multiple declarations for the same environment variable exist in your `reader`, the
258/// *last one* is applied.
259///
260/// If you want the existing environment to take precedence,
261/// or if you want to be able to override environment variables on the command line,
262/// then use [`from_read`] instead.
263///
264/// For regular files, use [`from_path_override`] or [`from_filename_override`].
265///
266/// # Examples
267/// ```no_run
268/// # #![cfg(unix)]
269/// use std::io::Read;
270/// use std::os::unix::net::UnixStream;
271///
272/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
273/// let mut stream = UnixStream::connect("/some/socket")?;
274/// dotenvy::from_read_override(stream)?;
275/// # Ok(())
276/// # }
277/// ```
278pub fn from_read_override<R: io::Read>(reader: R) -> Result<()> {
279 let iter = Iter::new(reader);
280 iter.load_override()?;
281 Ok(())
282}
283
284/// Returns an iterator over environment variables from [`io::Read`](std::io::Read).
285///
286/// # Examples
287///
288/// ```no_run
289/// # #![cfg(unix)]
290/// use std::io::Read;
291/// use std::os::unix::net::UnixStream;
292///
293/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
294/// let mut stream = UnixStream::connect("/some/socket")?;
295///
296/// for item in dotenvy::from_read_iter(stream) {
297/// let (key, val) = item?;
298/// println!("{}={}", key, val);
299/// }
300/// # Ok(())
301/// # }
302/// ```
303pub fn from_read_iter<R: io::Read>(reader: R) -> Iter<R> {
304 Iter::new(reader)
305}
306
307/// Loads the *.env* file from the current directory or parents. This is typically what you want.
308///
309/// If variables with the same names already exist in the environment, then their values will be
310/// preserved.
311///
312/// Where multiple declarations for the same environment variable exist in your *.env*
313/// file, the *first one* is applied.
314///
315/// If you wish to ensure all variables are loaded from your *.env* file, ignoring variables
316/// already existing in the environment, then use [`dotenv_override`] instead.
317///
318/// An error will be returned if the file is not found.
319///
320/// # Examples
321///
322/// ```
323/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
324/// dotenvy::dotenv()?;
325/// # Ok(())
326/// # }
327/// ```
328pub fn dotenv() -> Result<PathBuf> {
329 let (path, iter) = Finder::new().find()?;
330 iter.load()?;
331 Ok(path)
332}
333
334/// Loads all variables found in the `reader` into the environment,
335/// overriding any existing environment variables of the same name.
336///
337/// Where multiple declarations for the same environment variable exist in your *.env* file, the
338/// *last one* is applied.
339///
340/// If you want the existing environment to take precedence,
341/// or if you want to be able to override environment variables on the command line,
342/// then use [`dotenv`] instead.
343///
344/// # Examples
345/// ```
346/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
347/// dotenvy::dotenv_override()?;
348/// # Ok(())
349/// # }
350/// ```
351pub fn dotenv_override() -> Result<PathBuf> {
352 let (path, iter) = Finder::new().find()?;
353 iter.load_override()?;
354 Ok(path)
355}
356
357/// Returns an iterator over environment variables.
358///
359/// # Examples
360///
361/// ```
362/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
363/// for item in dotenvy::dotenv_iter()? {
364/// let (key, val) = item?;
365/// println!("{}={}", key, val);
366/// }
367/// # Ok(())
368/// # }
369/// ```
370pub fn dotenv_iter() -> Result<iter::Iter<File>> {
371 let (_, iter) = Finder::new().find()?;
372 Ok(iter)
373}