223 lines
5.4 KiB
Elixir
223 lines
5.4 KiB
Elixir
defmodule Envar do
|
|
@moduledoc """
|
|
Docs for `Envar`; Environment Variable checker/getter.
|
|
Variable names are logged to improve developer experience.
|
|
The _values_ of Environment Variables should _never_ be logged here.
|
|
If an App needs to debug a variable, it can log it locally.
|
|
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@doc """
|
|
`get/2` gets an environment variable by name
|
|
with an _optional_ second argument `default_value`
|
|
which, as it's name suggests, defines the default value
|
|
for the evironment variable if it is not set.
|
|
|
|
## Examples
|
|
|
|
iex> System.put_env("HELLO", "world")
|
|
iex> Envar.get("HELLO")
|
|
"world"
|
|
|
|
iex> Envar.get("FOO", "bar")
|
|
"bar"
|
|
"""
|
|
@spec get(binary, binary | nil) :: binary | nil
|
|
def get(varname, default \\ nil) do
|
|
val = System.get_env(varname, default)
|
|
|
|
if is_nil(val) do
|
|
Logger.error("ERROR: #{varname} Environment Variable is not set")
|
|
end
|
|
|
|
val
|
|
end
|
|
|
|
@doc """
|
|
`is_set/1` binary check that an environment variable is defined by name
|
|
e.g: `Envar.is_set?("HEROKU")` will return `false`
|
|
if the `HEROKU` environment variable is not set.
|
|
When a particular variable is set, it will return `true`.
|
|
|
|
## Examples
|
|
iex> Envar.is_set?("HEROKU")
|
|
false
|
|
|
|
iex> System.put_env("HELLO", "world")
|
|
iex> Envar.is_set?("HELLO")
|
|
true
|
|
|
|
"""
|
|
@spec is_set?(binary) :: boolean
|
|
def is_set?(varname) do
|
|
case System.get_env(varname) do
|
|
nil ->
|
|
Logger.debug("#{varname} Environment Variable is not set")
|
|
false
|
|
|
|
_ ->
|
|
true
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
`is_set_all/1` binary check that ***ALL***
|
|
environment variable in a `List` are defined.
|
|
e.g: `Envar.is_set_all?(~w/HEROKU FLYIO/)` will return `false`
|
|
if _both_ the `HEROKU` and `FLYIO` environment variables are _not_ set.
|
|
When _all_ of the environment variables in the list are set,
|
|
it will return `true`.
|
|
It's the equivalent of writing:
|
|
`Envar.is_set?("HEROKU") && Envar.is_set?("FLYIO")`.
|
|
|
|
## Examples
|
|
iex> Envar.is_set_all?(["HEROKU", "AWS"])
|
|
false
|
|
|
|
iex> Envar.set("HELLO", "world")
|
|
iex> Envar.set("GOODBYE", "au revoir")
|
|
iex> Envar.is_set_all?(["HELLO", "GOODBYE"])
|
|
true
|
|
|
|
"""
|
|
@spec is_set_all?(list) :: boolean
|
|
def is_set_all?(list) do
|
|
Enum.all?(list, fn var -> is_set?(var) end)
|
|
end
|
|
|
|
@doc """
|
|
`is_set_any/1` binary check that any
|
|
environment variable in a `List` is defined.
|
|
e.g: `Envar.is_set_any?(["HEROKU", "FLYIO"])` will return `false`
|
|
if _both_ the `HEROKU` and `FLYIO` environment variables are _not_ set.
|
|
When any of the environment variables in the list are set,
|
|
it will return `true`.
|
|
It's the equivalent of writing:
|
|
`Envar.is_set?("HEROKU") || Envar.is_set?("FLYIO")`.
|
|
|
|
## Examples
|
|
iex> Envar.is_set_any?(["HEROKU", "AWS"])
|
|
false
|
|
|
|
iex> System.put_env("HELLO", "world")
|
|
iex> Envar.is_set_any?(["HELLO", "GOODBYE"])
|
|
true
|
|
|
|
"""
|
|
@spec is_set_any?(list) :: boolean
|
|
def is_set_any?(list) do
|
|
Enum.any?(list, fn var -> is_set?(var) end)
|
|
end
|
|
|
|
@doc """
|
|
`set/2` set the `value` of an environment variable `varname`.
|
|
Accepts two `String` parameters: `varname` and `value`.
|
|
|
|
## Examples
|
|
iex> Envar.set("API_KEY", "YourSuperLongAPIKey")
|
|
:ok
|
|
|
|
"""
|
|
@spec set(binary, binary) :: :ok
|
|
def set(varname, value) do
|
|
System.put_env(varname, value)
|
|
end
|
|
|
|
@doc """
|
|
`load/1` load a file containing a line-separated list
|
|
of environment variables e.g: `.env`
|
|
Set the `value` of each environment variable.
|
|
|
|
## Examples
|
|
iex> Envar.load(".env")
|
|
:ok
|
|
|
|
"""
|
|
@spec load(binary) :: :ok
|
|
def load(filename) do
|
|
read(filename) |> Enum.each(fn {k, v} -> set(k, v) end)
|
|
|
|
:ok
|
|
end
|
|
|
|
@doc """
|
|
`require_env_file/1` load a file containing a line-separated list
|
|
of environment variables e.g: `.env`
|
|
Set the `value` of each environment variable.
|
|
Log an Error if the file is not available
|
|
|
|
## Examples
|
|
iex> Envar.require_env_file(".env")
|
|
:ok
|
|
|
|
iex> Envar.require_env_file(".env_not_there")
|
|
:error
|
|
|
|
"""
|
|
@spec require_env_file(binary) :: :ok
|
|
def require_env_file(filename) do
|
|
# check if the file exists:
|
|
path = Path.join(File.cwd!(), filename)
|
|
case File.exists?(path) do
|
|
true ->
|
|
load(filename)
|
|
false ->
|
|
Logger.error("Required .env file does not exist at path: #{path}")
|
|
:error
|
|
end
|
|
end
|
|
|
|
|
|
@spec keys(binary) :: list
|
|
def keys(filename) do
|
|
read(filename) |> Map.keys()
|
|
end
|
|
|
|
@spec values(binary) :: list
|
|
def values(filename) do
|
|
read(filename) |> Map.values()
|
|
end
|
|
|
|
@doc """
|
|
`read/1` reads a file containing a line-separated list
|
|
of environment variables e.g: `.env`
|
|
Returns a Map in the form %{ KEY: value, MYVAR: value2 }
|
|
|
|
## Examples
|
|
iex> Envar.read(".env")
|
|
%{
|
|
"ADMIN_EMAIL" => "alex@gmail.com",
|
|
"EVERYTHING" => "awesome!",
|
|
"SECRET" => "master plan"
|
|
}
|
|
|
|
"""
|
|
@spec read(binary) :: map
|
|
def read(filename) do
|
|
path = Path.join(File.cwd!(), filename)
|
|
|
|
Logger.debug(".env file path: #{path}")
|
|
|
|
data = File.read!(path)
|
|
|
|
data
|
|
|> String.trim()
|
|
|> String.split("\n")
|
|
|> Enum.reduce(%{}, fn line, acc ->
|
|
line = String.trim(line)
|
|
|
|
with line <- String.replace(line, ["export ", "'"], ""),
|
|
[key | rest] <- String.split(line, "="),
|
|
value <- Enum.join(rest, "=") do
|
|
if String.length(value) > 0 do
|
|
Map.put(acc, key, value)
|
|
else
|
|
acc
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
end
|