From ea8db9967fbfe53f581c3ae721657d9e6f919864 Mon Sep 17 00:00:00 2001 From: Mickael Remond Date: Sat, 4 Apr 2015 17:42:12 +0200 Subject: [PATCH] ejabberd can be embedded in an Elixir application --- .gitignore | 2 +- lib/mix/tasks/compile.asn1.ex | 53 +++++++++++++++++++++++++++++++++++ mix.exs | 44 +++++++++++++++++++++++++++++ src/ejabberd_config.erl | 19 +++++++++++-- 4 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 lib/mix/tasks/compile.asn1.ex create mode 100644 mix.exs diff --git a/.gitignore b/.gitignore index c72fcdc36..340a72203 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ /ebin/ /ejabberd.init /ejabberdctl.example -/include/XmppAddr.hrl +XmppAddr.hrl /rel/ejabberd/ /src/XmppAddr.asn1db /src/XmppAddr.erl diff --git a/lib/mix/tasks/compile.asn1.ex b/lib/mix/tasks/compile.asn1.ex new file mode 100644 index 000000000..e1af6046f --- /dev/null +++ b/lib/mix/tasks/compile.asn1.ex @@ -0,0 +1,53 @@ +defmodule Mix.Tasks.Compile.Asn1 do + use Mix.Task + alias Mix.Compilers.Erlang + + @recursive true + @manifest ".compile.asn1" + + @moduledoc """ + Compile ASN.1 source files. + When this task runs, it will check the modification time of every file, and + if it has changed, the file will be compiled. Files will be + compiled in the source directory with a .erl extension and generate a .hrl file. + You can force compilation regardless of modification times by passing + the `--force` option. + ## Command line options + * `--force` - forces compilation regardless of modification times + ## Configuration + * `:asn1_paths` - directories to find asn1 files. Defaults to `["asn1"]`. + """ + + @doc """ + Runs this task. + """ + @spec run(OptionParser.argv) :: :ok | :noop + def run(args) do + {opts, _, _} = OptionParser.parse(args, switches: [force: :boolean]) + + project = Mix.Project.config + source_paths = project[:asn1_paths] || ["asn1"] + dest_paths = project[:erlc_paths] + mappings = Enum.zip(source_paths, dest_paths) + options = project[:asn1_options] || [] + + Erlang.compile(manifest(), mappings, :asn1, :erl, opts[:force], fn + input, output -> + options = options ++ [:noobj, outdir: Erlang.to_erl_file(Path.dirname(output))] + :asn1ct.compile(Erlang.to_erl_file(input), options) + end) + end + + @doc """ + Returns ASN.1 manifests. + """ + def manifests, do: [manifest] + defp manifest, do: Path.join(Mix.Project.manifest_path, @manifest) + + @doc """ + Cleans up compilation artifacts. + """ + def clean do + Erlang.clean(manifest()) + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 000000000..8e735264b --- /dev/null +++ b/mix.exs @@ -0,0 +1,44 @@ +defmodule Ejabberd.Mixfile do + use Mix.Project + + def project do + [app: :ejabberd, + version: "15.03.0", + elixir: "~> 1.0", + elixirc_paths: ["lib"], + compile_path: ".", + compilers: Mix.compilers, + erlc_options: erlc_options, + deps: deps] + end + + def application do + [mod: {:ejabberd_app, []}, + applications: [:kernel, :stdlib]] + end + + defp erlc_options do + includes = Path.wildcard(Path.join("..", "/*/include")) + [:debug_info, {:d, :NO_EXT_LIB}] ++ Enum.map(includes, fn(path) -> {:i, path} end) + end + + defp deps do + [ + {:p1_xml, github: "processone/xml"}, + {:p1_logger, github: "processone/p1_logger"}, + {:p1_yaml, github: "processone/p1_yaml"}, + {:p1_tls, github: "processone/tls"}, + {:p1_stringprep, github: "processone/stringprep"}, + {:p1_zlib, github: "processone/zlib"}, + {:p1_cache_tab, github: "processone/cache_tab"}, + {:p1_utils, github: "processone/p1_utils"}, + {:p1_iconv, github: "processone/eiconv"}, + {:esip, github: "processone/p1_sip"}, + {:p1_stun, github: "processone/stun"}, + {:ehyperloglog, github: "vaxelfel/eHyperLogLog"}, + {:p1_mysql, github: "processone/mysql"}, + {:p1_pgsql, github: "processone/pgsql"}, + {:eredis, github: "wooga/eredis"} + ] + end +end diff --git a/src/ejabberd_config.erl b/src/ejabberd_config.erl index 6fc6c9e34..022590bc5 100644 --- a/src/ejabberd_config.erl +++ b/src/ejabberd_config.erl @@ -84,7 +84,7 @@ start() -> %% If not specified, the default value 'ejabberd.yml' is assumed. %% @spec () -> string() get_ejabberd_config_path() -> - case application:get_env(config) of + case get_env_config() of {ok, Path} -> Path; undefined -> case os:getenv("EJABBERD_CONFIG_PATH") of @@ -95,6 +95,18 @@ get_ejabberd_config_path() -> end end. +-spec get_env_config() -> {ok, string()} | undefined. +get_env_config() -> + %% First case: the filename can be specified with: erl -config "/path/to/ejabberd.yml". + case application:get_env(config) of + R = {ok, _Path} -> R; + undefined -> + %% Second case for embbeding ejabberd in another app, for example for Elixir: + %% config :ejabberd, + %% file: "config/ejabberd.yml" + application:get_env(ejabberd, file) + end. + %% @doc Read the ejabberd configuration file. %% It also includes additional configuration files and replaces macros. %% This function will crash if finds some error in the configuration file. @@ -679,7 +691,10 @@ is_file_readable(Path) -> end. get_version() -> - list_to_binary(element(2, application:get_key(ejabberd, vsn))). + case application:get_key(ejabberd, vsn) of + undefined -> ""; + {ok, Vsn} -> list_to_binary(Vsn) + end. -spec get_myhosts() -> [binary()].