aboutsummaryrefslogtreecommitdiff
path: root/src/ext_mod.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext_mod.erl')
-rw-r--r--src/ext_mod.erl149
1 files changed, 119 insertions, 30 deletions
diff --git a/src/ext_mod.erl b/src/ext_mod.erl
index f83fe2c6b..91526e71f 100644
--- a/src/ext_mod.erl
+++ b/src/ext_mod.erl
@@ -5,7 +5,7 @@
%%% Created : 19 Feb 2015 by Christophe Romain <christophe.romain@process-one.net>
%%%
%%%
-%%% ejabberd, Copyright (C) 2006-2015 ProcessOne
+%%% ejabberd, Copyright (C) 2006-2016 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
@@ -24,37 +24,34 @@
%%%----------------------------------------------------------------------
-module(ext_mod).
+
+-behaviour(ejabberd_config).
-author("Christophe Romain <christophe.romain@process-one.net>").
-%% Packaging service
-export([start/0, stop/0, update/0, check/1,
- available_command/0, available/0, available/1,
- installed_command/0, installed/0, installed/1,
- install/1, uninstall/1,
- upgrade/0, upgrade/1,
- add_sources/2, del_sources/1]).
+ available_command/0, available/0, available/1,
+ installed_command/0, installed/0, installed/1,
+ install/1, uninstall/1, upgrade/0, upgrade/1,
+ add_sources/2, del_sources/1, modules_dir/0,
+ config_dir/0, opt_type/1, get_commands_spec/0]).
-include("ejabberd_commands.hrl").
+-include("logger.hrl").
-define(REPOS, "https://github.com/processone/ejabberd-contrib").
%% -- ejabberd init and commands
start() ->
- case is_contrib_allowed() of
- true ->
- [code:add_patha(module_ebin_dir(Module))
- || {Module, _} <- installed()],
- application:start(inets),
- ejabberd_commands:register_commands(commands());
- false ->
- ok
- end.
+ [code:add_patha(module_ebin_dir(Module))
+ || {Module, _} <- installed()],
+ application:start(inets),
+ ejabberd_commands:register_commands(get_commands_spec()).
stop() ->
- ejabberd_commands:unregister_commands(commands()).
+ ejabberd_commands:unregister_commands(get_commands_spec()).
-commands() ->
+get_commands_spec() ->
[#ejabberd_commands{name = modules_update_specs,
tags = [admin,modules],
desc = "",
@@ -115,10 +112,19 @@ commands() ->
update() ->
add_sources(?REPOS),
- lists:foreach(fun({Package, Spec}) ->
+ Res = lists:foldl(fun({Package, Spec}, Acc) ->
Path = proplists:get_value(url, Spec, ""),
- add_sources(Package, Path)
- end, modules_spec(sources_dir(), "*")).
+ Update = add_sources(Package, Path),
+ ?INFO_MSG("Update package ~s: ~p", [Package, Update]),
+ case Update of
+ ok -> Acc;
+ Error -> [Error|Acc]
+ end
+ end, [], modules_spec(sources_dir(), "*")),
+ case Res of
+ [] -> ok;
+ [Error|_] -> Error
+ end.
available() ->
Jungle = modules_spec(sources_dir(), "*/*"),
@@ -163,6 +169,7 @@ install(Package) when is_binary(Package) ->
case compile_and_install(Module, Attrs) of
ok ->
code:add_patha(module_ebin_dir(Module)),
+ ejabberd_config:reload_file(),
ok;
Error ->
delete_path(module_lib_dir(Module)),
@@ -181,7 +188,8 @@ uninstall(Package) when is_binary(Package) ->
code:purge(Module),
code:delete(Module),
code:del_path(module_ebin_dir(Module)),
- delete_path(module_lib_dir(Module));
+ delete_path(module_lib_dir(Module)),
+ ejabberd_config:reload_file();
false ->
{error, not_installed}
end.
@@ -352,6 +360,10 @@ modules_dir() ->
sources_dir() ->
filename:join(modules_dir(), "sources").
+config_dir() ->
+ DefaultDir = filename:join(modules_dir(), "conf"),
+ getenv("CONTRIB_MODULES_CONF_DIR", DefaultDir).
+
module_lib_dir(Package) ->
filename:join(modules_dir(), Package).
@@ -444,9 +456,14 @@ compile_and_install(Module, Spec) ->
true ->
{ok, Dir} = file:get_cwd(),
file:set_cwd(SrcDir),
- Result = case compile(Module, Spec, LibDir) of
- ok -> install(Module, Spec, LibDir);
- Error -> Error
+ Result = case compile_deps(Module, Spec, LibDir) of
+ ok ->
+ case compile(Module, Spec, LibDir) of
+ ok -> install(Module, Spec, LibDir);
+ Error -> Error
+ end;
+ Error ->
+ Error
end,
file:set_cwd(Dir),
Result;
@@ -458,17 +475,46 @@ compile_and_install(Module, Spec) ->
end
end.
+compile_deps(_Module, _Spec, DestDir) ->
+ case filelib:is_dir("deps") of
+ true -> ok;
+ false -> fetch_rebar_deps()
+ end,
+ Ebin = filename:join(DestDir, "ebin"),
+ filelib:ensure_dir(filename:join(Ebin, ".")),
+ Result = lists:foldl(fun(Dep, Acc) ->
+ Inc = filename:join(Dep, "include"),
+ Src = filename:join(Dep, "src"),
+ Options = [{outdir, Ebin}, {i, Inc}],
+ [file:copy(App, Ebin) || App <- filelib:wildcard(Src++"/*.app")],
+ Acc++[case compile:file(File, Options) of
+ {ok, _} -> ok;
+ {ok, _, _} -> ok;
+ {ok, _, _, _} -> ok;
+ error -> {error, {compilation_failed, File}};
+ Error -> Error
+ end
+ || File <- filelib:wildcard(Src++"/*.erl")]
+ end, [], filelib:wildcard("deps/*")),
+ case lists:dropwhile(
+ fun(ok) -> true;
+ (_) -> false
+ end, Result) of
+ [] -> ok;
+ [Error|_] -> Error
+ end.
+
compile(_Module, _Spec, DestDir) ->
Ebin = filename:join(DestDir, "ebin"),
filelib:ensure_dir(filename:join(Ebin, ".")),
EjabBin = filename:dirname(code:which(ejabberd)),
EjabInc = filename:join(filename:dirname(EjabBin), "include"),
- XmlHrl = filename:join(EjabInc, "xml.hrl"),
- Logger = [{d, 'LAGER'} || code:is_loaded(lager)=/=false],
+ XmlHrl = filename:join(EjabInc, "fxml.hrl"),
ExtLib = [{d, 'NO_EXT_LIB'} || filelib:is_file(XmlHrl)],
Options = [{outdir, Ebin}, {i, "include"}, {i, EjabInc},
verbose, report_errors, report_warnings]
- ++ Logger ++ ExtLib,
+ ++ ExtLib,
+ [file:copy(App, Ebin) || App <- filelib:wildcard("src/*.app")],
Result = [case compile:file(File, Options) of
{ok, _} -> ok;
{ok, _, _} -> ok;
@@ -503,16 +549,59 @@ install(Module, Spec, DestDir) ->
Error -> Error
end.
+%% -- minimalist rebar spec parser, only support git
+
+fetch_rebar_deps() ->
+ case rebar_deps("rebar.config")++rebar_deps("rebar.config.script") of
+ [] ->
+ ok;
+ Deps ->
+ filelib:ensure_dir(filename:join("deps", ".")),
+ lists:foreach(fun({_App, Cmd}) ->
+ os:cmd("cd deps; "++Cmd++"; cd ..")
+ end, Deps)
+ end.
+rebar_deps(Script) ->
+ case file:script(Script) of
+ {ok, Config} when is_list(Config) ->
+ [rebar_dep(Dep) || Dep <- proplists:get_value(deps, Config, [])];
+ {ok, {deps, Deps}} ->
+ [rebar_dep(Dep) || Dep <- Deps];
+ _ ->
+ []
+ end.
+rebar_dep({App, _, {git, Url}}) ->
+ {App, "git clone "++Url++" "++filename:basename(App)};
+rebar_dep({App, _, {git, Url, {branch, Ref}}}) ->
+ {App, "git clone -n "++Url++" "++filename:basename(App)++
+ "; (cd "++filename:basename(App)++
+ "; git checkout -q origin/"++Ref++")"};
+rebar_dep({App, _, {git, Url, {tag, Ref}}}) ->
+ {App, "git clone -n "++Url++" "++filename:basename(App)++
+ "; (cd "++filename:basename(App)++
+ "; git checkout -q "++Ref++")"};
+rebar_dep({App, _, {git, Url, Ref}}) ->
+ {App, "git clone -n "++Url++" "++filename:basename(App)++
+ "; (cd "++filename:basename(App)++
+ "; git checkout -q "++Ref++")"}.
+
%% -- YAML spec parser
consult(File) ->
- case p1_yaml:decode_from_file(File, [plain_as_atom]) of
+ case fast_yaml:decode_from_file(File, [plain_as_atom]) of
{ok, []} -> {ok, []};
{ok, [Doc|_]} -> {ok, [format(Spec) || Spec <- Doc]};
- {error, Err} -> {error, p1_yaml:format_error(Err)}
+ {error, Err} -> {error, fast_yaml:format_error(Err)}
end.
format({Key, Val}) when is_binary(Val) ->
{Key, binary_to_list(Val)};
format({Key, Val}) -> % TODO: improve Yaml parsing
{Key, Val}.
+
+opt_type(allow_contrib_modules) ->
+ fun (false) -> false;
+ (no) -> false;
+ (_) -> true
+ end;
+opt_type(_) -> [allow_contrib_modules].