Skip to content

Instantly share code, notes, and snippets.

@thiamsantos
Last active March 10, 2020 14:59
Show Gist options
  • Save thiamsantos/16c15c394995c72b98ce1919da5aafbc to your computer and use it in GitHub Desktop.
Save thiamsantos/16c15c394995c72b98ce1919da5aafbc to your computer and use it in GitHub Desktop.

Usage

Just eval the file right in the beginning of each config.exs file. It will load the env of the .env files every time the project is compiled.

Umbrella

__ENV__.file()
|> Path.dirname()
|> Path.join("../../../config/dotenv.exs")
|> Path.expand()
|> Code.eval_file()

Non-umbrella

# config/config.exs
import Config

Code.eval_file("./config/dotenv.exs")

What other .env* files can I use?

The dotenv will override the env vars in the following order (highest defined variable overrides lower):

Hierarchy Priority Filename Environment Should I .gitignoreit? Notes
1st (highest) .env.$ENV.local dev/test/prod Yes! Local overrides of environment-specific settings.
2nd .env.$ENV dev/test/prod No. Overrides of environment-specific settings.
3rd .env.local All Environments Yes! Local overrides
Last .env All Environments No. The Original®
unless Code.ensure_compiled?(Dotenv) do
defmodule Dotenv do
@key_value_delimeter "="
def auto_load do
unless ci_environment?() do
current_env()
|> filenames()
|> Enum.map(&absolute_path/1)
|> Enum.filter(&File.exists?/1)
|> Enum.flat_map(&get_pairs/1)
|> load_env()
end
end
defp filenames(current_env) do
[".env", ".env.local", ".env.#{current_env}", ".env.local.#{current_env}"]
end
defp current_env do
Mix.env()
|> to_string()
|> String.downcase()
end
defp ci_environment? do
System.get_env("CI") != nil
end
defp absolute_path(filename) do
__ENV__.file()
|> Path.dirname()
|> Path.join("..")
|> Path.join(filename)
|> Path.expand()
end
defp get_pairs(filename) do
filename
|> File.read!()
|> String.split("\n")
|> Enum.reject(&blank_entry?/1)
|> Enum.reject(&comment_entry?/1)
|> Enum.map(&parse_line/1)
end
defp parse_line(line) do
[key, value] =
line
|> String.trim()
|> String.split(@key_value_delimeter, parts: 2)
{key, parse_value(value)}
end
defp parse_value(value) do
if String.starts_with?(value, "\"") do
unquote_string(value)
else
value |> String.split("#", parts: 2) |> List.first()
end
end
defp unquote_string(value) do
value
|> String.split(~r{(?<!\\)"}, parts: 3)
|> Enum.drop(1)
|> List.first()
|> String.replace(~r{\\"}, ~S("))
end
defp load_env(pairs) when is_list(pairs) do
pairs
|> Enum.filter(fn {key, _value} -> is_nil(System.get_env(key)) end)
|> Enum.each(fn {key, value} ->
System.put_env(String.upcase(key), value)
end)
end
defp blank_entry?(string) do
string == ""
end
defp comment_entry?(string) do
String.match?(string, ~r(^\s*#))
end
end
Dotenv.auto_load()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment