A Config.Provider that loads a CASC file via Cooper.load_file/2
and merges it into the release's app config at boot -- the same slot
Config.Reader (config/runtime.exs) normally fills.
Usage
Point a release at it in mix.exs:
def project do
[
...,
releases: releases()
]
end
defp releases do
[
my_app: [
config_providers: [
{CooperConfig.Provider, path: "/etc/my_app/config.casc"}
]
]
]
end:path accepts anything Config.Provider.resolve_config_path!/1
does -- a literal string, {:system, "ENV_VAR"}, or {:system, "ENV_VAR", "/default/path"} -- so the path itself can come from the
environment.
Options
Besides :path (required), every other option is passed straight
through to Cooper.load_file/2 -- see its moduledoc for what each
one does:
:env-- an override layer, not a replacement:System.get_env/0(and any.envfile, see:dotenvbelow) is always consulted too, for any name not given an explicit entry here. Defaults toCooper.load_file/2's own default (nothing extra layered on top ofSystem.get_env/0/.env) if omitted.:resolvers,:tags,:import_schemes-- default to%{}.:dotenv,:dotenv_env,:dotenv_files--.envfile layering, on by default; seeCooper.Dotenvfor the full rules. Omitted here means Cooper's own default applies.
:cache/:watch_env are deliberately not exposed -- load/2
always calls Cooper.load_file/2 with cache: false. Config.Provider
callbacks run before the release's own supervision tree starts, which
is also what starts :cooper's OTP application and, with it, the
Cooper.Cache process the cache relies on -- caching here wouldn't
just be pointless for a file read exactly once per boot, it would
crash trying to reach a cache process that isn't running yet.
Plus one option of its own:
:reveal_secrets-- passed toCooperConfig.Convert.to_app_config/2, see its moduledoc for the tradeoff. Defaults totrue.
Errors
A load failure (unreadable file, parse/resolve error, ...) raises --
Config.Provider callbacks run before the release's supervision tree
starts, so there's no supervisor to catch and restart from, and
booting further with incomplete config is worse than not booting.
Summary
Functions
Validates opts and builds the state load/2 receives.
Loads the CASC file described by state (as built by init/1) and
merges it into config via Config.Reader.merge/2.
Types
@type opts() :: [ path: Config.Provider.config_path(), env: %{optional(String.t()) => String.t()}, resolvers: %{ optional(String.t()) => (String.t() -> {:ok, term()} | {:error, term()}) }, tags: %{optional(String.t()) => (term() -> {:ok, term()} | {:error, term()})}, import_schemes: %{ optional(String.t()) => (String.t() -> {:ok, String.t()} | {:error, term()}) }, dotenv: boolean(), dotenv_env: atom() | nil, dotenv_files: [String.t()], reveal_secrets: boolean() ]
Functions
Validates opts and builds the state load/2 receives.
Raises if :path is missing or fails
Config.Provider.validate_config_path!/1.
Loads the CASC file described by state (as built by init/1) and
merges it into config via Config.Reader.merge/2.
Raises if the file can't be read, parsed, or resolved -- see the moduledoc's "Errors" section.