An app's configuration, from the literal config.exs on its data volume.
Each setting resolves as env var > config.exs > default. An app
declares its settings once, as {name, type, default}
(Macaw.Host.Config.Types), and loads them at boot:
@settings [
{:public_host, :string, "localhost"},
{:port, :port, 4000},
{:smtp_password, :secret, nil}
]
Macaw.Host.Config.load!(:my_app, @settings,
path: "/data/config.exs", env_prefix: "MY_APP")
Macaw.Host.Config.get(:my_app, :port)MY_APP_PORT wins over port in the file, which wins over 4000. Every
invalid value and every unknown key in the file fails the load at
once, each named with where it came from, so a broken boot says
everything that is wrong in one message. The resolved values, with each
one's source, are kept in :persistent_term and read without copying.
put!/4 and delete!/3 edit the file for the <app>-ctl config command:
the value is parsed as a literal, checked against the setting's type, and
the file is written atomically; nothing is evaluated.
Summary
Functions
Removes name from the file, so it falls back to its env var or default.
The env var a setting is read from: PREFIX_NAME.
A loaded setting's value. Raises for a name the app didn't declare.
The settings' names, in declared order.
Reads the file and the environment, resolves, and stores the result under
app. Options: :path (the file), :env_prefix, :env (default
System.get_env/0). Raises ArgumentError listing every fault.
A value as shown; anything but a secret is inspected. A secret is
unset when nil or empty, set (…last4) when it is at least 16
characters long (so at most a quarter of it shows), else set. The
generated script's Ctl.Secret.mask/1 follows the same rule.
Sets name in the file at path to the literal text, after checking it
against the setting's type. {:ok, value} or {:error, why}; the file is
untouched on error.
The file at path as a map, never raising: {:ok, map} (%{} when it
doesn't exist) or {:error, message}, every fault on one line, for the
ctl, whose failure is one line.
Resolves settings from an env map, a file map and the env var prefix.
Pure: {:ok, resolved} or {:error, faults}.
Resolves one setting as resolve/4 does, env var > file > default, the
file's key an atom or a string: {:ok, %{value, source}}, or
{:error, %{raw, source, fault}} with the value as found (the env var's
string, the file's literal) and the fault as resolve/4 words it.
resolve/4 is built on it, and so is <app>-ctl config list, so the
two never disagree.
Every loaded setting as {name, shown value, source}, secrets masked.
Where a loaded setting's value came from: :env, :file or :default.
Types
Functions
Removes name from the file, so it falls back to its env var or default.
The env var a setting is read from: PREFIX_NAME.
A loaded setting's value. Raises for a name the app didn't declare.
The settings' names, in declared order.
Reads the file and the environment, resolves, and stores the result under
app. Options: :path (the file), :env_prefix, :env (default
System.get_env/0). Raises ArgumentError listing every fault.
@spec mask(Macaw.Host.Config.Types.t(), term()) :: String.t()
A value as shown; anything but a secret is inspected. A secret is
unset when nil or empty, set (…last4) when it is at least 16
characters long (so at most a quarter of it shows), else set. The
generated script's Ctl.Secret.mask/1 follows the same rule.
Sets name in the file at path to the literal text, after checking it
against the setting's type. {:ok, value} or {:error, why}; the file is
untouched on error.
The file at path as a map, never raising: {:ok, map} (%{} when it
doesn't exist) or {:error, message}, every fault on one line, for the
ctl, whose failure is one line.
@spec resolve([spec()], %{required(String.t()) => String.t()}, map(), String.t()) :: {:ok, resolved()} | {:error, [String.t()]}
Resolves settings from an env map, a file map and the env var prefix.
Pure: {:ok, resolved} or {:error, faults}.
@spec resolve_setting( spec(), %{required(String.t()) => String.t()}, map(), String.t() ) :: {:ok, %{value: term(), source: source()}} | {:error, %{raw: term(), source: source(), fault: String.t()}}
Resolves one setting as resolve/4 does, env var > file > default, the
file's key an atom or a string: {:ok, %{value, source}}, or
{:error, %{raw, source, fault}} with the value as found (the env var's
string, the file's literal) and the fault as resolve/4 words it.
resolve/4 is built on it, and so is <app>-ctl config list, so the
two never disagree.
Every loaded setting as {name, shown value, source}, secrets masked.
Where a loaded setting's value came from: :env, :file or :default.