use crate::env_file::{ApplyEnvironmentFile, ApplyOptions}; use crate::EnvironmentFile; use std::fmt::Display; use std::fs::File; use std::io::Read; use std::path::Path; #[derive(Debug, thiserror::Error)] #[allow(clippy::enum_variant_names)] pub enum EnvFsError { /// Error opening the file, or reading it into a buffer. #[error(transparent)] IoError(#[from] std::io::Error), /// Error parsing the file from a string into an EnvironmentFile. Denotes syntax errors in the /// file. #[error(transparent)] ParseError(#[from] crate::EnvironmentFileError), /// An error thrown specifically when the given environment variable exists, but is cannot be /// represented in Rust (e.g. not Unicode). This error does **not** occur when the environment /// variable exists as valid Unicode. #[error("The target environment variable exists, but is not Unicode")] EnvironmentError, } /// Reads the file `.env` into memory, but does not apply it to the environment. pub fn env_file() -> Result<EnvironmentFile, EnvFsError> { env_file_from_path(".env") } /// Reads the file `.env.<environment>` into memory, but does not apply it to the environment. /// /// ### Example /// /// Calling `env_file_suffix("production")` will attempt to read the file `.env.production` in the /// directory the server was launched from. pub fn env_file_suffix(environment: impl Display) -> Result<EnvironmentFile, EnvFsError> { env_file_from_path(format!(".env.{}", environment)) } /// Reads the file at the specified path into memory, but does not apply it to the environment. pub fn env_file_from_path(path: impl AsRef<Path>) -> Result<EnvironmentFile, EnvFsError> { let mut file = File::open(path)?; let mut buffer = String::new(); file.read_to_string(&mut buffer)?; Ok(buffer.parse()?) } /// Look up a `.env` file in the working directory and apply its contents to the current environment. /// /// ### Errors /// /// This method returns an error under the following circumstances: /// /// - The target file does not exist /// - There was an error when reading the target file /// - The target was not a correctly formatted `.env` file /// /// ### Example /// /// This example will attempt to read the file `.env` in the directory the server was launched from. /// ```rust /// use envish::dotenv; /// let _ = dotenv(); /// ``` pub fn dotenv() -> Result<(), EnvFsError> { env_file()?.apply(Default::default()); Ok(()) } /// Look up a `.env` file in the working directory and apply its contents to the current environment, /// with the provided options, allowing for prefixing and overwriting existing values. /// /// ### Errors /// /// This method returns an error under the following circumstances: /// /// - The target file does not exist /// - There was an error when reading the target file /// - The target was not a correctly formatted `.env` file /// /// ### Example /// /// This example will attempt to read the file `.env`, and will prepend the given prefix to all the /// contained variables. For example, a variable in the file named "DATABASE_URL" will be added to /// the environment as "APP_DATABASE_URL". /// /// ```rust /// use envish::{dotenv_opts, ApplyOptions}; /// let _ = dotenv_opts(ApplyOptions::with_prefix("APP_")); /// ``` pub fn dotenv_opts(options: ApplyOptions) -> Result<(), EnvFsError> { env_file()?.apply(options); Ok(()) } /// Look up a `.env` file with the provided suffix in the working directory and apply its contents /// to the current environment. /// /// ### Errors /// /// This method returns an error under the following circumstances: /// /// - The target file does not exist /// - There was an error when reading the target file /// - The target was not a correctly formatted `.env` file /// /// ### Example /// /// This example will attempt to read the file `.env.development` /// /// ```rust /// use envish::dotenv_suffix; /// let _ = dotenv_suffix("development"); /// ``` pub fn dotenv_suffix(environment: impl Display) -> Result<(), EnvFsError> { env_file_suffix(environment)?.apply(Default::default()); Ok(()) } /// Look up an environment file at the given path and apply its contents to the current environment. /// /// ### Errors /// /// This method returns an error under the following circumstances: /// /// - The target file does not exist /// - There was an error when reading the target file /// - The target was not a correctly formatted `.env` file /// /// ### Example /// /// This example will attempt to read the file `my_dotenv_file` at the specified path. The file must /// be correctly formatted as any other .env file, but does not need to have a specific name. /// /// ```rust /// use envish::dotenv_from; /// let _ = dotenv_from("/some/other/path/to/my_dotenv_file"); /// ``` pub fn dotenv_from(path: impl AsRef<Path>) -> Result<(), EnvFsError> { env_file_from_path(path)?.apply(Default::default()); Ok(()) }