rebar.config.erl 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. -module('rebar.config').
  2. -export([do/2]).
  3. do(Dir, CONFIG) ->
  4. case iolist_to_binary(Dir) of
  5. <<".">> ->
  6. C1 = deps(CONFIG),
  7. Config = dialyzer(C1),
  8. maybe_dump(Config ++ [{overrides, overrides()}] ++ coveralls() ++ config());
  9. _ ->
  10. CONFIG
  11. end.
  12. bcrypt() ->
  13. {bcrypt, {git, "https://github.com/emqx/erlang-bcrypt.git", {branch, "0.6.0"}}}.
  14. quicer() ->
  15. {quicer, {git, "https://github.com/emqx/quic.git", {tag, "0.0.9"}}}.
  16. deps(Config) ->
  17. {deps, OldDeps} = lists:keyfind(deps, 1, Config),
  18. MoreDeps = [bcrypt() || provide_bcrypt_dep()] ++
  19. [quicer() || is_quicer_supported()],
  20. lists:keystore(deps, 1, Config, {deps, OldDeps ++ MoreDeps}).
  21. overrides() ->
  22. [ {add, [ {extra_src_dirs, [{"etc", [{recursive,true}]}]}
  23. , {erl_opts, [{compile_info, [{emqx_vsn, get_vsn()}]}]}
  24. ]}
  25. ] ++ snabbkaffe_overrides().
  26. %% Temporary workaround for a rebar3 erl_opts duplication
  27. %% bug. Ideally, we want to set this define globally
  28. snabbkaffe_overrides() ->
  29. Apps = [snabbkaffe, ekka, mria],
  30. [{add, App, [{erl_opts, [{d, snk_kind, msg}]}]} || App <- Apps].
  31. config() ->
  32. [ {cover_enabled, is_cover_enabled()}
  33. , {profiles, profiles()}
  34. , {plugins, plugins()}
  35. ].
  36. is_cover_enabled() ->
  37. case os:getenv("ENABLE_COVER_COMPILE") of
  38. "1"-> true;
  39. "true" -> true;
  40. _ -> false
  41. end.
  42. is_enterprise(ce) -> false;
  43. is_enterprise(ee) -> true.
  44. is_quicer_supported() ->
  45. not (false =/= os:getenv("BUILD_WITHOUT_QUIC") orelse
  46. is_win32() orelse is_centos_6()
  47. ).
  48. is_centos_6() ->
  49. %% reason:
  50. %% glibc is too old
  51. case file:read_file("/etc/centos-release") of
  52. {ok, <<"CentOS release 6", _/binary >>} ->
  53. true;
  54. _ ->
  55. false
  56. end.
  57. is_win32() ->
  58. win32 =:= element(1, os:type()).
  59. project_app_dirs(Edition) ->
  60. ["apps/*"] ++
  61. case is_enterprise(Edition) of
  62. true -> ["lib-ee/*"];
  63. false -> []
  64. end.
  65. plugins() ->
  66. [ {relup_helper,{git,"https://github.com/emqx/relup_helper", {tag, "2.0.0"}}}
  67. , {er_coap_client, {git, "https://github.com/emqx/er_coap_client", {tag, "v1.0.4"}}}
  68. %% emqx main project does not require port-compiler
  69. %% pin at root level for deterministic
  70. , {pc, {git, "https://github.com/emqx/port_compiler.git", {tag, "v1.11.1"}}}
  71. ]
  72. %% test plugins are concatenated to default profile plugins
  73. %% otherwise rebar3 test profile runs are super slow
  74. ++ test_plugins().
  75. test_plugins() ->
  76. [ {rebar3_proper, "0.12.1"}
  77. , {coveralls, {git, "https://github.com/emqx/coveralls-erl", {tag, "v2.2.0-emqx-1"}}}
  78. ].
  79. test_deps() ->
  80. [ {bbmustache, "1.10.0"}
  81. , {meck, "0.9.2"}
  82. , {proper, "1.4.0"}
  83. ].
  84. common_compile_opts() ->
  85. [ debug_info % alwyas include debug_info
  86. , {compile_info, [{emqx_vsn, get_vsn()}]}
  87. ] ++
  88. [{d, 'EMQX_BENCHMARK'} || os:getenv("EMQX_BENCHMARK") =:= "1" ].
  89. prod_compile_opts() ->
  90. [ compressed
  91. , deterministic
  92. , warnings_as_errors
  93. | common_compile_opts()
  94. ].
  95. prod_overrides() ->
  96. [{add, [ {erl_opts, [deterministic]}]}].
  97. profiles() ->
  98. Vsn = get_vsn(),
  99. [ {'emqx',
  100. [ {erl_opts, prod_compile_opts()}
  101. , {relx, relx(Vsn, cloud, bin, ce)}
  102. , {overrides, prod_overrides()}
  103. , {project_app_dirs, project_app_dirs(ce)}
  104. , {post_hooks, [{compile, "bash build emqx doc"}]}
  105. ]}
  106. , {'emqx-pkg',
  107. [ {erl_opts, prod_compile_opts()}
  108. , {relx, relx(Vsn, cloud, pkg, ce)}
  109. , {overrides, prod_overrides()}
  110. , {project_app_dirs, project_app_dirs(ce)}
  111. , {post_hooks, [{compile, "bash build emqx-pkg doc"}]}
  112. ]}
  113. , {'emqx-enterprise',
  114. [ {erl_opts, prod_compile_opts()}
  115. , {relx, relx(Vsn, cloud, bin, ee)}
  116. , {overrides, prod_overrides()}
  117. , {project_app_dirs, project_app_dirs(ee)}
  118. , {post_hooks, [{compile, "bash build emqx-enterprise doc"}]}
  119. ]}
  120. , {'emqx-enterprise-pkg',
  121. [ {erl_opts, prod_compile_opts()}
  122. , {relx, relx(Vsn, cloud, pkg, ee)}
  123. , {overrides, prod_overrides()}
  124. , {project_app_dirs, project_app_dirs(ee)}
  125. , {post_hooks, [{compile, "bash build emqx-enterprise-pkg doc"}]}
  126. ]}
  127. , {'emqx-edge',
  128. [ {erl_opts, prod_compile_opts()}
  129. , {relx, relx(Vsn, edge, bin, ce)}
  130. , {overrides, prod_overrides()}
  131. , {project_app_dirs, project_app_dirs(ce)}
  132. , {post_hooks, [{compile, "bash build emqx-edge doc"}]}
  133. ]}
  134. , {'emqx-edge-pkg',
  135. [ {erl_opts, prod_compile_opts()}
  136. , {relx, relx(Vsn, edge, pkg, ce)}
  137. , {overrides, prod_overrides()}
  138. , {project_app_dirs, project_app_dirs(ce)}
  139. , {post_hooks, [{compile, "bash build emqx-edge-pkg doc"}]}
  140. ]}
  141. , {check,
  142. [ {erl_opts, common_compile_opts()}
  143. , {project_app_dirs, project_app_dirs(ce)}
  144. ]}
  145. , {test,
  146. [ {deps, test_deps()}
  147. , {erl_opts, common_compile_opts() ++ erl_opts_i(ce) }
  148. , {extra_src_dirs, [{"test", [{recursive, true}]}]}
  149. , {project_app_dirs, project_app_dirs(ce)}
  150. ]}
  151. ].
  152. %% RelType: cloud (full size) | edge (slim size)
  153. %% PkgType: bin | pkg
  154. relx(Vsn, RelType, PkgType, Edition) ->
  155. [ {include_src,false}
  156. , {include_erts, true}
  157. , {extended_start_script,false}
  158. , {generate_start_script,false}
  159. , {sys_config,false}
  160. , {vm_args,false}
  161. , {release, {emqx, Vsn}, relx_apps(RelType, Edition)}
  162. , {overlay, relx_overlay(RelType, Edition)}
  163. , {overlay_vars, [ {built_on_arch, rebar_utils:get_arch()}
  164. , {emqx_description, emqx_description(RelType, Edition)}
  165. | overlay_vars(RelType, PkgType, Edition)]}
  166. ].
  167. emqx_description(cloud, ee) -> "EMQ X Enterprise Edition";
  168. emqx_description(cloud, ce) -> "EMQ X Community Edition";
  169. emqx_description(edge, ce) -> "EMQ X Edge Edition".
  170. overlay_vars(RelType, PkgType, _Edition) ->
  171. overlay_vars_rel(RelType) ++ overlay_vars_pkg(PkgType).
  172. %% vars per release type, cloud or edge
  173. overlay_vars_rel(RelType) ->
  174. VmArgs = case RelType of
  175. cloud -> "vm.args";
  176. edge -> "vm.args.edge"
  177. end,
  178. [ {vm_args_file, VmArgs}
  179. ].
  180. %% vars per packaging type, bin(zip/tar.gz/docker) or pkg(rpm/deb)
  181. overlay_vars_pkg(bin) ->
  182. [ {platform_bin_dir, "bin"}
  183. , {platform_data_dir, "data"}
  184. , {platform_etc_dir, "etc"}
  185. , {platform_lib_dir, "lib"}
  186. , {platform_log_dir, "log"}
  187. , {platform_plugins_dir, "plugins"}
  188. , {runner_root_dir, "$(cd $(dirname $(readlink $0 || echo $0))/..; pwd -P)"}
  189. , {runner_bin_dir, "$RUNNER_ROOT_DIR/bin"}
  190. , {runner_etc_dir, "$RUNNER_ROOT_DIR/etc"}
  191. , {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
  192. , {runner_log_dir, "$RUNNER_ROOT_DIR/log"}
  193. , {runner_data_dir, "$RUNNER_ROOT_DIR/data"}
  194. , {runner_user, ""}
  195. , {is_elixir, "no"}
  196. ];
  197. overlay_vars_pkg(pkg) ->
  198. [ {platform_bin_dir, ""}
  199. , {platform_data_dir, "/var/lib/emqx"}
  200. , {platform_etc_dir, "/etc/emqx"}
  201. , {platform_lib_dir, ""}
  202. , {platform_log_dir, "/var/log/emqx"}
  203. , {platform_plugins_dir, "/var/lib/emqx/plugins"}
  204. , {runner_root_dir, "/usr/lib/emqx"}
  205. , {runner_bin_dir, "/usr/bin"}
  206. , {runner_etc_dir, "/etc/emqx"}
  207. , {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
  208. , {runner_log_dir, "/var/log/emqx"}
  209. , {runner_data_dir, "/var/lib/emqx"}
  210. , {runner_user, "emqx"}
  211. , {is_elixir, "no"}
  212. ].
  213. relx_apps(ReleaseType, Edition) ->
  214. [ kernel
  215. , sasl
  216. , crypto
  217. , public_key
  218. , asn1
  219. , syntax_tools
  220. , ssl
  221. , os_mon
  222. , inets
  223. , compiler
  224. , runtime_tools
  225. , redbug
  226. , {hocon, load}
  227. , {emqx, load} % started by emqx_machine
  228. , {emqx_conf, load}
  229. , emqx_machine
  230. , {mnesia, load}
  231. , {ekka, load}
  232. , {emqx_plugin_libs, load}
  233. , {esasl, load}
  234. , observer_cli
  235. , system_monitor
  236. , emqx_http_lib
  237. , emqx_resource
  238. , emqx_connector
  239. , emqx_authn
  240. , emqx_authz
  241. , emqx_auto_subscribe
  242. , emqx_gateway
  243. , emqx_exhook
  244. , emqx_bridge
  245. , emqx_rule_engine
  246. , emqx_modules
  247. , emqx_management
  248. , emqx_dashboard
  249. , emqx_retainer
  250. , emqx_statsd
  251. , emqx_prometheus
  252. , emqx_psk
  253. , emqx_slow_subs
  254. , emqx_plugins
  255. ]
  256. ++ [quicer || is_quicer_supported()]
  257. %++ [emqx_license || is_enterprise(Edition)]
  258. ++ [bcrypt || provide_bcrypt_release(ReleaseType)]
  259. ++ relx_apps_per_rel(ReleaseType)
  260. %% NOTE: applications below are only loaded after node start/restart
  261. %% TODO: Add loaded/unloaded state to plugin apps
  262. %% then we can always start plugin apps
  263. ++ [{N, load} || N <- relx_plugin_apps(ReleaseType, Edition)].
  264. relx_apps_per_rel(cloud) ->
  265. [ xmerl
  266. | [{observer, load} || is_app(observer)]
  267. ];
  268. relx_apps_per_rel(edge) ->
  269. [].
  270. is_app(Name) ->
  271. case application:load(Name) of
  272. ok -> true;
  273. {error,{already_loaded, _}} -> true;
  274. _ -> false
  275. end.
  276. relx_plugin_apps(ReleaseType, Edition) ->
  277. relx_plugin_apps_per_rel(ReleaseType)
  278. ++ relx_plugin_apps_enterprise(Edition).
  279. relx_plugin_apps_per_rel(cloud) ->
  280. [];
  281. relx_plugin_apps_per_rel(edge) ->
  282. [].
  283. relx_plugin_apps_enterprise(ee) ->
  284. [list_to_atom(A) || A <- filelib:wildcard("*", "lib-ee"),
  285. filelib:is_dir(filename:join(["lib-ee", A]))];
  286. relx_plugin_apps_enterprise(ce) -> [].
  287. relx_overlay(ReleaseType, Edition) ->
  288. [ {mkdir, "log/"}
  289. , {mkdir, "data/"}
  290. , {mkdir, "plugins"}
  291. , {mkdir, "data/mnesia"}
  292. , {mkdir, "data/configs"}
  293. , {mkdir, "data/patches"}
  294. , {mkdir, "data/scripts"}
  295. , {template, "rel/emqx_vars", "releases/emqx_vars"}
  296. , {template, "rel/BUILT_ON", "releases/{{release_version}}/BUILT_ON"}
  297. , {copy, "bin/emqx", "bin/emqx"}
  298. , {copy, "bin/emqx_ctl", "bin/emqx_ctl"}
  299. , {copy, "bin/node_dump", "bin/node_dump"}
  300. , {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript"}
  301. , {copy, "bin/emqx", "bin/emqx-{{release_version}}"} %% for relup
  302. , {copy, "bin/emqx_ctl", "bin/emqx_ctl-{{release_version}}"} %% for relup
  303. , {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript-{{release_version}}"} %% for relup
  304. , {copy, "apps/emqx_gateway/src/lwm2m/lwm2m_xml", "etc/lwm2m_xml"}
  305. , {copy, "apps/emqx_authz/etc/acl.conf", "etc/acl.conf"}
  306. , {template, "bin/emqx.cmd", "bin/emqx.cmd"}
  307. , {template, "bin/emqx_ctl.cmd", "bin/emqx_ctl.cmd"}
  308. , {copy, "bin/nodetool", "bin/nodetool"}
  309. , {copy, "bin/nodetool", "bin/nodetool-{{release_version}}"}
  310. ] ++ etc_overlay(ReleaseType, Edition).
  311. etc_overlay(ReleaseType, _Edition) ->
  312. Templates = emqx_etc_overlay(ReleaseType),
  313. [ {mkdir, "etc/"}
  314. , {copy, "{{base_dir}}/lib/emqx/etc/certs","etc/"}
  315. ] ++
  316. lists:map(
  317. fun({From, To}) -> {template, From, To};
  318. (FromTo) -> {template, FromTo, FromTo}
  319. end, Templates)
  320. ++ extra_overlay(ReleaseType).
  321. extra_overlay(cloud) ->
  322. [
  323. ];
  324. extra_overlay(edge) ->
  325. [].
  326. emqx_etc_overlay(cloud) ->
  327. emqx_etc_overlay_common() ++
  328. [ {"{{base_dir}}/lib/emqx/etc/emqx_cloud/vm.args","etc/vm.args"}
  329. ];
  330. emqx_etc_overlay(edge) ->
  331. emqx_etc_overlay_common() ++
  332. [ {"{{base_dir}}/lib/emqx/etc/emqx_edge/vm.args","etc/vm.args"}
  333. ].
  334. emqx_etc_overlay_common() ->
  335. [ {"{{base_dir}}/lib/emqx_conf/etc/emqx.conf.all", "etc/emqx.conf"}
  336. , {"{{base_dir}}/lib/emqx/etc/ssl_dist.conf", "etc/ssl_dist.conf"}
  337. ].
  338. get_vsn() ->
  339. %% to make it compatible to Linux and Windows,
  340. %% we must use bash to execute the bash file
  341. %% because "./" will not be recognized as an internal or external command
  342. PkgVsn = os:cmd("bash pkg-vsn.sh"),
  343. re:replace(PkgVsn, "\n", "", [{return ,list}]).
  344. maybe_dump(Config) ->
  345. is_debug() andalso file:write_file("rebar.config.rendered", [io_lib:format("~p.\n", [I]) || I <- Config]),
  346. Config.
  347. is_debug() -> is_debug("DEBUG") orelse is_debug("DIAGNOSTIC").
  348. is_debug(VarName) ->
  349. case os:getenv(VarName) of
  350. false -> false;
  351. "" -> false;
  352. _ -> true
  353. end.
  354. provide_bcrypt_dep() ->
  355. not is_win32().
  356. provide_bcrypt_release(ReleaseType) ->
  357. provide_bcrypt_dep() andalso ReleaseType =:= cloud.
  358. erl_opts_i(Edition) ->
  359. [{i, "apps"}] ++
  360. [{i, Dir} || Dir <- filelib:wildcard(filename:join(["apps", "*", "include"]))] ++
  361. case is_enterprise(Edition) of
  362. true ->
  363. [{i, Dir} || Dir <- filelib:wildcard(filename:join(["lib-ee", "*", "include"]))];
  364. false -> []
  365. end.
  366. dialyzer(Config) ->
  367. {dialyzer, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config),
  368. AppsToAnalyse = case os:getenv("DIALYZER_ANALYSE_APP") of
  369. false ->
  370. [];
  371. Value ->
  372. [ list_to_atom(App) || App <- string:tokens(Value, ",")]
  373. end,
  374. AppNames = app_names(),
  375. KnownApps = [Name || Name <- AppsToAnalyse, lists:member(Name, AppNames)],
  376. AppsToExclude = AppNames -- KnownApps,
  377. case length(AppsToAnalyse) > 0 of
  378. true ->
  379. lists:keystore(dialyzer, 1, Config, {dialyzer, OldDialyzerConfig ++ [{exclude_apps, AppsToExclude}]});
  380. false ->
  381. Config
  382. end.
  383. coveralls() ->
  384. case {os:getenv("GITHUB_ACTIONS"), os:getenv("GITHUB_TOKEN")} of
  385. {"true", Token} when is_list(Token) ->
  386. Cfgs = [{coveralls_repo_token, Token},
  387. {coveralls_service_job_id, os:getenv("GITHUB_RUN_ID")},
  388. {coveralls_commit_sha, os:getenv("GITHUB_SHA")},
  389. {coveralls_coverdata, "_build/test/cover/*.coverdata"},
  390. {coveralls_service_name, "github"}],
  391. case os:getenv("GITHUB_EVENT_NAME") =:= "pull_request"
  392. andalso string:tokens(os:getenv("GITHUB_REF"), "/") of
  393. [_, "pull", PRNO, _] ->
  394. [{coveralls_service_pull_request, PRNO} | Cfgs];
  395. _ ->
  396. Cfgs
  397. end;
  398. _ ->
  399. []
  400. end.
  401. app_names() -> list_dir("apps") ++ list_dir("lib-ee").
  402. list_dir(Dir) ->
  403. case filelib:is_dir(Dir) of
  404. true ->
  405. {ok, Names} = file:list_dir(Dir),
  406. [list_to_atom(Name) || Name <- Names, filelib:is_dir(filename:join([Dir, Name]))];
  407. false ->
  408. []
  409. end.