Current section

Files

Jump to
dot_env src dot_env.gleam
Raw

src/dot_env.gleam

import gleam/io
import gleam/string
import gleam/result.{try}
import dot_env/internal/parser
import dot_env/env
import simplifile
pub type Opts {
/// Customized options for loading the .env file
Opts(
/// The path to the .env file relative to the project root eg. .env and src/.env are two different things, .env points to the root of the project, src/.env points to the src folder in the root of the project
path: String,
/// Print debug information if something goes wrong
debug: Bool,
/// Force all keys to be uppercase
capitalize: Bool,
)
/// Default options for loading the .env file - see `default` constant
Default
}
pub opaque type DotEnv {
DotEnv(path: String, debug: Bool, capitalize: Bool)
}
pub const default = DotEnv(path: ".env", debug: True, capitalize: True)
///
/// Load the .env file at the default path (.env) and set the environment variables
///
/// Debug information will be printed to the console if something goes wrong and all keys will be capitalized
///
/// # Example
///
/// ```gleam
/// import dot_env
///
/// pub fn main() {
/// dot_env.load()
/// }
/// ```
pub fn load() {
load_with_opts(Default)
}
///
/// Load the .env file at the specified path and set the environment variables
///
/// Debug information and key capitalization can be customized
///
/// # Example
///
/// ```gleam
/// import dot_env
///
/// pub fn main() {
/// dot_env.load_with_opts(dot_env.Opts(path: "src/.env", debug: False, capitalize: False))
/// }
/// ```
pub fn load_with_opts(opts: Opts) {
let dotenv = case opts {
Opts(path, debug, capitalize) -> DotEnv(path, debug, capitalize)
Default -> default
}
dotenv
|> load_and_return_error
|> fn(r) {
case r {
Ok(_) -> Nil
Error(msg) -> {
case dotenv.debug {
True -> io.println_error(msg)
False -> Nil
}
}
}
}
}
fn load_and_return_error(dotenv: DotEnv) -> Result(Nil, String) {
use content <- try(read_file(dotenv))
use kv_pairs <- try(parser.parse(content))
dotenv
|> recursively_set_environment_variables(kv_pairs)
Ok(Nil)
}
fn recursively_set_environment_variables(
config: DotEnv,
kv_pairs: parser.EnvPairs,
) {
case kv_pairs {
[] -> Nil
[pair] -> {
env.set(
case config.capitalize {
True -> string.uppercase(pair.0)
False -> pair.0
},
pair.1,
)
}
[pair, ..rest] -> {
env.set(
case config.capitalize {
True -> string.uppercase(pair.0)
False -> pair.0
},
pair.1,
)
recursively_set_environment_variables(config, rest)
}
}
}
fn read_file(dotenv: DotEnv) -> Result(String, String) {
case simplifile.is_file(dotenv.path) {
True -> {
case simplifile.read(dotenv.path) {
Ok(contents) -> Ok(contents)
Error(_) -> {
let msg =
"Unable to read file at `" <> dotenv.path <> "`, ensure the file exists and is readable"
io.println(msg)
Error(msg)
}
}
}
False -> Error("Specified file `" <> dotenv.path <> "` does not exist")
}
}