-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
loadconfig.ex
113 lines (86 loc) · 3.13 KB
/
loadconfig.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
defmodule Mix.Tasks.Loadconfig do
use Mix.Task
@shortdoc "Loads and persists the given configuration"
@moduledoc """
Loads and persists the given configuration.
$ mix loadconfig path/to/config.exs
Any configuration file loaded with `loadconfig` is treated
as a compile-time configuration.
Note that "config/config.exs" is always loaded automatically
by the Mix CLI when it boots. "config/runtime.exs" is loaded
automatically by `mix app.config` before starting the current
application. Therefore there is no need to load those config
files directly.
This task is automatically re-enabled, so it can be called
multiple times to load different configs.
"""
@reserved_apps [:stdlib, :kernel]
@impl true
def run(args) do
Mix.Task.reenable("loadconfig")
case args do
[] -> load_default()
[file] -> load_compile(file)
end
end
defp load_default do
config = Mix.Project.config()
if File.regular?(config[:config_path]) or config[:config_path] != "config/config.exs" do
load_compile(config[:config_path])
else
[]
end
end
@doc false
def read_compile() do
Mix.State.read_cache(__MODULE__) || []
end
@doc false
# Loads compile-time configuration, they support imports, and are not deep merged.
def load_compile(file) do
{config, files} = Config.Reader.read_imports!(file, env: Mix.env(), target: Mix.target())
Mix.ProjectStack.loaded_config(persist_apps(config, file), files)
Mix.State.write_cache(__MODULE__, config)
end
@doc false
# Loads runtime configuration, they do not support imports, and are deep merged.
def load_runtime(file) do
config = Config.Reader.read!(file, env: Mix.env(), target: Mix.target(), imports: :disabled)
Mix.ProjectStack.loaded_config(persist_apps(hydrate_apps(config), file), [])
config
end
defp hydrate_apps(config) do
for {app, pairs} <- config do
hd(Config.Reader.merge([{app, Application.get_all_env(app)}], [{app, pairs}]))
end
end
defp persist_apps(config, file) do
Application.put_all_env(config, persistent: true)
apps = Keyword.keys(config)
case Enum.filter(@reserved_apps, &(&1 in apps)) do
[] ->
:ok
reserved_apps ->
Mix.shell().error("""
Cannot configure base applications: #{inspect(reserved_apps)}
These applications are already started by the time the configuration
executes and these configurations have no effect.
If you want to configure these applications for a release, you can
specify them in your vm.args file:
-kernel config_key config_value
Alternatively, if you must configure them dynamically, you can wrap
them in a conditional block in your config files:
if System.get_env("RELEASE_MODE") do
config :kernel, ...
end
and then configure your releases to reboot after configuration:
releases: [
my_app: [reboot_system_after_config: true]
]
This happened when loading #{Path.relative_to_cwd(file)} or
one of its imports.
""")
end
apps
end
end