Current section
Files
Jump to
Current section
Files
lib/ex_env.ex
defmodule ExEnv do
@moduledoc """
Tool provides support of Elixir terms in system env variables.
For security reasons only literals/terms are allowed in configs (no functions, macros, modules etc).
"""
defmacro __using__([]) do
quote do
import Config
require ExEnv
Mix.Project.config()[:deps]
|> Enum.each(fn dependency ->
ExEnv.config(elem(dependency, 0))
end)
ExEnv.config(Mix.Project.config()[:app])
ExEnv.config(:logger)
end
end
@doc """
Works as Mix.Config.Config macro.
Gets single argument, name of otp_app (atom).
Infers config system variable name from otp_app argument:
capitalize name and adds _CONFIG postfix.
## Example
```
# reads, validates and evaluates BEST_APP_CONFIG system variable
ExEnv.config(:best_app)
```
"""
defmacro config(otp_app_ast) do
quote do
otp_app = unquote(otp_app_ast)
unless is_atom(otp_app) do
"otp_app should be Erlang atom type, but got #{inspect(otp_app)}"
|> raise
end
ExEnv.config(otp_app, "#{otp_app |> Atom.to_string() |> String.upcase()}_CONFIG")
end
end
@doc """
Works as &ExEnv.config/1 macro, but
second argument is explicit system variable name.
## Example
```
# reads, validates and evaluates MY_FAVORITE_APP_DATA system variable
ExEnv.config(:best_app, "MY_FAVORITE_APP_DATA")
```
"""
defmacro config(otp_app_ast, os_var_name_ast) do
quote do
otp_app = unquote(otp_app_ast)
os_var_name = unquote(os_var_name_ast)
unless is_atom(otp_app) do
"otp_app should be Erlang atom type, but got #{inspect(otp_app)}"
|> raise
end
unless String.valid?(os_var_name) do
"os_var_name should be string, but got #{os_var_name}"
|> raise
end
:ok = ExEnv.Utils.validate_otp_app(otp_app)
os_var_name
|> System.get_env()
|> case do
nil ->
:ok
config_string when is_binary(config_string) ->
config_string
|> Code.string_to_quoted()
|> case do
{:ok, config_ast} ->
:ok = ExEnv.Utils.validate_config_ast(config_ast)
{config_term, []} = Code.eval_quoted(config_ast)
config(otp_app, config_term)
{:error, error} ->
"application #{otp_app} got error #{inspect(error)} while parse AST of #{config_string}"
|> raise
end
end
end
end
end