-
Notifications
You must be signed in to change notification settings - Fork 3.3k
/
reader.ex
87 lines (67 loc) · 2.5 KB
/
reader.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
defmodule Config.Reader do
@moduledoc """
API for reading config files defined with `Config`.
## As a provider
`Config.Reader` can also be used as a `Config.Provider`.
When used as a provider, it expects a single argument:
which the configuration path (as outlined in
`t:Config.Provider.config_path/0`) for the configuration
to be read and loaded during the system boot.
"""
@behaviour Config.Provider
@impl true
def init(path) do
Config.Provider.validate_config_path!(path)
path
end
@impl true
def load(config, path) do
merge(config, path |> Config.Provider.resolve_config_path!() |> read!())
end
@doc """
Reads the configuration file.
The same as `read_imports!/2` but only returns the configuration
in the given file, without returning the imported paths.
It exists for convenience purposes. For example, you could
invoke it inside your `mix.exs` to read some external data
you decided to move to a configuration file:
releases: Config.Reader.read!("rel/releases.exs")
"""
@doc since: "1.9.0"
@spec read!(Path.t(), [Path.t()]) :: keyword
def read!(file, imported_paths \\ [])
when is_binary(file) and is_list(imported_paths) do
Config.__eval__!(file, imported_paths) |> elem(0)
end
@doc """
Reads the given configuration file alongside its imports.
It accepts a list of `imported_paths` that should raise if attempted
to be imported again (to avoid recursive imports).
It returns a tuple with the configuration and the imported paths.
"""
@doc since: "1.9.0"
@spec read_imports!(Path.t(), [Path.t()]) :: {keyword, [Path.t()]}
def read_imports!(file, imported_paths \\ [])
when is_binary(file) and is_list(imported_paths) do
Config.__eval__!(file, imported_paths)
end
@doc """
Merges two configurations.
The configurations are merged together with the values in
the second one having higher preference than the first in
case of conflicts. In case both values are set to keyword
lists, it deep merges them.
## Examples
iex> Config.Reader.merge([app: [k: :v1]], [app: [k: :v2]])
[app: [k: :v2]]
iex> Config.Reader.merge([app: [k: [v1: 1, v2: 2]]], [app: [k: [v2: :a, v3: :b]]])
[app: [k: [v1: 1, v2: :a, v3: :b]]]
iex> Config.Reader.merge([app1: []], [app2: []])
[app1: [], app2: []]
"""
@doc since: "1.9.0"
@spec merge(keyword, keyword) :: keyword
def merge(config1, config2) when is_list(config1) and is_list(config2) do
Config.__merge__(config1, config2)
end
end