%%%----------------------------------------------------------------------
%%%
%%% ejabberd, Copyright (C) 2002-2021 ProcessOne
%%%
%%% This program is free software; you can redistribute it and/or
%%% modify it under the terms of the GNU General Public License as
%%% published by the Free Software Foundation; either version 2 of the
%%% License, or (at your option) any later version.
%%%
%%% This program is distributed in the hope that it will be useful,
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
%%% General Public License for more details.
%%%
%%% You should have received a copy of the GNU General Public License along
%%% with this program; if not, write to the Free Software Foundation, Inc.,
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
Vars = case file:consult(filename:join([filename:dirname(SCRIPT),"vars.config"])) of
{ok, Terms} ->
Terms;
_Err ->
[]
end ++ [{cflags, "-g -O2 -Wall"}, {cppflags, "-g -O2 -Wall"},
{ldflags, ""}, {system_deps, false}],
{cflags, CFlags} = lists:keyfind(cflags, 1, Vars),
{cppflags, CPPFlags} = lists:keyfind(cppflags, 1, Vars),
{ldflags, LDFlags} = lists:keyfind(ldflags, 1, Vars),
{system_deps, SystemDeps} = lists:keyfind(system_deps, 1, Vars),
GetCfg = fun GetCfg(Cfg, [Key | Tail], Default) ->
Val = case lists:keyfind(Key, 1, Cfg) of
{Key, V1} -> V1;
false -> Default
end,
case Tail of
[] ->
Val;
_ ->
GetCfg(Val, Tail, Default)
end
end,
ModCfg = fun ModCfg(Cfg, [Key | Tail], Op, Default) ->
{OldVal, PartCfg} = case lists:keytake(Key, 1, Cfg) of
{value, {_, V1}, V2} -> {V1, V2};
false -> {if Tail == [] -> Default; true -> [] end, Cfg}
end,
case Tail of
[] ->
[{Key, Op(OldVal)} | PartCfg];
_ ->
[{Key, ModCfg(OldVal, Tail, Op, Default)} | PartCfg]
end
end,
FilterConfig = fun FilterConfig(Cfg, [{Path, true, ModFun, Default} | Tail]) ->
FilterConfig(ModCfg(Cfg, Path, ModFun, Default), Tail);
FilterConfig(Cfg, [{Path, SourcePath, true, ModFun, Default, SourceDefault} | Tail]) ->
SourceVal = GetCfg(Cfg, SourcePath, SourceDefault),
ModFun2 = fun(V) -> ModFun(V, SourceVal) end,
FilterConfig(ModCfg(Cfg, Path, ModFun2, Default), Tail);
FilterConfig(Cfg, [_ | Tail]) ->
FilterConfig(Cfg, Tail);
FilterConfig(Cfg, []) ->
Cfg
end,
IsRebar3 = case application:get_key(rebar, vsn) of
{ok, VSN} ->
[VSN1 | _] = string:tokens(VSN, "-"),
[Maj|_] = string:tokens(VSN1, "."),
(list_to_integer(Maj) >= 3);
undefined ->
lists:keymember(mix, 1, application:loaded_applications())
end,
SysVer = erlang:system_info(otp_release),
ProcessSingleVar = fun(F, Var, Tail) ->
case F([Var], []) of
[] -> Tail;
[Val] -> [Val | Tail]
end
end,
ProcessVars = fun F([], Acc) ->
lists:reverse(Acc);
F([{Type, Ver, Value} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
SysVer = erlang:system_info(otp_release),
Include = if Type == if_version_above ->
SysVer > Ver;
true ->
SysVer < Ver
end,
if Include ->
F(Tail, ProcessSingleVar(F, Value, Acc));
true ->
F(Tail, Acc)
end;
F([{Type, Ver, Value, ElseValue} | Tail], Acc) when
Type == if_version_above orelse
Type == if_version_below ->
Include = if Type == if_version_above ->
SysVer > Ver;
true ->
SysVer < Ver
end,
if Include ->
F(Tail, ProcessSingleVar(F, Value, Acc));
true ->
F(Tail, ProcessSingleVar(F, ElseValue, Acc))
end;
F([{Type, Var, Value} | Tail], Acc) when
Type == if_var_true orelse
Type == if_var_false ->
Flag = Type == if_var_true,
case proplists:get_bool(Var, Vars) of
V when V == Flag ->
F(Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(Tail, Acc)
end;
F([{Type, Value} | Tail], Acc) when
Type == if_rebar3 orelse
Type == if_not_rebar3 ->
Flag = Type == if_rebar3,
case IsRebar3 == Flag of
true ->
F(Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(Tail, Acc)
end;
F([{Type, Var, Match, Value} | Tail], Acc) when
Type == if_var_match orelse
Type == if_var_no_match ->
case proplists:get_value(Var, Vars) of
V when V == Match ->
F(Tail, ProcessSingleVar(F, Value, Acc));
_ ->
F(Tail, Acc)
end;
F([{if_have_fun, MFA, Value} | Tail], Acc) ->
{Mod, Fun, Arity} = MFA,
code:ensure_loaded(Mod),
case erlang:function_exported(Mod, Fun, Arity) of
true ->
F(Tail, ProcessSingleVar(F, Value, Acc));
false ->
F(Tail, Acc)
end;
F([Other1 | Tail1], Acc) ->
F(Tail1, [F(Other1, []) | Acc]);
F(Val, Acc) when is_tuple(Val) ->
list_to_tuple(F(tuple_to_list(Val), Acc));
F(Other2, _Acc) ->
Other2
end,
MaybeApply = fun(Val) when is_function(Val) ->
Val();
(Val) ->
Val
end,
MaybeApply2 = fun(Val, Arg) when is_function(Val) ->
Val(Arg);
(Val, _) ->
Val
end,
AppendStr = fun(Append) ->
fun("") ->
lists:flatten(MaybeApply(Append));
(Val) ->
lists:flatten([Val, " ", MaybeApply(Append)])
end
end,
AppendList = fun(Append) ->
fun(Val) ->
Val ++ MaybeApply(Append)
end
end,
AppendStr2 = fun(Append) ->
fun("", Arg) ->
lists:flatten(MaybeApply2(Append, Arg));
(Val, Arg) ->
lists:flatten([Val, " ", MaybeApply2(Append, Arg)])
end
end,
AppendList2 = fun(Append) ->
fun(Val, Arg) ->
Val ++ MaybeApply2(Append, Arg)
end
end,
Rebar3DepsFilter =
fun(DepsList, GitOnlyDeps) ->
lists:map(fun({DepName, _, {git, _, {tag, Version}}} = Dep) ->
case lists:member(DepName, GitOnlyDeps) of
true ->
Dep;
_ ->
{DepName, Version}
end;
(Dep) ->
Dep
end, DepsList)
end,
DepAlts = fun("esip") -> ["esip", "p1_sip"];
("xmpp") -> ["xmpp", "p1_xmpp"];
("fast_xml") -> ["fast_xml", "p1_xml"];
(Val) -> [Val]
end,
LibDirInt = fun F([Dep|Rest], Suffix) ->
case code:lib_dir(Dep) of
{error, _} ->
F(Rest, Suffix);
V -> V ++ Suffix
end;
F([], _) ->
error
end,
LibDir = fun(Name, Suffix) ->
LibDirInt(DepAlts(Name), Suffix)
end,
GlobalDepsFilter =
fun(Deps) ->
DepNames = lists:map(fun({DepName, _, _}) -> DepName;
({DepName, _}) -> DepName
end, Deps),
lists:filtermap(fun(Dep) ->
case LibDir(atom_to_list(Dep), "") of
error ->
exit("Unable to locate dep '" ++ atom_to_list(Dep) ++ "' in system deps.");
_ ->
false
end
end, DepNames)
end,
{ok, Cwd} = file:get_cwd(),
TestConfigFile = filename:join([Cwd, "test", "config.ctc"]),
TestConfig = case file:read_file_info(TestConfigFile) of
{ok, _} ->
[" -userconfig ct_config_plain ", TestConfigFile, " "];
_ ->
""
end,
ResolveDepPath = case {SystemDeps, IsRebar3} of
{true, _} ->
fun("deps/" ++ Rest) ->
Slash = string:str(Rest, "/"),
case LibDir(string:sub_string(Rest, 1, Slash -1), string:sub_string(Rest, Slash)) of
error -> Rest;
V -> V
end;
(Path) ->
Path
end;
{_, true} ->
fun("deps/" ++ Rest) ->
Slash = string:str(Rest, "/"),
"_build/default/lib/" ++
string:sub_string(Rest, 1, Slash - 1) ++
string:sub_string(Rest, Slash);
(Path) ->
Path
end;
_ ->
fun(P) ->
P
end
end,
CtParams = fun(CompileOpts) ->
["-ct_hooks cth_surefire ",
lists:map(fun({i, IncPath}) ->
[" -include ", filename:absname(ResolveDepPath(IncPath), Cwd)]
end, CompileOpts),
TestConfig]
end,
GenDepConfigureLine =
fun(DepPath, Flags) ->
["sh -c 'if test ! -f config.status -o ",
"../../config.status -nt config.status; ",
"then (",
"CFLAGS=\"", CFlags,"\" ",
"CPPFLAGS=\"", CPPFlags, "\" "
"LDFLAGS=\"", LDFlags, "\"",
" ./configure ", string:join(Flags, " "),
"); fi'"]
end,
GenDepsConfigure =
fun(Hooks) ->
lists:map(fun({Pkg, Flags}) ->
DepPath = ResolveDepPath("deps/" ++ Pkg ++ "/"),
Line = lists:flatten(GenDepConfigureLine(DepPath, Flags)),
{add, list_to_atom(Pkg), [{pre_hooks, [{{pc, compile}, Line}, {'compile', Line}, {'configure-deps', Line}]}]}
end, Hooks)
end,
ProcessErlOpt = fun(Vals) ->
R = lists:map(
fun({i, Path}) ->
{i, ResolveDepPath(Path)};
(ErlOpt) ->
ErlOpt
end, Vals),
M = lists:filter(fun({d, M}) -> true; (_) -> false end, R),
[{d, 'ALL_DEFS', M} | R]
end,
ProcssXrefExclusions = fun(Items) ->
[{lists:flatten(["(XC - UC) || (XU - X - B ",
[[" - ", V] || V <- Items], ")"]),
[]}]
end,
ProcessFloatingDeps =
fun(Deps, FDeps) ->
lists:map(fun({DepName, _Ver, {git, Repo, _Commit}} = Dep) ->
case lists:member(DepName, FDeps) of
true ->
{DepName, ".*", {git, Repo}};
_ ->
Dep
end;
(Dep2) ->
Dep2
end, Deps)
end,
TravisPostHooks =
fun(true) ->
[{eunit, "echo '\n%%! -pa .eunit/ deps/coveralls/ebin\n" ++
"main(_)->{ok,F}=file:open(\"erlang.json\",[write])," ++
"io:fwrite(F,\"~s\",[coveralls:convert_file(" ++
"\".eunit/cover.coverdata\", \"" ++
os:getenv("TRAVIS_JOB_ID") ++
"\", \"travis-ci\",\"\")]).' > getcover.erl"},
{eunit, "escript ./getcover.erl"}];
(_) ->
[]
end,
Rules = [
{[provider_hooks], IsRebar3,
AppendList([{pre, [
{compile, {asn, compile}},
{clean, {asn, clean}}
]}]), []},
{[deps], os:getenv("TRAVIS") == "true",
AppendList([{coveralls, ".*", {git, "https://github.com/markusn/coveralls-erl", {tag, "v2.0.1"}}}]), []},
{[post_hooks], [cover_enabled], os:getenv("TRAVIS") == "true",
AppendList2(TravisPostHooks), [], false},
{[overrides], [post_hook_configure], SystemDeps == false,
AppendList2(GenDepsConfigure), [], []},
{[ct_extra_params], [eunit_compile_opts], true,
AppendStr2(CtParams), "", []},
{[erl_opts], true,
ProcessErlOpt, []},
{[xref_queries], [xref_exclusions], true,
AppendList2(ProcssXrefExclusions), [], []},
{[deps], [floating_deps], true,
ProcessFloatingDeps, [], []},
{[deps], [gitonly_deps], IsRebar3,
Rebar3DepsFilter, [], []},
{[deps], SystemDeps /= false,
GlobalDepsFilter, []}
],
Config = [{plugin_dir, filename:join([filename:dirname(SCRIPT),"plugins"])}]++
FilterConfig(ProcessVars(CONFIG, []), Rules),
%io:format("ejabberd configuration:~n ~p~n", [Config]),
Config.
%% Local Variables:
%% mode: erlang
%% End:
%% vim: set filetype=erlang tabstop=8: