In order for us to reuse most of the functionalities implemented in `bin/eqmx` also in the Elixir release script, common variable and function definitions are extracted in separated bash files that can be sourced by both Rebar and Elixir release scripts.
463 lines
14 KiB
Erlang
463 lines
14 KiB
Erlang
-module('rebar.config').
|
|
|
|
-export([do/2]).
|
|
|
|
do(Dir, CONFIG) ->
|
|
case iolist_to_binary(Dir) of
|
|
<<".">> ->
|
|
C1 = deps(CONFIG),
|
|
Config = dialyzer(C1),
|
|
maybe_dump(Config ++ [{overrides, overrides()}] ++ coveralls() ++ config());
|
|
_ ->
|
|
CONFIG
|
|
end.
|
|
|
|
bcrypt() ->
|
|
{bcrypt, {git, "https://github.com/emqx/erlang-bcrypt.git", {branch, "0.6.0"}}}.
|
|
|
|
quicer() ->
|
|
{quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.9"}}}.
|
|
|
|
deps(Config) ->
|
|
{deps, OldDeps} = lists:keyfind(deps, 1, Config),
|
|
MoreDeps = [bcrypt() || provide_bcrypt_dep()] ++
|
|
[quicer() || is_quicer_supported()],
|
|
lists:keystore(deps, 1, Config, {deps, OldDeps ++ MoreDeps}).
|
|
|
|
overrides() ->
|
|
[ {add, [ {extra_src_dirs, [{"etc", [{recursive,true}]}]}
|
|
, {erl_opts, [{compile_info, [{emqx_vsn, get_vsn()}]}]}
|
|
]}
|
|
] ++ snabbkaffe_overrides().
|
|
|
|
%% Temporary workaround for a rebar3 erl_opts duplication
|
|
%% bug. Ideally, we want to set this define globally
|
|
snabbkaffe_overrides() ->
|
|
Apps = [snabbkaffe, ekka, mria],
|
|
[{add, App, [{erl_opts, [{d, snk_kind, msg}]}]} || App <- Apps].
|
|
|
|
config() ->
|
|
[ {cover_enabled, is_cover_enabled()}
|
|
, {profiles, profiles()}
|
|
, {plugins, plugins()}
|
|
].
|
|
|
|
is_cover_enabled() ->
|
|
case os:getenv("ENABLE_COVER_COMPILE") of
|
|
"1"-> true;
|
|
"true" -> true;
|
|
_ -> false
|
|
end.
|
|
|
|
is_enterprise(ce) -> false;
|
|
is_enterprise(ee) -> true.
|
|
|
|
is_quicer_supported() ->
|
|
not (false =/= os:getenv("BUILD_WITHOUT_QUIC") orelse
|
|
is_win32() orelse is_centos_6()
|
|
).
|
|
|
|
is_centos_6() ->
|
|
%% reason:
|
|
%% glibc is too old
|
|
case file:read_file("/etc/centos-release") of
|
|
{ok, <<"CentOS release 6", _/binary >>} ->
|
|
true;
|
|
_ ->
|
|
false
|
|
end.
|
|
|
|
is_win32() ->
|
|
win32 =:= element(1, os:type()).
|
|
|
|
project_app_dirs(Edition) ->
|
|
["apps/*"] ++
|
|
case is_enterprise(Edition) of
|
|
true -> ["lib-ee/*"];
|
|
false -> []
|
|
end.
|
|
|
|
plugins() ->
|
|
[ {relup_helper,{git,"https://github.com/emqx/relup_helper", {tag, "2.0.0"}}}
|
|
, {er_coap_client, {git, "https://github.com/emqx/er_coap_client", {tag, "v1.0.4"}}}
|
|
%% emqx main project does not require port-compiler
|
|
%% pin at root level for deterministic
|
|
, {pc, {git, "https://github.com/emqx/port_compiler.git", {tag, "v1.11.1"}}}
|
|
]
|
|
%% test plugins are concatenated to default profile plugins
|
|
%% otherwise rebar3 test profile runs are super slow
|
|
++ test_plugins().
|
|
|
|
test_plugins() ->
|
|
[ {rebar3_proper, "0.12.1"}
|
|
, {coveralls, {git, "https://github.com/emqx/coveralls-erl", {tag, "v2.2.0-emqx-1"}}}
|
|
].
|
|
|
|
test_deps() ->
|
|
[ {bbmustache, "1.10.0"}
|
|
, {meck, "0.9.2"}
|
|
, {proper, "1.4.0"}
|
|
].
|
|
|
|
common_compile_opts() ->
|
|
[ debug_info % alwyas include debug_info
|
|
, {compile_info, [{emqx_vsn, get_vsn()}]}
|
|
] ++
|
|
[{d, 'EMQX_BENCHMARK'} || os:getenv("EMQX_BENCHMARK") =:= "1" ].
|
|
|
|
prod_compile_opts() ->
|
|
[ compressed
|
|
, deterministic
|
|
, warnings_as_errors
|
|
| common_compile_opts()
|
|
].
|
|
|
|
prod_overrides() ->
|
|
[{add, [ {erl_opts, [deterministic]}]}].
|
|
|
|
profiles() ->
|
|
Vsn = get_vsn(),
|
|
[ {'emqx',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, cloud, bin, ce)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
, {post_hooks, [{compile, "./build emqx doc"}]}
|
|
]}
|
|
, {'emqx-pkg',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, cloud, pkg, ce)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
, {post_hooks, [{compile, "./build emqx-pkg doc"}]}
|
|
]}
|
|
, {'emqx-enterprise',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, cloud, bin, ee)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ee)}
|
|
, {post_hooks, [{compile, "./build emqx-enterprise doc"}]}
|
|
]}
|
|
, {'emqx-enterprise-pkg',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, cloud, pkg, ee)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ee)}
|
|
, {post_hooks, [{compile, "./build emqx-enterprise-pkg doc"}]}
|
|
]}
|
|
, {'emqx-edge',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, edge, bin, ce)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
, {post_hooks, [{compile, "./build emqx-edge doc"}]}
|
|
]}
|
|
, {'emqx-edge-pkg',
|
|
[ {erl_opts, prod_compile_opts()}
|
|
, {relx, relx(Vsn, edge, pkg, ce)}
|
|
, {overrides, prod_overrides()}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
, {post_hooks, [{compile, "./build emqx-edge-pkg doc"}]}
|
|
]}
|
|
, {check,
|
|
[ {erl_opts, common_compile_opts()}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
]}
|
|
, {test,
|
|
[ {deps, test_deps()}
|
|
, {erl_opts, common_compile_opts() ++ erl_opts_i(ce) }
|
|
, {extra_src_dirs, [{"test", [{recursive, true}]}]}
|
|
, {project_app_dirs, project_app_dirs(ce)}
|
|
]}
|
|
].
|
|
|
|
%% RelType: cloud (full size) | edge (slim size)
|
|
%% PkgType: bin | pkg
|
|
relx(Vsn, RelType, PkgType, Edition) ->
|
|
[ {include_src,false}
|
|
, {include_erts, true}
|
|
, {extended_start_script,false}
|
|
, {generate_start_script,false}
|
|
, {sys_config,false}
|
|
, {vm_args,false}
|
|
, {release, {emqx, Vsn}, relx_apps(RelType, Edition)}
|
|
, {overlay, relx_overlay(RelType, Edition)}
|
|
, {overlay_vars, [ {built_on_arch, rebar_utils:get_arch()}
|
|
, {emqx_description, emqx_description(RelType, Edition)}
|
|
| overlay_vars(RelType, PkgType, Edition)]}
|
|
].
|
|
|
|
emqx_description(cloud, ee) -> "EMQ X Enterprise Edition";
|
|
emqx_description(cloud, ce) -> "EMQ X Community Edition";
|
|
emqx_description(edge, ce) -> "EMQ X Edge Edition".
|
|
|
|
overlay_vars(RelType, PkgType, _Edition) ->
|
|
overlay_vars_rel(RelType) ++ overlay_vars_pkg(PkgType).
|
|
|
|
%% vars per release type, cloud or edge
|
|
overlay_vars_rel(RelType) ->
|
|
VmArgs = case RelType of
|
|
cloud -> "vm.args";
|
|
edge -> "vm.args.edge"
|
|
end,
|
|
|
|
[ {vm_args_file, VmArgs}
|
|
].
|
|
|
|
%% vars per packaging type, bin(zip/tar.gz/docker) or pkg(rpm/deb)
|
|
overlay_vars_pkg(bin) ->
|
|
[ {platform_bin_dir, "bin"}
|
|
, {platform_data_dir, "data"}
|
|
, {platform_etc_dir, "etc"}
|
|
, {platform_lib_dir, "lib"}
|
|
, {platform_log_dir, "log"}
|
|
, {platform_plugins_dir, "plugins"}
|
|
, {runner_root_dir, "$(cd $(dirname $(readlink $0 || echo $0))/..; pwd -P)"}
|
|
, {runner_bin_dir, "$RUNNER_ROOT_DIR/bin"}
|
|
, {runner_etc_dir, "$RUNNER_ROOT_DIR/etc"}
|
|
, {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
|
|
, {runner_log_dir, "$RUNNER_ROOT_DIR/log"}
|
|
, {runner_data_dir, "$RUNNER_ROOT_DIR/data"}
|
|
, {runner_user, ""}
|
|
];
|
|
overlay_vars_pkg(pkg) ->
|
|
[ {platform_bin_dir, ""}
|
|
, {platform_data_dir, "/var/lib/emqx"}
|
|
, {platform_etc_dir, "/etc/emqx"}
|
|
, {platform_lib_dir, ""}
|
|
, {platform_log_dir, "/var/log/emqx"}
|
|
, {platform_plugins_dir, "/var/lib/emqx/plugins"}
|
|
, {runner_root_dir, "/usr/lib/emqx"}
|
|
, {runner_bin_dir, "/usr/bin"}
|
|
, {runner_etc_dir, "/etc/emqx"}
|
|
, {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
|
|
, {runner_log_dir, "/var/log/emqx"}
|
|
, {runner_data_dir, "/var/lib/emqx"}
|
|
, {runner_user, "emqx"}
|
|
].
|
|
|
|
relx_apps(ReleaseType, Edition) ->
|
|
[ kernel
|
|
, sasl
|
|
, crypto
|
|
, public_key
|
|
, asn1
|
|
, syntax_tools
|
|
, ssl
|
|
, os_mon
|
|
, inets
|
|
, compiler
|
|
, runtime_tools
|
|
, {hocon, load}
|
|
, {emqx, load} % started by emqx_machine
|
|
, {emqx_conf, load}
|
|
, emqx_machine
|
|
, {mnesia, load}
|
|
, {ekka, load}
|
|
, {emqx_plugin_libs, load}
|
|
, {esasl, load}
|
|
, observer_cli
|
|
, system_monitor
|
|
, emqx_http_lib
|
|
, emqx_resource
|
|
, emqx_connector
|
|
, emqx_authn
|
|
, emqx_authz
|
|
, emqx_auto_subscribe
|
|
, emqx_gateway
|
|
, emqx_exhook
|
|
, emqx_bridge
|
|
, emqx_rule_engine
|
|
, emqx_modules
|
|
, emqx_management
|
|
, emqx_dashboard
|
|
, emqx_retainer
|
|
, emqx_statsd
|
|
, emqx_prometheus
|
|
, emqx_psk
|
|
, emqx_slow_subs
|
|
, emqx_plugins
|
|
]
|
|
++ [quicer || is_quicer_supported()]
|
|
%++ [emqx_license || is_enterprise(Edition)]
|
|
++ [bcrypt || provide_bcrypt_release(ReleaseType)]
|
|
++ relx_apps_per_rel(ReleaseType)
|
|
%% NOTE: applications below are only loaded after node start/restart
|
|
%% TODO: Add loaded/unloaded state to plugin apps
|
|
%% then we can always start plugin apps
|
|
++ [{N, load} || N <- relx_plugin_apps(ReleaseType, Edition)].
|
|
|
|
relx_apps_per_rel(cloud) ->
|
|
[ xmerl
|
|
| [{observer, load} || is_app(observer)]
|
|
];
|
|
relx_apps_per_rel(edge) ->
|
|
[].
|
|
|
|
is_app(Name) ->
|
|
case application:load(Name) of
|
|
ok -> true;
|
|
{error,{already_loaded, _}} -> true;
|
|
_ -> false
|
|
end.
|
|
|
|
relx_plugin_apps(ReleaseType, Edition) ->
|
|
relx_plugin_apps_per_rel(ReleaseType)
|
|
++ relx_plugin_apps_enterprise(Edition).
|
|
|
|
relx_plugin_apps_per_rel(cloud) ->
|
|
[];
|
|
relx_plugin_apps_per_rel(edge) ->
|
|
[].
|
|
|
|
relx_plugin_apps_enterprise(ee) ->
|
|
[list_to_atom(A) || A <- filelib:wildcard("*", "lib-ee"),
|
|
filelib:is_dir(filename:join(["lib-ee", A]))];
|
|
relx_plugin_apps_enterprise(ce) -> [].
|
|
|
|
relx_overlay(ReleaseType, Edition) ->
|
|
[ {mkdir, "log/"}
|
|
, {mkdir, "data/"}
|
|
, {mkdir, "plugins"}
|
|
, {mkdir, "data/mnesia"}
|
|
, {mkdir, "data/configs"}
|
|
, {mkdir, "data/patches"}
|
|
, {mkdir, "data/scripts"}
|
|
, {template, "data/emqx_vars", "releases/emqx_vars"}
|
|
, {template, "data/BUILT_ON", "releases/{{release_version}}/BUILT_ON"}
|
|
, {copy, "bin/emqx", "bin/emqx"}
|
|
, {copy, "bin/common_defs.sh", "bin/common_defs.sh"}
|
|
, {copy, "bin/common_defs2.sh", "bin/common_defs2.sh"}
|
|
, {copy, "bin/common_functions.sh", "bin/common_functions.sh"}
|
|
, {copy, "bin/emqx_ctl", "bin/emqx_ctl"}
|
|
, {copy, "bin/node_dump", "bin/node_dump"}
|
|
, {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript"}
|
|
, {copy, "bin/emqx", "bin/emqx-{{release_version}}"} %% for relup
|
|
, {copy, "bin/emqx_ctl", "bin/emqx_ctl-{{release_version}}"} %% for relup
|
|
, {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript-{{release_version}}"} %% for relup
|
|
, {copy, "apps/emqx_gateway/src/lwm2m/lwm2m_xml", "etc/lwm2m_xml"}
|
|
, {copy, "apps/emqx_authz/etc/acl.conf", "etc/acl.conf"}
|
|
, {template, "bin/emqx.cmd", "bin/emqx.cmd"}
|
|
, {template, "bin/emqx_ctl.cmd", "bin/emqx_ctl.cmd"}
|
|
, {copy, "bin/nodetool", "bin/nodetool"}
|
|
, {copy, "bin/nodetool", "bin/nodetool-{{release_version}}"}
|
|
] ++ etc_overlay(ReleaseType, Edition).
|
|
|
|
etc_overlay(ReleaseType, _Edition) ->
|
|
Templates = emqx_etc_overlay(ReleaseType),
|
|
[ {mkdir, "etc/"}
|
|
, {copy, "{{base_dir}}/lib/emqx/etc/certs","etc/"}
|
|
] ++
|
|
lists:map(
|
|
fun({From, To}) -> {template, From, To};
|
|
(FromTo) -> {template, FromTo, FromTo}
|
|
end, Templates)
|
|
++ extra_overlay(ReleaseType).
|
|
|
|
extra_overlay(cloud) ->
|
|
[
|
|
];
|
|
extra_overlay(edge) ->
|
|
[].
|
|
emqx_etc_overlay(cloud) ->
|
|
emqx_etc_overlay_common() ++
|
|
[ {"{{base_dir}}/lib/emqx/etc/emqx_cloud/vm.args","etc/vm.args"}
|
|
];
|
|
emqx_etc_overlay(edge) ->
|
|
emqx_etc_overlay_common() ++
|
|
[ {"{{base_dir}}/lib/emqx/etc/emqx_edge/vm.args","etc/vm.args"}
|
|
].
|
|
|
|
emqx_etc_overlay_common() ->
|
|
[ {"{{base_dir}}/lib/emqx_conf/etc/emqx.conf.all", "etc/emqx.conf"}
|
|
, {"{{base_dir}}/lib/emqx/etc/ssl_dist.conf", "etc/ssl_dist.conf"}
|
|
].
|
|
|
|
get_vsn() ->
|
|
%% to make it compatible to Linux and Windows,
|
|
%% we must use bash to execute the bash file
|
|
%% because "./" will not be recognized as an internal or external command
|
|
PkgVsn = os:cmd("bash pkg-vsn.sh"),
|
|
re:replace(PkgVsn, "\n", "", [{return ,list}]).
|
|
|
|
maybe_dump(Config) ->
|
|
is_debug() andalso file:write_file("rebar.config.rendered", [io_lib:format("~p.\n", [I]) || I <- Config]),
|
|
Config.
|
|
|
|
is_debug() -> is_debug("DEBUG") orelse is_debug("DIAGNOSTIC").
|
|
|
|
is_debug(VarName) ->
|
|
case os:getenv(VarName) of
|
|
false -> false;
|
|
"" -> false;
|
|
_ -> true
|
|
end.
|
|
|
|
provide_bcrypt_dep() ->
|
|
not is_win32().
|
|
|
|
provide_bcrypt_release(ReleaseType) ->
|
|
provide_bcrypt_dep() andalso ReleaseType =:= cloud.
|
|
|
|
erl_opts_i(Edition) ->
|
|
[{i, "apps"}] ++
|
|
[{i, Dir} || Dir <- filelib:wildcard(filename:join(["apps", "*", "include"]))] ++
|
|
case is_enterprise(Edition) of
|
|
true ->
|
|
[{i, Dir} || Dir <- filelib:wildcard(filename:join(["lib-ee", "*", "include"]))];
|
|
false -> []
|
|
end.
|
|
|
|
dialyzer(Config) ->
|
|
{dialyzer, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config),
|
|
|
|
AppsToAnalyse = case os:getenv("DIALYZER_ANALYSE_APP") of
|
|
false ->
|
|
[];
|
|
Value ->
|
|
[ list_to_atom(App) || App <- string:tokens(Value, ",")]
|
|
end,
|
|
|
|
AppNames = app_names(),
|
|
|
|
KnownApps = [Name || Name <- AppsToAnalyse, lists:member(Name, AppNames)],
|
|
|
|
AppsToExclude = AppNames -- KnownApps,
|
|
|
|
case length(AppsToAnalyse) > 0 of
|
|
true ->
|
|
lists:keystore(dialyzer, 1, Config, {dialyzer, OldDialyzerConfig ++ [{exclude_apps, AppsToExclude}]});
|
|
false ->
|
|
Config
|
|
end.
|
|
|
|
coveralls() ->
|
|
case {os:getenv("GITHUB_ACTIONS"), os:getenv("GITHUB_TOKEN")} of
|
|
{"true", Token} when is_list(Token) ->
|
|
Cfgs = [{coveralls_repo_token, Token},
|
|
{coveralls_service_job_id, os:getenv("GITHUB_RUN_ID")},
|
|
{coveralls_commit_sha, os:getenv("GITHUB_SHA")},
|
|
{coveralls_coverdata, "_build/test/cover/*.coverdata"},
|
|
{coveralls_service_name, "github"}],
|
|
case os:getenv("GITHUB_EVENT_NAME") =:= "pull_request"
|
|
andalso string:tokens(os:getenv("GITHUB_REF"), "/") of
|
|
[_, "pull", PRNO, _] ->
|
|
[{coveralls_service_pull_request, PRNO} | Cfgs];
|
|
_ ->
|
|
Cfgs
|
|
end;
|
|
_ ->
|
|
[]
|
|
end.
|
|
|
|
app_names() -> list_dir("apps") ++ list_dir("lib-ee").
|
|
|
|
list_dir(Dir) ->
|
|
case filelib:is_dir(Dir) of
|
|
true ->
|
|
{ok, Names} = file:list_dir(Dir),
|
|
[list_to_atom(Name) || Name <- Names, filelib:is_dir(filename:join([Dir, Name]))];
|
|
false ->
|
|
[]
|
|
end.
|