defmodule Weave.Loaders.File do @moduledoc """ This loader will attempt to consume files located within a configured directory. The directory must be cofigured like one of the following: ```elixir loaders: [ {Weave.Loaders.File, directories: [ "/run/secrets" ]}, ] ``` With the above configuration, any files in the mentioned directories will be sent to the handler. Please note, the filenames will be "sanitized" before being sent to the handler. This means "/run/secrets/my_DB_password" will become "my_db_password" """ use Weave.Loader require Logger @spec load_configuration_from_directory(binary, atom, list | nil) :: list @spec load_file(binary, binary, atom) :: :ok @doc """ You shouldn't call this function youroself. Instead, use a Weave module. """ def load_configuration(options: [directories: directories], only: only, handler: handler) do Logger.debug(fn -> "Weave - Environment Loader: directories: #{inspect(directories)}, only: #{inspect(only)}, handler: #{ inspect(handler) }" end) Enum.reduce(directories, [], fn directory, acc -> acc ++ load_configuration_from_directory(directory, handler, only) end) end @doc """ Safety net to provide debug when people don't configure their loaders correctly """ def load_configuration(options: options, only: _, handler: _) do Logger.warn(fn -> "Weave File Loader called, but wasn't configured with `directories: [binary]`" end) Logger.debug(fn -> "options: #{inspect(options)}" end) [] end defp load_configuration_from_directory(directory, handler, accepted_filenames) when is_binary(directory) and is_atom(handler) do Logger.info(fn -> "Loading configuration from directory '#{directory}'" end) directory |> String.trim_trailing("/") |> File.ls!() |> Enum.filter(fn file -> !File.dir?("#{directory}/#{file}") end) |> filter_filenames(accepted_filenames) |> Enum.map(fn file -> Logger.info(fn -> "Found File: #{file}" end) load_file(directory, file, handler) sanitize(file) end) end defp load_file(file_directory, file_name, handler) do configuration = "#{file_directory}/#{file_name}" |> File.read!() |> String.trim() apply_configuration(file_name, configuration, handler) end defp filter_filenames(files, nil), do: files defp filter_filenames(files, accepted_filenames) when is_list(accepted_filenames) do # Allow variables names to be passed as string or atoms # by converting everything to strings here only = Enum.map(accepted_filenames, &sanitize/1) Enum.filter(files, fn file -> Logger.debug(fn -> "Checking if #{file} is within our only filter: #{file in only}" end) file in only end) end end