rebar.config.erl 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. -module('rebar.config').
  2. -export([do/2]).
  3. do(Dir, CONFIG) ->
  4. case iolist_to_binary(Dir) of
  5. <<".">> ->
  6. {HasElixir, C1} = deps(CONFIG),
  7. Config = dialyzer(C1),
  8. maybe_dump(Config ++ [{overrides, overrides()}] ++ coveralls() ++ config(HasElixir));
  9. _ ->
  10. CONFIG
  11. end.
  12. bcrypt() ->
  13. {bcrypt, {git, "https://github.com/emqx/erlang-bcrypt.git", {branch, "0.6.0"}}}.
  14. deps(Config) ->
  15. {deps, OldDeps} = lists:keyfind(deps, 1, Config),
  16. MoreDeps = case provide_bcrypt_dep() of
  17. true -> [bcrypt()];
  18. false -> []
  19. end,
  20. {HasElixir, ExtraDeps} = extra_deps(),
  21. {HasElixir, lists:keystore(deps, 1, Config, {deps, OldDeps ++ MoreDeps ++ ExtraDeps})}.
  22. extra_deps() ->
  23. {ok, Proplist} = file:consult("lib-extra/plugins"),
  24. ErlPlugins0 = proplists:get_value(erlang_plugins, Proplist),
  25. ExPlugins0 = proplists:get_value(elixir_plugins, Proplist),
  26. Filter = string:split(os:getenv("EMQX_EXTRA_PLUGINS", ""), ",", all),
  27. ErlPlugins = filter_extra_deps(ErlPlugins0, Filter),
  28. ExPlugins = filter_extra_deps(ExPlugins0, Filter),
  29. {ExPlugins =/= [], ErlPlugins ++ ExPlugins}.
  30. filter_extra_deps(AllPlugins, ["all"]) ->
  31. AllPlugins;
  32. filter_extra_deps(AllPlugins, Filter) ->
  33. filter_extra_deps(AllPlugins, Filter, []).
  34. filter_extra_deps([], _, Acc) ->
  35. lists:reverse(Acc);
  36. filter_extra_deps([{Plugin, _} = P | More], Filter, Acc) ->
  37. case lists:member(atom_to_list(Plugin), Filter) of
  38. true ->
  39. filter_extra_deps(More, Filter, [P | Acc]);
  40. false ->
  41. filter_extra_deps(More, Filter, Acc)
  42. end.
  43. overrides() ->
  44. [ {add, [ {extra_src_dirs, [{"etc", [{recursive,true}]}]}
  45. , {erl_opts, [{compile_info, [{emqx_vsn, get_vsn()}]}]}
  46. ]}
  47. , {add, snabbkaffe,
  48. [{erl_opts, common_compile_opts()}]}
  49. ] ++ community_plugin_overrides().
  50. community_plugin_overrides() ->
  51. [{add, App, [ {erl_opts, [{i, "include"}]}]} || App <- relx_plugin_apps_extra()].
  52. config(HasElixir) ->
  53. [ {cover_enabled, is_cover_enabled()}
  54. , {profiles, profiles()}
  55. , {project_app_dirs, project_app_dirs()}
  56. , {plugins, plugins(HasElixir)}
  57. | [ {provider_hooks, [ {pre, [{compile, {mix, find_elixir_libs}}]}
  58. , {post, [{compile, {mix, consolidate_protocols}}]}
  59. ]} || HasElixir ]
  60. ].
  61. is_cover_enabled() ->
  62. case os:getenv("ENABLE_COVER_COMPILE") of
  63. "1"-> true;
  64. "true" -> true;
  65. _ -> false
  66. end.
  67. is_enterprise() ->
  68. filelib:is_regular("EMQX_ENTERPRISE").
  69. project_app_dirs() ->
  70. ["apps/*"] ++
  71. case is_enterprise() of
  72. true -> ["lib-ee/*"];
  73. false -> []
  74. end.
  75. plugins(HasElixir) ->
  76. [ {relup_helper,{git,"https://github.com/emqx/relup_helper", {tag, "2.0.0"}}}
  77. , {er_coap_client, {git, "https://github.com/emqx/er_coap_client", {tag, "v1.0"}}}
  78. %% emqx main project does not require port-compiler
  79. %% pin at root level for deterministic
  80. , {pc, {git, "https://github.com/emqx/port_compiler.git", {tag, "v1.11.1"}}}
  81. | [ rebar_mix || HasElixir ]
  82. ]
  83. %% test plugins are concatenated to default profile plugins
  84. %% otherwise rebar3 test profile runs are super slow
  85. ++ test_plugins().
  86. test_plugins() ->
  87. [ rebar3_proper,
  88. {coveralls, {git, "https://github.com/emqx/coveralls-erl", {branch, "fix-git-info"}}}
  89. ].
  90. test_deps() ->
  91. [ {bbmustache, "1.10.0"}
  92. , {emqx_ct_helpers, {git, "https://github.com/emqx/emqx-ct-helpers", {tag, "2.0.0"}}}
  93. , meck
  94. ].
  95. common_compile_opts() ->
  96. [ debug_info % alwyas include debug_info
  97. , {compile_info, [{emqx_vsn, get_vsn()}]}
  98. , {d, snk_kind, msg}
  99. ] ++
  100. [{d, 'EMQX_ENTERPRISE'} || is_enterprise()] ++
  101. [{d, 'EMQX_BENCHMARK'} || os:getenv("EMQX_BENCHMARK") =:= "1" ].
  102. prod_compile_opts() ->
  103. [ compressed
  104. , deterministic
  105. , warnings_as_errors
  106. | common_compile_opts()
  107. ].
  108. prod_overrides() ->
  109. [{add, [ {erl_opts, [deterministic]}]}].
  110. profiles() ->
  111. Vsn = get_vsn(),
  112. [ {'emqx', [ {erl_opts, prod_compile_opts()}
  113. , {relx, relx(Vsn, cloud, bin)}
  114. , {overrides, prod_overrides()}
  115. ]}
  116. , {'emqx-pkg', [ {erl_opts, prod_compile_opts()}
  117. , {relx, relx(Vsn, cloud, pkg)}
  118. , {overrides, prod_overrides()}
  119. ]}
  120. , {'emqx-edge', [ {erl_opts, prod_compile_opts()}
  121. , {relx, relx(Vsn, edge, bin)}
  122. , {overrides, prod_overrides()}
  123. ]}
  124. , {'emqx-edge-pkg', [ {erl_opts, prod_compile_opts()}
  125. , {relx, relx(Vsn, edge, pkg)}
  126. , {overrides, prod_overrides()}
  127. ]}
  128. , {check, [ {erl_opts, common_compile_opts()}
  129. ]}
  130. , {test, [ {deps, test_deps()}
  131. , {erl_opts, common_compile_opts() ++ erl_opts_i()}
  132. , {extra_src_dirs, [{"test", [{recursive,true}]}]}
  133. ]}
  134. ] ++ ee_profiles(Vsn).
  135. %% RelType: cloud (full size) | edge (slim size)
  136. %% PkgType: bin | pkg
  137. relx(Vsn, RelType, PkgType) ->
  138. IsEnterprise = is_enterprise(),
  139. [ {include_src,false}
  140. , {include_erts, true}
  141. , {extended_start_script,false}
  142. , {generate_start_script,false}
  143. , {sys_config,false}
  144. , {vm_args,false}
  145. , {release, {emqx, Vsn}, relx_apps(RelType)}
  146. , {overlay, relx_overlay(RelType)}
  147. , {overlay_vars, [ {built_on_arch, rebar_utils:get_arch()}
  148. , {emqx_description, emqx_description(RelType, IsEnterprise)}
  149. | overlay_vars(RelType, PkgType, IsEnterprise)]}
  150. ].
  151. emqx_description(cloud, true) -> "EMQ X Enterprise";
  152. emqx_description(cloud, false) -> "EMQ X Broker";
  153. emqx_description(edge, _) -> "EMQ X Edge".
  154. overlay_vars(_RelType, PkgType, true) ->
  155. ee_overlay_vars(PkgType);
  156. overlay_vars(RelType, PkgType, false) ->
  157. overlay_vars_rel(RelType) ++ overlay_vars_pkg(PkgType).
  158. %% vars per release type, cloud or edge
  159. overlay_vars_rel(RelType) ->
  160. VmArgs = case RelType of
  161. cloud -> "vm.args";
  162. edge -> "vm.args.edge"
  163. end,
  164. [ {enable_plugin_emqx_rule_engine, RelType =:= cloud}
  165. , {enable_plugin_emqx_bridge_mqtt, RelType =:= edge}
  166. , {enable_plugin_emqx_resource, true}
  167. , {enable_plugin_emqx_connector, true}
  168. , {enable_plugin_emqx_data_bridge, true}
  169. , {enable_plugin_emqx_modules, false} %% modules is not a plugin in ce
  170. , {enable_plugin_emqx_recon, true}
  171. , {enable_plugin_emqx_retainer, true}
  172. , {enable_plugin_emqx_telemetry, true}
  173. , {vm_args_file, VmArgs}
  174. ].
  175. %% vars per packaging type, bin(zip/tar.gz/docker) or pkg(rpm/deb)
  176. overlay_vars_pkg(bin) ->
  177. [ {platform_bin_dir, "bin"}
  178. , {platform_data_dir, "data"}
  179. , {platform_etc_dir, "etc"}
  180. , {platform_lib_dir, "lib"}
  181. , {platform_log_dir, "log"}
  182. , {platform_plugins_dir, "etc/plugins"}
  183. , {runner_root_dir, "$(cd $(dirname $(readlink $0 || echo $0))/..; pwd -P)"}
  184. , {runner_bin_dir, "$RUNNER_ROOT_DIR/bin"}
  185. , {runner_etc_dir, "$RUNNER_ROOT_DIR/etc"}
  186. , {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
  187. , {runner_log_dir, "$RUNNER_ROOT_DIR/log"}
  188. , {runner_data_dir, "$RUNNER_ROOT_DIR/data"}
  189. , {runner_user, ""}
  190. ];
  191. overlay_vars_pkg(pkg) ->
  192. [ {platform_bin_dir, ""}
  193. , {platform_data_dir, "/var/lib/emqx"}
  194. , {platform_etc_dir, "/etc/emqx"}
  195. , {platform_lib_dir, ""}
  196. , {platform_log_dir, "/var/log/emqx"}
  197. , {platform_plugins_dir, "/var/lib/emqx/plugins"}
  198. , {runner_root_dir, "/usr/lib/emqx"}
  199. , {runner_bin_dir, "/usr/bin"}
  200. , {runner_etc_dir, "/etc/emqx"}
  201. , {runner_lib_dir, "$RUNNER_ROOT_DIR/lib"}
  202. , {runner_log_dir, "/var/log/emqx"}
  203. , {runner_data_dir, "/var/lib/emqx"}
  204. , {runner_user, "emqx"}
  205. ].
  206. relx_apps(ReleaseType) ->
  207. [ kernel
  208. , sasl
  209. , crypto
  210. , public_key
  211. , asn1
  212. , syntax_tools
  213. , ssl
  214. , os_mon
  215. , inets
  216. , compiler
  217. , runtime_tools
  218. , cuttlefish
  219. , emqx
  220. , {mnesia, load}
  221. , {ekka, load}
  222. , {emqx_plugin_libs, load}
  223. , observer_cli
  224. , emqx_http_lib
  225. ]
  226. ++ [emqx_modules || not is_enterprise()]
  227. ++ [emqx_license || is_enterprise()]
  228. ++ [bcrypt || provide_bcrypt_release(ReleaseType)]
  229. ++ relx_apps_per_rel(ReleaseType)
  230. ++ [{N, load} || N <- relx_plugin_apps(ReleaseType)].
  231. relx_apps_per_rel(cloud) ->
  232. [ luerl
  233. , xmerl
  234. | [{observer, load} || is_app(observer)]
  235. ];
  236. relx_apps_per_rel(edge) ->
  237. [].
  238. is_app(Name) ->
  239. case application:load(Name) of
  240. ok -> true;
  241. {error,{already_loaded, _}} -> true;
  242. _ -> false
  243. end.
  244. relx_plugin_apps(ReleaseType) ->
  245. [ emqx_retainer
  246. , emqx_management
  247. , emqx_dashboard
  248. , emqx_bridge_mqtt
  249. , emqx_sn
  250. , emqx_coap
  251. , emqx_stomp
  252. , emqx_authentication
  253. , emqx_auth_http
  254. , emqx_auth_mysql
  255. , emqx_auth_jwt
  256. , emqx_auth_mnesia
  257. , emqx_web_hook
  258. , emqx_recon
  259. , emqx_resource
  260. , emqx_connector
  261. , emqx_data_bridge
  262. , emqx_rule_engine
  263. , emqx_sasl
  264. ]
  265. ++ [emqx_telemetry || not is_enterprise()]
  266. ++ relx_plugin_apps_per_rel(ReleaseType)
  267. ++ relx_plugin_apps_enterprise(is_enterprise())
  268. ++ relx_plugin_apps_extra().
  269. relx_plugin_apps_per_rel(cloud) ->
  270. [ emqx_lwm2m
  271. , emqx_auth_ldap
  272. , emqx_auth_pgsql
  273. , emqx_auth_redis
  274. , emqx_auth_mongo
  275. , emqx_lua_hook
  276. , emqx_exhook
  277. , emqx_exproto
  278. , emqx_prometheus
  279. , emqx_psk_file
  280. ];
  281. relx_plugin_apps_per_rel(edge) ->
  282. [].
  283. relx_plugin_apps_enterprise(true) ->
  284. [list_to_atom(A) || A <- filelib:wildcard("*", "lib-ee"),
  285. filelib:is_dir(filename:join(["lib-ee", A]))];
  286. relx_plugin_apps_enterprise(false) -> [].
  287. relx_plugin_apps_extra() ->
  288. {_HasElixir, ExtraDeps} = extra_deps(),
  289. [Plugin || {Plugin, _} <- ExtraDeps].
  290. relx_overlay(ReleaseType) ->
  291. [ {mkdir, "log/"}
  292. , {mkdir, "data/"}
  293. , {mkdir, "data/mnesia"}
  294. , {mkdir, "data/configs"}
  295. , {mkdir, "data/patches"}
  296. , {mkdir, "data/scripts"}
  297. , {template, "data/loaded_plugins.tmpl", "data/loaded_plugins"}
  298. , {template, "data/loaded_modules.tmpl", "data/loaded_modules"}
  299. , {template, "data/emqx_vars", "releases/emqx_vars"}
  300. , {template, "data/BUILT_ON", "releases/{{release_version}}/BUILT_ON"}
  301. , {copy, "bin/emqx", "bin/emqx"}
  302. , {copy, "bin/emqx_ctl", "bin/emqx_ctl"}
  303. , {copy, "bin/node_dump", "bin/node_dump"}
  304. , {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript"}
  305. , {copy, "bin/emqx", "bin/emqx-{{release_version}}"} %% for relup
  306. , {copy, "bin/emqx_ctl", "bin/emqx_ctl-{{release_version}}"} %% for relup
  307. , {copy, "bin/install_upgrade.escript", "bin/install_upgrade.escript-{{release_version}}"} %% for relup
  308. , {template, "bin/emqx.cmd", "bin/emqx.cmd"}
  309. , {template, "bin/emqx_ctl.cmd", "bin/emqx_ctl.cmd"}
  310. , {copy, "bin/nodetool", "bin/nodetool"}
  311. , {copy, "bin/nodetool", "bin/nodetool-{{release_version}}"}
  312. ] ++ case is_enterprise() of
  313. true -> ee_etc_overlay(ReleaseType);
  314. false -> etc_overlay(ReleaseType)
  315. end.
  316. etc_overlay(ReleaseType) ->
  317. PluginApps = relx_plugin_apps(ReleaseType),
  318. Templates = emqx_etc_overlay(ReleaseType) ++
  319. lists:append([plugin_etc_overlays(App) || App <- PluginApps]) ++
  320. [community_plugin_etc_overlays(App) || App <- relx_plugin_apps_extra()],
  321. [ {mkdir, "etc/"}
  322. , {mkdir, "etc/plugins"}
  323. , {copy, "{{base_dir}}/lib/emqx/etc/certs","etc/"}
  324. ] ++
  325. lists:map(
  326. fun({From, To}) -> {template, From, To};
  327. (FromTo) -> {template, FromTo, FromTo}
  328. end, Templates)
  329. ++ extra_overlay(ReleaseType).
  330. extra_overlay(cloud) ->
  331. [ {copy,"{{base_dir}}/lib/emqx_lwm2m/lwm2m_xml","etc/"}
  332. , {copy, "{{base_dir}}/lib/emqx_psk_file/etc/psk.txt", "etc/psk.txt"}
  333. ];
  334. extra_overlay(edge) ->
  335. [].
  336. emqx_etc_overlay(cloud) ->
  337. emqx_etc_overlay_common() ++
  338. [ {"{{base_dir}}/lib/emqx/etc/emqx_cloud/vm.args","etc/vm.args"}
  339. ];
  340. emqx_etc_overlay(edge) ->
  341. emqx_etc_overlay_common() ++
  342. [ {"{{base_dir}}/lib/emqx/etc/emqx_edge/vm.args","etc/vm.args"}
  343. ].
  344. emqx_etc_overlay_common() ->
  345. [{"{{base_dir}}/lib/emqx/etc/acl.conf", "etc/acl.conf"},
  346. {"{{base_dir}}/lib/emqx/etc/emqx.conf", "etc/emqx.conf"},
  347. {"{{base_dir}}/lib/emqx/etc/ssl_dist.conf", "etc/ssl_dist.conf"},
  348. %% TODO: check why it has to end with .paho
  349. %% and why it is put to etc/plugins dir
  350. {"{{base_dir}}/lib/emqx/etc/acl.conf.paho", "etc/plugins/acl.conf.paho"}].
  351. plugin_etc_overlays(App0) ->
  352. App = atom_to_list(App0),
  353. ConfFiles = find_conf_files(App),
  354. %% NOTE: not filename:join here since relx translates it for windows
  355. [{"{{base_dir}}/lib/"++ App ++"/etc/" ++ F, "etc/plugins/" ++ F}
  356. || F <- ConfFiles].
  357. community_plugin_etc_overlays(App0) ->
  358. App = atom_to_list(App0),
  359. {"{{base_dir}}/lib/"++ App ++"/etc/" ++ App ++ ".conf", "etc/plugins/" ++ App ++ ".conf"}.
  360. %% NOTE: for apps fetched as rebar dependency (there is so far no such an app)
  361. %% the overlay should be hand-coded but not to rely on build-time wildcards.
  362. find_conf_files(App) ->
  363. Dir1 = filename:join(["apps", App, "etc"]),
  364. filelib:wildcard("*.conf", Dir1) ++
  365. case is_enterprise() of
  366. true ->
  367. Dir2 = filename:join(["lib-ee", App, "etc"]),
  368. filelib:wildcard("*.conf", Dir2);
  369. false -> []
  370. end.
  371. env(Name, Default) ->
  372. case os:getenv(Name) of
  373. "" -> Default;
  374. false -> Default;
  375. Value -> Value
  376. end.
  377. get_vsn() ->
  378. PkgVsn = case env("PKG_VSN", false) of
  379. false -> os:cmd("./pkg-vsn.sh");
  380. Vsn -> Vsn
  381. end,
  382. re:replace(PkgVsn, "\n", "", [{return ,list}]).
  383. maybe_dump(Config) ->
  384. is_debug() andalso file:write_file("rebar.config.rendered", [io_lib:format("~p.\n", [I]) || I <- Config]),
  385. Config.
  386. is_debug() -> is_debug("DEBUG") orelse is_debug("DIAGNOSTIC").
  387. is_debug(VarName) ->
  388. case os:getenv(VarName) of
  389. false -> false;
  390. "" -> false;
  391. _ -> true
  392. end.
  393. provide_bcrypt_dep() ->
  394. case os:type() of
  395. {win32, _} -> false;
  396. _ -> true
  397. end.
  398. provide_bcrypt_release(ReleaseType) ->
  399. provide_bcrypt_dep() andalso ReleaseType =:= cloud.
  400. erl_opts_i() ->
  401. [{i, "apps"}] ++
  402. [{i, Dir} || Dir <- filelib:wildcard(filename:join(["apps", "*", "include"]))] ++
  403. case is_enterprise() of
  404. true ->
  405. [{i, Dir} || Dir <- filelib:wildcard(filename:join(["lib-ee", "*", "include"]))];
  406. false -> []
  407. end.
  408. dialyzer(Config) ->
  409. {dialyzer, OldDialyzerConfig} = lists:keyfind(dialyzer, 1, Config),
  410. AppsToAnalyse = case os:getenv("DIALYZER_ANALYSE_APP") of
  411. false ->
  412. [];
  413. Value ->
  414. [ list_to_atom(App) || App <- string:tokens(Value, ",")]
  415. end,
  416. AppNames = [list_dir("apps")] ++
  417. case is_enterprise() of
  418. true -> [list_dir("lib-ee")];
  419. false -> []
  420. end,
  421. KnownApps = [Name || Name <- AppsToAnalyse, lists:member(Name, AppNames)],
  422. AppsToExclude = AppNames -- KnownApps,
  423. case length(AppsToAnalyse) > 0 of
  424. true ->
  425. lists:keystore(dialyzer, 1, Config, {dialyzer, OldDialyzerConfig ++ [{exclude_apps, AppsToExclude}]});
  426. false ->
  427. Config
  428. end.
  429. coveralls() ->
  430. case {os:getenv("GITHUB_ACTIONS"), os:getenv("GITHUB_TOKEN")} of
  431. {"true", Token} when is_list(Token) ->
  432. Cfgs = [{coveralls_repo_token, Token},
  433. {coveralls_service_job_id, os:getenv("GITHUB_RUN_ID")},
  434. {coveralls_commit_sha, os:getenv("GITHUB_SHA")},
  435. {coveralls_coverdata, "_build/test/cover/*.coverdata"},
  436. {coveralls_service_name, "github"}],
  437. case os:getenv("GITHUB_EVENT_NAME") =:= "pull_request"
  438. andalso string:tokens(os:getenv("GITHUB_REF"), "/") of
  439. [_, "pull", PRNO, _] ->
  440. [{coveralls_service_pull_request, PRNO} | Cfgs];
  441. _ ->
  442. Cfgs
  443. end;
  444. _ ->
  445. []
  446. end.
  447. list_dir(Dir) ->
  448. {ok, Names} = file:list_dir(Dir),
  449. [list_to_atom(Name) || Name <- Names, filelib:is_dir(filename:join([Dir, Name]))].
  450. %% ==== Enterprise supports below ==================================================================
  451. ee_profiles(_Vsn) -> [].
  452. ee_etc_overlay(_) -> [].
  453. ee_overlay_vars(_PkgType) -> [].