diff options
Diffstat (limited to 'src/ext_mod.erl')
-rw-r--r-- | src/ext_mod.erl | 149 |
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]. |