aboutsummaryrefslogtreecommitdiff
path: root/lib/ejabberd/config/validator
diff options
context:
space:
mode:
authorgabrielgatu <gabriel.dny@gmail.com>2016-09-08 11:34:42 +0200
committerMickael Remond <mremond@process-one.net>2016-09-08 11:37:14 +0200
commit803270fc6b8ed3ba718f7e231b149caef70aa1ae (patch)
treecc4508758cbcec7a74568834888f3208d876a953 /lib/ejabberd/config/validator
parentSupport for publishing to hex.pm with latest Elixir mix (diff)
Support for Elixir configuration file #1208
Contribution for Google Summer of code 2016 by Gabriel Gatu
Diffstat (limited to 'lib/ejabberd/config/validator')
-rw-r--r--lib/ejabberd/config/validator/validation.ex40
-rw-r--r--lib/ejabberd/config/validator/validator_attrs.ex28
-rw-r--r--lib/ejabberd/config/validator/validator_dependencies.ex30
-rw-r--r--lib/ejabberd/config/validator/validator_utility.ex30
4 files changed, 128 insertions, 0 deletions
diff --git a/lib/ejabberd/config/validator/validation.ex b/lib/ejabberd/config/validator/validation.ex
new file mode 100644
index 000000000..2fe00361a
--- /dev/null
+++ b/lib/ejabberd/config/validator/validation.ex
@@ -0,0 +1,40 @@
+defmodule Ejabberd.Config.Validation do
+ @moduledoc """
+ Module used to validate a list of modules.
+ """
+
+ @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
+ @type mod_validation_result :: {:ok, EjabberdModule.t} | {:error, EjabberdModule.t, map}
+
+ alias Ejabberd.Config.EjabberdModule
+ alias Ejabberd.Config.Attr
+ alias Ejabberd.Config.Validator
+ alias Ejabberd.Config.ValidatorUtility
+
+ @doc """
+ Given a module or a list of modules it runs validators on them
+ and returns {:ok, mod} or {:error, mod, errors}, for each
+ of them.
+ """
+ @spec validate([EjabberdModule.t] | EjabberdModule.t) :: [mod_validation_result]
+ def validate(modules) when is_list(modules), do: Enum.map(modules, &do_validate(modules, &1))
+ def validate(module), do: validate([module])
+
+ # Private API
+
+ @spec do_validate([EjabberdModule.t], EjabberdModule.t) :: mod_validation_result
+ defp do_validate(modules, mod) do
+ {modules, mod, %{}}
+ |> Validator.Attrs.validate
+ |> Validator.Dependencies.validate
+ |> resolve_validation_result
+ end
+
+ @spec resolve_validation_result(mod_validation) :: mod_validation_result
+ defp resolve_validation_result({_modules, mod, errors}) do
+ case errors do
+ err when err == %{} -> {:ok, mod}
+ err -> {:error, mod, err}
+ end
+ end
+end
diff --git a/lib/ejabberd/config/validator/validator_attrs.ex b/lib/ejabberd/config/validator/validator_attrs.ex
new file mode 100644
index 000000000..94117ab21
--- /dev/null
+++ b/lib/ejabberd/config/validator/validator_attrs.ex
@@ -0,0 +1,28 @@
+defmodule Ejabberd.Config.Validator.Attrs do
+ @moduledoc """
+ Validator module used to validate attributes.
+ """
+
+ # TODO: Duplicated from validator.ex !!!
+ @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
+
+ import Ejabberd.Config.ValidatorUtility
+ alias Ejabberd.Config.Attr
+
+ @doc """
+ Given a module (with the form used for validation)
+ it runs Attr.validate/1 on each attribute and
+ returns the validation tuple with the errors updated, if found.
+ """
+ @spec validate(mod_validation) :: mod_validation
+ def validate({modules, mod, errors}) do
+ errors = Enum.reduce mod.attrs, errors, fn(attr, err) ->
+ case Attr.validate(attr) do
+ {:ok, attr} -> err
+ {:error, attr, cause} -> put_error(err, :attribute, {attr, cause})
+ end
+ end
+
+ {modules, mod, errors}
+ end
+end
diff --git a/lib/ejabberd/config/validator/validator_dependencies.ex b/lib/ejabberd/config/validator/validator_dependencies.ex
new file mode 100644
index 000000000..d44c8a136
--- /dev/null
+++ b/lib/ejabberd/config/validator/validator_dependencies.ex
@@ -0,0 +1,30 @@
+defmodule Ejabberd.Config.Validator.Dependencies do
+ @moduledoc """
+ Validator module used to validate dependencies specified
+ with the @dependency annotation.
+ """
+
+ # TODO: Duplicated from validator.ex !!!
+ @type mod_validation :: {[EjabberdModule.t], EjabberdModule.t, map}
+ import Ejabberd.Config.ValidatorUtility
+
+ @doc """
+ Given a module (with the form used for validation)
+ it checks if the @dependency annotation is respected and
+ returns the validation tuple with the errors updated, if found.
+ """
+ @spec validate(mod_validation) :: mod_validation
+ def validate({modules, mod, errors}) do
+ module_names = extract_module_names(modules)
+ dependencies = mod.attrs[:dependency]
+
+ errors = Enum.reduce dependencies, errors, fn(req_module, err) ->
+ case req_module in module_names do
+ true -> err
+ false -> put_error(err, :dependency, {req_module, :not_found})
+ end
+ end
+
+ {modules, mod, errors}
+ end
+end
diff --git a/lib/ejabberd/config/validator/validator_utility.ex b/lib/ejabberd/config/validator/validator_utility.ex
new file mode 100644
index 000000000..17805f748
--- /dev/null
+++ b/lib/ejabberd/config/validator/validator_utility.ex
@@ -0,0 +1,30 @@
+defmodule Ejabberd.Config.ValidatorUtility do
+ @moduledoc """
+ Module used as a base validator for validation modules.
+ Imports utility functions for working with validation structures.
+ """
+
+ alias Ejabberd.Config.EjabberdModule
+
+ @doc """
+ Inserts an error inside the errors collection, for the given key.
+ If the key doesn't exists then it creates an empty collection
+ and inserts the value passed.
+ """
+ @spec put_error(map, atom, any) :: map
+ def put_error(errors, key, val) do
+ Map.update errors, key, [val], fn coll ->
+ [val | coll]
+ end
+ end
+
+ @doc """
+ Given a list of modules it extracts and returns a list
+ of the module names (which are Elixir.Module).
+ """
+ @spec extract_module_names(EjabberdModule.t) :: [atom]
+ def extract_module_names(modules) when is_list(modules) do
+ modules
+ |> Enum.map(&Map.get(&1, :module))
+ end
+end