From 91a73bce5c16577182de93588f67a9d1f2298a42 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:54:45 +0100 Subject: [PATCH 01/12] Version 1 (begin) --- src/dot_env.gleam | 2 - src/dot_env/env.gleam | 65 ------------------------------- src/dot_env/internal/parser.gleam | 3 +- 3 files changed, 2 insertions(+), 68 deletions(-) delete mode 100644 src/dot_env/env.gleam diff --git a/src/dot_env.gleam b/src/dot_env.gleam index d634b04..a74c660 100644 --- a/src/dot_env.gleam +++ b/src/dot_env.gleam @@ -34,7 +34,6 @@ pub const default = DotEnv( ignore_missing_file: 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 @@ -52,7 +51,6 @@ 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 diff --git a/src/dot_env/env.gleam b/src/dot_env/env.gleam deleted file mode 100644 index aff80b2..0000000 --- a/src/dot_env/env.gleam +++ /dev/null @@ -1,65 +0,0 @@ -import gleam/int -import gleam/result - -/// Set an environment variable (supports both Erlang and JavaScript targets) -/// -/// Example: -/// ```gleam -/// import dot_env/env -/// -/// env.set("MY_ENV_VAR", "my value") -/// ``` -/// -@external(erlang, "dot_env_ffi", "set_env") -@external(javascript, "../dot_env_ffi.mjs", "set_env") -pub fn set(key: String, value: String) -> Nil - -/// Get an environment variable (supports both Erlang and JavaScript targets) -/// -/// Example: -/// ```gleam -/// import dot_env/env -/// import gleam/io -/// import gleam/result -/// -/// env.get("MY_ENV_VAR") -/// |> result.unwrap("NOT SET") -/// |> io.println -/// ``` -@external(erlang, "dot_env_ffi", "get_env") -@external(javascript, "../dot_env_ffi.mjs", "get_env") -pub fn get(key: String) -> Result(String, String) - -/// Get an environment variable or return a default value -pub fn get_or(key: String, default: String) -> String { - case get(key) { - Ok(value) -> value - Error(_) -> default - } -} - -/// Get an environment variable as an integer -pub fn get_int(key: String) -> Result(Int, String) { - case get(key) { - Ok(value) -> { - int.parse(value) - |> result.map_error(fn(_) { - "Failed to parse string to int, confirm the value you are trying to retrieve is a valid integer" - }) - } - Error(e) -> Error(e) - } -} - -/// Get an environment variable as a boolean -pub fn get_bool(key: String) -> Result(Bool, String) { - case get(key) { - Ok(value) -> { - case value { - "True" | "true" | "1" -> Ok(True) - _ -> Ok(False) - } - } - Error(e) -> Error(e) - } -} diff --git a/src/dot_env/internal/parser.gleam b/src/dot_env/internal/parser.gleam index 6559343..fa8cf94 100644 --- a/src/dot_env/internal/parser.gleam +++ b/src/dot_env/internal/parser.gleam @@ -1,6 +1,6 @@ -import gleam/string import gleam/list import gleam/result.{try} +import gleam/string pub type KVPair = #(String, String) @@ -121,3 +121,4 @@ fn join(strings: List(String)) -> String { |> list.reverse |> string.join("") } + From 0cb12471eb883bef2242b5612b9a17ac1d6345f9 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 27 May 2024 02:28:19 +0100 Subject: [PATCH 02/12] More JS shenanigan --- src/dot_env.gleam | 14 +++++------ src/dot_env_ffi.mjs | 58 ++++++++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/dot_env.gleam b/src/dot_env.gleam index a74c660..65261a0 100644 --- a/src/dot_env.gleam +++ b/src/dot_env.gleam @@ -1,9 +1,9 @@ +import dot_env/env +import dot_env/internal/parser import gleam/bool import gleam/io -import gleam/string import gleam/result.{try} -import dot_env/internal/parser -import dot_env/env +import gleam/string import simplifile pub type Opts { @@ -147,11 +147,9 @@ fn read_file(dotenv: DotEnv) -> Result(String, String) { use contents <- result.try( simplifile.read(dotenv.path) |> result.map_error(with: fn(_) { - let msg = - "Unable to read file at `" - <> dotenv.path - <> "`, ensure the file exists and is readable" - msg + "Unable to read file at `" + <> dotenv.path + <> "`, ensure the file exists and is readable" }), ) diff --git a/src/dot_env_ffi.mjs b/src/dot_env_ffi.mjs index 2ad4c00..618668f 100644 --- a/src/dot_env_ffi.mjs +++ b/src/dot_env_ffi.mjs @@ -1,27 +1,51 @@ import { Ok as GleamOk, Error as GleamError } from "./gleam.mjs"; -const Nil = undefined; - +// TODO: support bun and deno export function set_env(key, value) { - if (!process.env) { - console.error("process.env is not available"); - return Nil; - } + const runtime = get_runtime(); + if (runtime == "browser") + return GleamError("dotenv is not supported in browser"); + if (runtime == "unknown") return GleamError("unknown runtime"); + + if (!process.env) { + console.error("process.env is not available"); + return Nil; + } - process.env[key] = value; - return Nil; + process.env[key] = value; + return Nil; } export function get_env(key) { - if (!process.env) { - console.error("process.env is not available"); - return new GleamError("process.env is not available"); - } + if (!process.env) { + console.error("process.env is not available"); + return new GleamError("process.env is not available"); + } + + const value = process.env[key]; + if (!value) { + return new GleamError(`key \`${key}\` is not set`); + } + + return new GleamOk(value); +} + +function get_runtime() { + if (typeof process !== "undefined") { + return "node"; + } + + if (typeof Deno !== "undefined") { + return "deno"; + } + + if (typeof Bun !== "undefined") { + return "bun"; + } - const value = process.env[key]; - if (!value) { - return new GleamError(`key \`${key}\` is not set`); - } + if (typeof window !== "undefined") { + return "browser"; + } - return new GleamOk(value); + return "unknown"; } From 17fdae5efdee1e9d1a37a33f97344bebe317e207 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Sun, 2 Jun 2024 22:29:02 +0100 Subject: [PATCH 03/12] Support Node, Bun and Deno (#8) --- src/dot_env_ffi.mjs | 109 +++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/src/dot_env_ffi.mjs b/src/dot_env_ffi.mjs index 618668f..a20fa5a 100644 --- a/src/dot_env_ffi.mjs +++ b/src/dot_env_ffi.mjs @@ -1,51 +1,88 @@ -import { Ok as GleamOk, Error as GleamError } from "./gleam.mjs"; +import { Error as GleamError, Ok as GleamOk } from "./gleam.mjs"; -// TODO: support bun and deno +const Nil = undefined; + +/** + * @param {string} key + * @param {string} value + * @returns {GleamError | GleamOk} + */ export function set_env(key, value) { - const runtime = get_runtime(); - if (runtime == "browser") - return GleamError("dotenv is not supported in browser"); - if (runtime == "unknown") return GleamError("unknown runtime"); - - if (!process.env) { - console.error("process.env is not available"); - return Nil; - } - - process.env[key] = value; - return Nil; + // Ensure we can even run in this runtime + const runtime = get_runtime(); + if (runtime == "unknown") { + return GleamError("unknown runtime"); + } + + // Ensure we have a non-empty key and a non-null/empty value + key = key?.trim(); + if (!key) return GleamError("key is required"); + if (value === undefined || value === null) { + // A blank string counts as a value in this case, useful for situations where the user explicitly wants to override an env var with an empty string + return GleamError("value is required for key: " + key); + } + + if (runtime == "node" || runtime == "bun") { + process.env[key?.trim()] = value; + } else if (runtime == "deno") { + Deno.env.set(key?.trim(), value); + } else { + return GleamError("unsupported runtime: " + runtime); + } + + return GleamOk(Nil); } +/** + * @param {string} key + * @param {string} value + * @returns {GleamError | GleamOk} + */ export function get_env(key) { - if (!process.env) { - console.error("process.env is not available"); - return new GleamError("process.env is not available"); - } + const runtime = get_runtime(); + if (runtime == "unknown") { + return GleamError("unknown runtime"); + } + + key = key?.trim(); + if (!key) return GleamError("key is required"); + + let value = ""; - const value = process.env[key]; - if (!value) { - return new GleamError(`key \`${key}\` is not set`); - } + switch (runtime) { + case "node": + case "bun": + value = process.env[key]; + break; + case "deno": + value = Deno.env.get(key); + break; + default: + return GleamError("unsupported runtime: " + runtime); + } - return new GleamOk(value); + return new GleamOk(value); } +/** + * @returns {"node" | "deno" | "bun" | "browser" | "unknown"} + */ function get_runtime() { - if (typeof process !== "undefined") { - return "node"; - } + if (typeof process !== "undefined") { + return "node"; + } - if (typeof Deno !== "undefined") { - return "deno"; - } + if (typeof Deno !== "undefined") { + return "deno"; + } - if (typeof Bun !== "undefined") { - return "bun"; - } + if (typeof Bun !== "undefined") { + return "bun"; + } - if (typeof window !== "undefined") { - return "browser"; - } + if (typeof window !== "undefined") { + return "browser"; + } - return "unknown"; + return "unknown"; } From 95ade95715c90c047b21c120529fec051ce99072 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:21:01 +0100 Subject: [PATCH 04/12] Return result in set_env for Erlang runtime --- src/dot_env_ffi.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dot_env_ffi.erl b/src/dot_env_ffi.erl index 1d5f58a..a88ce2e 100644 --- a/src/dot_env_ffi.erl +++ b/src/dot_env_ffi.erl @@ -12,4 +12,4 @@ get_env(Name) -> set_env(Name, Value) -> os:putenv(binary_to_list(Name), binary_to_list(Value)), - nil. + {ok, nil}. From 66ad35a9a15f0e93212c0f88149e6941b7ea38ae Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:29:34 +0100 Subject: [PATCH 05/12] Minor `env` module updates - Added new default implementations for int and bool - Refactored to be more idiomatic --- src/dot_env/env.gleam | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/dot_env/env.gleam diff --git a/src/dot_env/env.gleam b/src/dot_env/env.gleam new file mode 100644 index 0000000..632f902 --- /dev/null +++ b/src/dot_env/env.gleam @@ -0,0 +1,87 @@ +import gleam/int +import gleam/result +import gleam/string + +/// Set an environment variable (supports both Erlang and JavaScript targets) +/// +/// Example: +/// ```gleam +/// import dot_env/env +/// +/// env.set("FOO", "my value") +/// ``` +/// +@external(erlang, "dot_env_ffi", "set_env") +@external(javascript, "../dot_env_ffi.mjs", "set_env") +pub fn set(key: String, value: String) -> Result(Nil, String) + +/// Get an environment variable (supports both Erlang and JavaScript targets) +/// +/// Example: +/// ```gleam +/// import dot_env/env +/// import gleam/io +/// import gleam/result +/// +/// env.get("FOO") +/// |> result.unwrap("NOT SET") +/// |> io.println +/// ``` +@external(erlang, "dot_env_ffi", "get_env") +@external(javascript, "../dot_env_ffi.mjs", "get_env") +pub fn get(key: String) -> Result(String, String) + +/// Get an environment variable or return a default value if it is not set +pub fn get_or(key: String, default: String) -> String { + get(key) + |> result.unwrap(default) +} + +/// An alternative implementation of `get` that allows for chaining using `use` +pub fn get_then( + key: String, + f: fn(String) -> Result(t, String), +) -> Result(t, String) { + case get(key) { + Ok(value) -> f(value) + Error(err) -> Error(err) + } +} + +/// Get an environment variable as an integer +pub fn get_int(key: String) -> Result(Int, String) { + use raw_value <- get_then(key) + + int.parse(raw_value) + |> result.map_error(fn(_) { + "Failed to parse environment variable for `" <> key <> "` as integer" + }) +} + +/// Get an environment variable as an integer or return a default value if it is not set +pub fn get_int_or(key: String, default: Int) -> Int { + get_int(key) + |> result.unwrap(default) +} + +/// Get an environment variable as a boolean +pub fn get_bool(key: String) -> Result(Bool, String) { + use raw_value <- get_then(key) + + case string.lowercase(raw_value) { + "true" | "1" -> Ok(True) + "false" | "0" -> Ok(True) + _ -> + Error( + "Invalid boolean value for environment variable `" + <> key + <> "`. Expected one of `true`, `false`, `1`, or `0`.", + ) + } +} + +/// Get an environment variable as a boolean or return a default value if it is not set +pub fn get_bool_or(key: String, default: Bool) -> Bool { + get_bool(key) + |> result.unwrap(default) +} From 0c7acd2b0274428e322dbdfca2f4cda6c2c7c359 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Sun, 2 Jun 2024 23:59:21 +0100 Subject: [PATCH 06/12] Fixed JS bindings --- src/dot_env_ffi.mjs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/dot_env_ffi.mjs b/src/dot_env_ffi.mjs index a20fa5a..ce0a773 100644 --- a/src/dot_env_ffi.mjs +++ b/src/dot_env_ffi.mjs @@ -11,7 +11,7 @@ export function set_env(key, value) { // Ensure we can even run in this runtime const runtime = get_runtime(); if (runtime == "unknown") { - return GleamError("unknown runtime"); + return new GleamError("unknown runtime"); } // Ensure we have a non-empty key and a non-null/empty value @@ -19,7 +19,7 @@ export function set_env(key, value) { if (!key) return GleamError("key is required"); if (value === undefined || value === null) { // A blank string counts as a value in this case, useful for situations where the user explicitly wants to override an env var with an empty string - return GleamError("value is required for key: " + key); + return new GleamError("value is required for key: " + key); } if (runtime == "node" || runtime == "bun") { @@ -27,10 +27,10 @@ export function set_env(key, value) { } else if (runtime == "deno") { Deno.env.set(key?.trim(), value); } else { - return GleamError("unsupported runtime: " + runtime); + return new GleamError("unsupported runtime: " + runtime); } - return GleamOk(Nil); + return new GleamOk(Nil); } /** @@ -41,24 +41,28 @@ export function set_env(key, value) { export function get_env(key) { const runtime = get_runtime(); if (runtime == "unknown") { - return GleamError("unknown runtime"); + return new GleamError("unknown runtime"); } key = key?.trim(); - if (!key) return GleamError("key is required"); + if (!key) return new GleamError("key is required"); - let value = ""; + let value = Nil; switch (runtime) { case "node": case "bun": - value = process.env[key]; + value = process?.env[key]; break; case "deno": value = Deno.env.get(key); break; default: - return GleamError("unsupported runtime: " + runtime); + return new GleamError("unsupported runtime: " + runtime); + } + + if (value == Nil || value === undefined) { + return new GleamError(Nil); } return new GleamOk(value); From 900fe4122c468e74675fb36ec941e56c74554d75 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:16:16 +0100 Subject: [PATCH 07/12] Added builder methods and fixed all tests --- src/dot_env.gleam | 64 +++++++++++++++++++++++++++++++++++++++-- test/dot_env_test.gleam | 29 +++++++++++++++---- 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/src/dot_env.gleam b/src/dot_env.gleam index 65261a0..742ce4a 100644 --- a/src/dot_env.gleam +++ b/src/dot_env.gleam @@ -34,6 +34,66 @@ pub const default = DotEnv( ignore_missing_file: True, ) +/// Create a default DotEnv instance. This is designed to use used as the starting point for using any of the builder methods +pub fn new() -> DotEnv { + default +} + +/// Create a new DotEnv instance with the specified path +pub fn new_with_path(path: String) -> DotEnv { + DotEnv(..default, path: path) +} + +/// Set whether to print debug information in the current DotEnv instance +pub fn set_debug(instance: DotEnv, debug: Bool) -> DotEnv { + DotEnv(..instance, debug: debug) +} + +/// Set whether to capitalize all keys in the current DotEnv instance +pub fn set_capitalize(instance: DotEnv, capitalize: Bool) -> DotEnv { + DotEnv(..instance, capitalize: capitalize) +} + +/// Set whether to ignore missing file errors in the current DotEnv instance +pub fn set_ignore_missing_file( + instance: DotEnv, + ignore_missing_file: Bool, +) -> DotEnv { + DotEnv(..instance, ignore_missing_file: ignore_missing_file) +} + +/// Set the path to the .env file in the current DotEnv instance +pub fn set_path(instance: DotEnv, path: String) -> DotEnv { + DotEnv(..instance, path: path) +} + +/// Get the path to the .env file in the current DotEnv instance +pub fn path(instance: DotEnv) -> String { + instance.path +} + +/// Load the .env file using the current DotEnv instance and set the environment variables +/// +/// # Example +/// +/// ```gleam +/// import dot_env as dot +/// +/// pub fn main() { +/// dot.new() +/// |> dot.set_path("src/.env") +/// |> dot.set_debug(False) +/// |> dot.load +/// } +pub fn load(dotenv: DotEnv) -> Nil { + load_with_opts(Opts( + path: dotenv.path, + debug: dotenv.debug, + capitalize: dotenv.capitalize, + ignore_missing_file: dotenv.ignore_missing_file, + )) +} + /// 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 @@ -44,10 +104,10 @@ pub const default = DotEnv( /// import dot_env /// /// pub fn main() { -/// dot_env.load() +/// dot_env.load_default() /// } /// ``` -pub fn load() { +pub fn load_default() -> Nil { load_with_opts(Default) } diff --git a/test/dot_env_test.gleam b/test/dot_env_test.gleam index 002f6e7..e70e6d7 100644 --- a/test/dot_env_test.gleam +++ b/test/dot_env_test.gleam @@ -8,7 +8,13 @@ pub fn main() { } pub fn get_test() { - dot_env.load() + dot_env.load_default() + + env.get("DEFINITELY_NOT_A_REAL_KEY") + |> should.be_error + + env.get("PORT") + |> should.equal(Ok("9000")) env.get_or("UNDEFINED_KEY", "default") |> should.equal("default") @@ -18,10 +24,22 @@ pub fn get_test() { env.get_bool("APP_DEBUG") |> should.equal(Ok(True)) + + env.get_int_or("PORT", 3000) + |> should.equal(9000) + + env.get_bool_or("APP_DEBUG", False) + |> should.equal(True) + + env.get_bool("PORT") + |> should.be_error + + env.get_int("APP_DEBUG") + |> should.be_error } pub fn load_missing_env_file_test() { - env.set("PORT", "9000") + let assert Ok(Nil) = env.set("PORT", "9000") // This should not fail or crash dot_env.load_with_opts(Opts( @@ -36,7 +54,7 @@ pub fn load_missing_env_file_test() { } pub fn load_default_test() { - dot_env.load() + dot_env.load_default() env.get("PORT") |> should.equal(Ok("9000")) @@ -223,9 +241,8 @@ pub fn load_multiline_test() { env.get("MULTI_DOUBLE_QUOTED") |> should.equal(Ok("THIS\nIS\nA\nMULTILINE\nSTRING")) - // Currently failing i.e. not supported - // env.get("MULTI_SINGLE_QUOTED") - // |> should.equal(Ok("THIS\nIS\nA\nMULTILINE\nSTRING")) + env.get("MULTI_SINGLE_QUOTED") + |> should.equal(Ok("THIS\nIS\nA\nMULTILINE\nSTRING")) env.get("MULTI_BACKTICKED") |> should.equal(Ok("THIS\nIS\nA\n\"MULTILINE'S\"\nSTRING")) From 94905bc5f17826dfbee747b6da6020388220a7ff Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:17:18 +0100 Subject: [PATCH 08/12] Refactored to use results in env setting related methods --- src/dot_env.gleam | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/dot_env.gleam b/src/dot_env.gleam index 742ce4a..8cd6b3f 100644 --- a/src/dot_env.gleam +++ b/src/dot_env.gleam @@ -131,9 +131,7 @@ pub fn load_with_opts(opts: Opts) { Default -> default } - let state = - dotenv - |> load_and_return_error + let state = dotenv |> load_and_return_error case state { Ok(_) -> Nil @@ -154,8 +152,6 @@ fn load_and_return_error(dotenv: DotEnv) -> Result(Nil, String) { dotenv |> recursively_set_environment_variables(kv_pairs) - - Ok(Nil) } fn handle_file_result( @@ -166,26 +162,25 @@ fn handle_file_result( res } -fn set_env(config: DotEnv, pair: #(String, String)) { - let #(key, value) = pair - +fn set_env(config: DotEnv, pair: #(String, String)) -> Result(Nil, String) { let key = { - use <- bool.guard(when: !config.capitalize, return: key) - string.uppercase(key) + use <- bool.guard(when: !config.capitalize, return: pair.0) + string.uppercase(pair.0) } - env.set(key, value) + key + |> env.set(pair.1) } fn recursively_set_environment_variables( config: DotEnv, kv_pairs: parser.KVPairs, -) { +) -> Result(Nil, String) { case kv_pairs { - [] -> Nil + [] -> Ok(Nil) [pair] -> set_env(config, pair) [pair, ..rest] -> { - set_env(config, pair) + use _ <- result.try(set_env(config, pair)) recursively_set_environment_variables(config, rest) } } From fecb05092d0c7fe995e91ddc92b86eecec4f49f6 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:17:27 +0100 Subject: [PATCH 09/12] Updated docs --- README.md | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bc4e625..5d367a1 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,9 @@ -- [dot_env](#dotenv) - - [Quick start](#quick-start) - - [Installation](#installation) - +- [Quick start](#quick-start) +- [Installation](#installation) + [![Package Version](https://img.shields.io/hexpm/v/dot_env)](https://hex.pm/packages/dotenv) [![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/dot_env/) @@ -14,24 +13,37 @@ dot_env is a port of the popular JavaScript [dotenv](https://github.com/motdotla > This package may support other formats in the future but for now, supports the popular .env format > -> You can find the Javascript test [here](https://github.com/aosasona/dot_js_test) +> You can find the Javascript "tests" [here](https://github.com/aosasona/dot_js_test) ## Quick start ```gleam -import dot_env +import dot_env as dot import dot_env/env import gleam/io pub fn main() { - dot_env.load_with_opts(dot_env.Opts(path: "path/to/.env", debug: False, capitalize: False)) - // or `dot_env.load()` to load the `.env` file in the root path + dot.new() + |> dot.set_path("path/to/.env") + |> dot.set_debug(False) + |> dot.load + + // or dot_env.load_with_opts(dot_env.Opts(path: "path/to/.env", debug: False, capitalize: False)) + // or `dot_env.load_default()` to load the `.env` file in the root path case env.get("MY_ENV_VAR") { Ok(value) -> io.println(value) Error(_) -> io.println("something went wrong") } + let app_name = env.get_or("APP_NAME", "my app name") + let port = env.get_int_or("PORT", 3000) + let enable_signup = env.get_bool_or("ENABLE_SIGNUP", True) + + io.debug(app_name) + io.debug(port) + io.debug(enable_signup) + Nil } ``` From 25d8d887a53f4151bf1ad4b814c9cfb9d1de870b Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:19:37 +0100 Subject: [PATCH 10/12] Bump version and deps --- gleam.toml | 10 +++++----- manifest.toml | 13 +++++++------ src/dot_env.gleam | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/gleam.toml b/gleam.toml index 5dedfd4..4a90d56 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,5 +1,5 @@ name = "dot_env" -version = "0.5.1" +version = "1.0.0" description = "Load and use environment variables from files" licences = ["Apache-2.0"] @@ -7,11 +7,11 @@ repository = { type = "github", user = "aosasona", repo = "dotenv" } internal_modules = ["dot_env/internal/*"] -gleam = ">= 0.34.0" +gleam = ">= 1.0.0" [dependencies] -simplifile = "~> 1.5" -gleam_stdlib = "~> 0.34 or ~> 1.0" +simplifile = ">= 2.0.0 and < 3.0.0" +gleam_stdlib = ">= 0.38.0 and < 1.0.0" [dev-dependencies] -gleeunit = "~> 1.0" +gleeunit = ">= 1.1.2 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index 06a746a..06a8890 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,12 +2,13 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, - { name = "simplifile", version = "1.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "EB9AA8E65E5C1E3E0FDCFC81BC363FD433CB122D7D062750FFDF24DE4AC40116" }, + { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "gleam_stdlib", version = "0.38.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "663CF11861179AF415A625307447775C09404E752FF99A24E2057C835319F1BE" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, + { name = "simplifile", version = "2.0.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "95219227A43FCFE62C6E494F413A1D56FF953B68FE420698612E3D89A1EFE029" }, ] [requirements] -gleam_stdlib = { version = "~> 0.34 or ~> 1.0" } -gleeunit = { version = "~> 1.0"} -simplifile = { version = "~> 1.5" } +gleam_stdlib = { version = ">= 0.38.0 and < 1.0.0"} +gleeunit = { version = ">= 1.1.2 and < 2.0.0" } +simplifile = { version = ">= 2.0.0 and < 3.0.0" } diff --git a/src/dot_env.gleam b/src/dot_env.gleam index 8cd6b3f..9456c9c 100644 --- a/src/dot_env.gleam +++ b/src/dot_env.gleam @@ -188,7 +188,7 @@ fn recursively_set_environment_variables( fn read_file(dotenv: DotEnv) -> Result(String, String) { use is_file <- result.try( - simplifile.verify_is_file(dotenv.path) + simplifile.is_file(dotenv.path) |> result.map_error(with: fn(_) { "Failed to access file, ensure the file exists and is a readable file" }), From b9a23859fa2a43fbaa0a3724dddeb46ca066b6a2 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:42:53 +0100 Subject: [PATCH 11/12] Formatting updates --- src/dot_env/internal/parser.gleam | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/dot_env/internal/parser.gleam b/src/dot_env/internal/parser.gleam index fa8cf94..391f204 100644 --- a/src/dot_env/internal/parser.gleam +++ b/src/dot_env/internal/parser.gleam @@ -12,9 +12,7 @@ type Chars = List(String) pub fn parse(text: String) -> Result(KVPairs, String) { - text - |> string.to_graphemes - |> parse_kvs([]) + text |> string.to_graphemes |> parse_kvs([]) } fn parse_kvs(text: Chars, acc: KVPairs) -> Result(KVPairs, String) { @@ -117,8 +115,5 @@ fn parse_comment(text: Chars, next: fn(Chars) -> a) -> a { } fn join(strings: List(String)) -> String { - strings - |> list.reverse - |> string.join("") + strings |> list.reverse |> string.join("") } - From 363ff875fdad26b02485e79781983d8dcad7c4f3 Mon Sep 17 00:00:00 2001 From: Ayodeji O <97124713+aosasona@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:44:27 +0100 Subject: [PATCH 12/12] Bumped CI deps --- .github/workflows/publish.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2f923c4..7f67134 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,6 +13,6 @@ jobs: - uses: erlef/setup-beam@v1 with: otp-version: "26.0.2" - gleam-version: "1.0.0" + gleam-version: "1.2.1" rebar3-version: "3" - run: gleam publish --yes diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15bba36..d298938 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: - uses: erlef/setup-beam@v1 with: otp-version: "26.0.2" - gleam-version: "1.0.0" + gleam-version: "1.2.1" rebar3-version: "3" - run: gleam format --check src test - run: gleam deps download