Skogsra
The Skogsrå was a mythical creature of the forest that appears in the form of a small, beautiful woman with a seemingly friendly temperament. However, those who are enticed into following her into the forest are never seen again.
This library attempts to improve the use of OS environment variables for application configuration:
- Automatic type casting of values.
- Configuration options documentation.
- Variables defaults.
Small Example
You would create a settings module e.g:
defmodule MyApp.Settings do
use Skogsra
app_env :my_hostname, :myapp, :hostname,
default: "localhost"
end
Calling MyApp.Settings.my_hostname() will retrieve the value for the
hostname in the following order:
-
From the OS environment variable
$MYAPP_HOSTNAME. -
From the configuration file e.g:
config :myapp, hostname: "my.custom.host" -
From the default value if it exists (In this case, it would return
"localhost").
Handling different environments
If it's necessary to keep several environments, it's possible to use a
namespace e.g:
Calling MyApp.Settings.my_hostname(Test) will retrieve the value for the
hostname in the following order:
-
From the OS environment variable
$TEST_MYAPP_HOSTNAME. -
From the configuration file e.g:
config :myapp, Test, hostname: "my.custom.test.host" - From the default value if it exists.
Required variables
It is possible to set a environment variable as required with the required
option e.g:
defmodule MyApp.Settings do
use Skogsra
app_env :my_hostname, :myapp, :port,
required: true
end
If the variable $MYAPP_PORT is undefined and the configuration is missing,
calling to MyApp.Settings.my_hostname() will return an error tuple. Calling
$MyApp.Settings.my_hostname!() (with the bang) will raise a runtime
exception.
Automatic casting
If the default value is set, the OS environment variable value will be casted
as the same type of the default value. Otherwise, it is possible to set the
type for the variable with the option type. The available types are
:binary (default), :integer, :float, :boolean and :atom.
Additionally, you can create a function to cast the value and specify it as
{module_name, function_name} e.g:
defmodule MyApp.Settings do
use Skogsra
app_env :my_channels, :myapp, :channels,
type: {__MODULE__, channels},
required: true
def channels(value), do: String.split(value, ", ")
end
If $MYAPP_CHANNELS's value is "ch0, ch1, ch2" then the casted value
will be ["ch0", "ch1", "ch2"].
Configuration definitions
Calling MyApp.Settings.my_hostname(nil, :system) will print the expected OS
environment variable name and MyApp.Settings.my_hostname(nil, :config) will
print the expected Mix configuration. If the namespace is necessary, pass
it as first parameter.
Reloading
For debugging purposes is possible to reload variables at runtime with
MyApp.Settings.my_hostname(nil, :reload).
Recommended Usage
The recommended way of using this project is to define a .env file in the
root of your project with the variables that you want to define e.g:
export MYSERVICE_PORT=1234
and then when sourceing the file right before you execute your application.
In bash (or zsh) would be like this:
$ source .env
The previous step can be automated by adding the following code to your
~/.bashrc (or ~/.zshrc):
#################
# BEGIN: Auto env
export LAST_ENV=
function auto_env_on_chpwd() {
env_type="$1"
env_file="$PWD/.env"
if [ -n "$env_type" ]
then
env_file="$PWD/.env.$env_type"
if [ ! -r "$env_file" ]
then
echo -e "\e[33mFile $env_file does not exist.\e[0m"
env_file="$PWD/.env"
fi
fi
if [ -n "$LAST_ENV" ] && [ -r "$LAST_ENV" ]
then
UNSET=$(
cat $LAST_ENV |
sed -e 's/^export \([0-9a-zA-Z\_]*\)=.*$/unset \1/'
)
source <(echo "$UNSET")
echo -e "\e[33mUnloaded ENV VARS defined in \"$LAST_ENV\"\e[0m"
export LAST_ENV=
fi
if [ -r "$env_file" ]
then
export LAST_ENV="$env_file"
source $LAST_ENV
echo -e "\e[32mLoaded \"$LAST_ENV\"\e[0m"
fi
}
chpwd_functions=(${chpwd_functions[@]} "auto_env_on_chpwd")
if [ -n "$TMUX" ]
then
auto_env_on_chpwd
fi
alias change_to='function _change_to() {auto_env_on_chpwd $1}; _change_to'
# END: Auto env
###############
The previous code will attempt to source any .env file every time you
change directory e.g:
/home/alex $ cd my_app
Loaded "/home/alex/my_app/.env"
/home/alex/my_app $ echo "$MYSERVICE_PORT"
1234
Additionally, the command change_to <ENV> is included. To keep your prod,
dev and test environment variables separated, just create a
.env.${MIX_ENV} in the root directory of your project. And when you want to
use the variables set in one of those files, just run the following:
$ change_to dev # Will use `.env.dev` instead of `.env`Installation
The package can be installed by adding skogsra to your list of dependencies
in mix.exs:
def deps do
[{:skogsra, "~> 1.0"}]
endAuthor
Alexander de Sousa.
License
Skogsra is released under the MIT License. See the LICENSE file for further
details.