zenv/
lib.rs

1//! Zenv is a dotenv loader which parses and loads your environment variables from a `.env` file.
2//!
3//! This crate also supports variable substitution inside your .env file, if not found then
4//! tries to fetch from the running operating system. By default, this is disabled.
5//!
6//! _This crate only meant to use inside a development environment._
7//!
8//! Example
9//! ```
10//! use zenv::{zenv, Zenv};
11//!
12//! fn main() {
13//!     Zenv::new(".env", false).configure().ok();
14//!     // is equivalent to
15//!     zenv!();
16//!
17//!     // with other file
18//!     zenv!(".env.development");
19//!
20//!     // or with variable substitution
21//!     zenv!(".env.development", true);
22//! }
23//! ```
24
25mod parser;
26
27use std::{
28    collections::HashMap,
29    fs::read_to_string,
30    io::{Error, ErrorKind, Result},
31    path::PathBuf,
32};
33
34// Just re-exporting to use as a standalone parser
35pub use parser::{KeyVal, Line, Lines, Quote};
36
37/// Use this to load and configure the environment variables
38#[derive(Debug)]
39pub struct Zenv {
40    path: PathBuf,
41    expand: bool,
42}
43
44impl Zenv {
45    /// Create a new instance of Zenv with the provided file path
46    pub fn new(path: &str, expand: bool) -> Self {
47        Self {
48            path: PathBuf::from(path),
49            expand,
50        }
51    }
52
53    /// Read and parse the file from provided path and returns a hashmap
54    ///
55    /// Example
56    /// ```
57    /// let parsed = zenv::Zenv::new("tests/.env.basic", false).parse().unwrap();
58    ///
59    /// assert_eq!(parsed.get("BASIC"), Some(&"basic".to_string()))
60    /// ```
61    pub fn parse(&self) -> Result<HashMap<String, String>> {
62        let path = &self.path;
63
64        if !path.exists() {
65            return Err(Error::new(
66                ErrorKind::NotFound,
67                format!("Unable to find file - {}", path.display()),
68            ));
69        }
70
71        let r = read_to_string(path)?;
72        let lines = Lines::from(r.as_str());
73
74        let hash = match self.expand {
75            true => lines.expand(),
76            false => lines.to_hash_map(),
77        };
78
79        Ok(hash)
80    }
81
82    /// Parse the file using [Zenv::parse] and sets the environment variable
83    ///
84    /// Example
85    /// ```
86    /// zenv::Zenv::new("tests/.env.basic", false).configure().ok();
87    ///
88    /// assert_eq!(std::env::var_os("BASIC"), Some("basic".into()))
89    /// ```
90    pub fn configure(&self) -> Result<()> {
91        let vars = self.parse()?;
92
93        for (key, val) in vars {
94            std::env::set_var(key, val);
95        }
96
97        Ok(())
98    }
99}
100
101/// This macro can be used as a shortcut for [`Zenv`]
102///
103/// Example
104/// ```
105/// use zenv::zenv;
106///
107/// zenv!();
108///
109/// // with other file
110/// zenv!(".env.development");
111///
112/// // or with variable substitution
113/// zenv!(".env.development", true);
114/// ````
115#[macro_export]
116macro_rules! zenv {
117    () => {
118        zenv::Zenv::new(".env", false).configure().ok()
119    };
120    ($path:expr) => {
121        zenv::Zenv::new($path, false).configure().ok()
122    };
123    ($path:expr, $expand:expr) => {
124        zenv::Zenv::new($path, $expand).configure().ok()
125    };
126}