mix.exs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. defmodule EMQXUmbrella.MixProject do
  2. use Mix.Project
  3. @moduledoc """
  4. The purpose of this file is to configure the release of EMQX under
  5. Mix. Since EMQX uses its own configuration conventions and startup
  6. procedures, one cannot simply use `iex -S mix`. Instead, it's
  7. recommendd to build and use the release.
  8. ## Profiles
  9. To control the profile and edition to build, we case split on the
  10. MIX_ENV value.
  11. The following profiles are valid:
  12. * `emqx`
  13. * `emqx-enterprise`
  14. * `emqx-pkg`
  15. * `emqx-enterprise-pkg`
  16. * `dev` -> same as `emqx`, for convenience
  17. ## Release Environment Variables
  18. The release build is controlled by a few environment variables.
  19. * `ELIXIR_MAKE_TAR` - If set to `yes`, will produce a `.tar.gz`
  20. tarball along with the release.
  21. """
  22. def project() do
  23. profile_info = check_profile!()
  24. [
  25. app: :emqx_mix,
  26. version: pkg_vsn(),
  27. deps: deps(profile_info),
  28. releases: releases()
  29. ]
  30. end
  31. defp deps(profile_info) do
  32. # we need several overrides here because dependencies specify
  33. # other exact versions, and not ranges.
  34. [
  35. {:lc, github: "emqx/lc", tag: "0.3.1"},
  36. {:redbug, "2.0.7"},
  37. {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true},
  38. {:ehttpc, github: "emqx/ehttpc", tag: "0.3.0"},
  39. {:gproc, github: "uwiger/gproc", tag: "0.8.0", override: true},
  40. {:jiffy, github: "emqx/jiffy", tag: "1.0.5", override: true},
  41. {:cowboy, github: "emqx/cowboy", tag: "2.9.0", override: true},
  42. {:esockd, github: "emqx/esockd", tag: "5.9.4", override: true},
  43. {:ekka, github: "emqx/ekka", tag: "0.13.4", override: true},
  44. {:gen_rpc, github: "emqx/gen_rpc", tag: "2.8.1", override: true},
  45. {:grpc, github: "emqx/grpc-erl", tag: "0.6.6", override: true},
  46. {:minirest, github: "emqx/minirest", tag: "1.3.6", override: true},
  47. {:ecpool, github: "emqx/ecpool", tag: "0.5.2"},
  48. {:replayq, "0.3.4", override: true},
  49. {:pbkdf2, github: "emqx/erlang-pbkdf2", tag: "2.0.4", override: true},
  50. {:emqtt, github: "emqx/emqtt", tag: "1.6.0", override: true},
  51. {:rulesql, github: "emqx/rulesql", tag: "0.1.4"},
  52. {:observer_cli, "1.7.1"},
  53. {:system_monitor, github: "ieQu1/system_monitor", tag: "3.0.3"},
  54. # in conflict by emqtt and hocon
  55. {:getopt, "1.0.2", override: true},
  56. {:snabbkaffe, github: "kafka4beam/snabbkaffe", tag: "1.0.0", override: true},
  57. {:hocon, github: "emqx/hocon", tag: "0.30.0", override: true},
  58. {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.1", override: true},
  59. {:esasl, github: "emqx/esasl", tag: "0.2.0"},
  60. {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2"},
  61. # in conflict by ehttpc and emqtt
  62. {:gun, github: "emqx/gun", tag: "1.3.7", override: true},
  63. # in conflict by emqx_connectior and system_monitor
  64. {:epgsql, github: "emqx/epgsql", tag: "4.7-emqx.2", override: true},
  65. # in conflict by mongodb and eredis_cluster
  66. {:poolboy, github: "emqx/poolboy", tag: "1.5.2", override: true},
  67. # in conflict by emqx and observer_cli
  68. {:recon, github: "ferd/recon", tag: "2.5.1", override: true},
  69. {:jsx, github: "talentdeficit/jsx", tag: "v3.1.0", override: true},
  70. # dependencies of dependencies; we choose specific refs to match
  71. # what rebar3 chooses.
  72. # in conflict by gun and emqtt
  73. {:cowlib,
  74. github: "ninenines/cowlib", ref: "c6553f8308a2ca5dcd69d845f0a7d098c40c3363", override: true},
  75. # in conflict by cowboy_swagger and cowboy
  76. {:ranch,
  77. github: "ninenines/ranch", ref: "a692f44567034dacf5efcaa24a24183788594eb7", override: true},
  78. # in conflict by grpc and eetcd
  79. {:gpb, "4.11.2", override: true, runtime: false}
  80. ] ++
  81. umbrella_apps() ++ enterprise_apps(profile_info) ++ bcrypt_dep() ++ jq_dep() ++ quicer_dep()
  82. end
  83. defp umbrella_apps() do
  84. "apps/*"
  85. |> Path.wildcard()
  86. |> Enum.map(fn path ->
  87. app =
  88. path
  89. |> Path.basename()
  90. |> String.to_atom()
  91. {app, path: path, manager: :rebar3, override: true}
  92. end)
  93. end
  94. defp enterprise_apps(_profile_info = %{edition_type: :enterprise}) do
  95. "lib-ee/*"
  96. |> Path.wildcard()
  97. |> Enum.filter(&File.dir?/1)
  98. |> Enum.map(fn path ->
  99. app =
  100. path
  101. |> Path.basename()
  102. |> String.to_atom()
  103. {app, path: path, manager: :rebar3, override: true}
  104. end)
  105. end
  106. defp enterprise_apps(_profile_info) do
  107. []
  108. end
  109. defp releases() do
  110. [
  111. emqx: fn ->
  112. %{
  113. release_type: release_type,
  114. package_type: package_type,
  115. edition_type: edition_type
  116. } = check_profile!()
  117. base_steps = [
  118. &make_docs(&1),
  119. :assemble,
  120. &create_RELEASES/1,
  121. &copy_files(&1, release_type, package_type, edition_type),
  122. &copy_escript(&1, "nodetool"),
  123. &copy_escript(&1, "install_upgrade.escript")
  124. ]
  125. steps =
  126. if System.get_env("ELIXIR_MAKE_TAR") == "yes" do
  127. base_steps ++ [&prepare_tar_overlays/1, :tar]
  128. else
  129. base_steps
  130. end
  131. [
  132. applications: applications(edition_type),
  133. skip_mode_validation_for: [
  134. :emqx_gateway,
  135. :emqx_dashboard,
  136. :emqx_resource,
  137. :emqx_connector,
  138. :emqx_exhook,
  139. :emqx_bridge,
  140. :emqx_modules,
  141. :emqx_management,
  142. :emqx_statsd,
  143. :emqx_retainer,
  144. :emqx_prometheus,
  145. :emqx_auto_subscribe,
  146. :emqx_slow_subs,
  147. :emqx_plugins
  148. ],
  149. steps: steps,
  150. strip_beams: false
  151. ]
  152. end
  153. ]
  154. end
  155. def applications(edition_type) do
  156. [
  157. crypto: :permanent,
  158. public_key: :permanent,
  159. asn1: :permanent,
  160. syntax_tools: :permanent,
  161. ssl: :permanent,
  162. os_mon: :permanent,
  163. inets: :permanent,
  164. compiler: :permanent,
  165. runtime_tools: :permanent,
  166. redbug: :permanent,
  167. xmerl: :permanent,
  168. hocon: :load,
  169. emqx: :load,
  170. emqx_conf: :load,
  171. emqx_machine: :permanent
  172. ] ++
  173. if(enable_rocksdb?(),
  174. do: [mnesia_rocksdb: :load],
  175. else: []
  176. ) ++
  177. [
  178. mnesia: :load,
  179. ekka: :load,
  180. emqx_plugin_libs: :load,
  181. esasl: :load,
  182. observer_cli: :permanent,
  183. system_monitor: :load,
  184. emqx_http_lib: :permanent,
  185. emqx_resource: :permanent,
  186. emqx_connector: :permanent,
  187. emqx_authn: :permanent,
  188. emqx_authz: :permanent,
  189. emqx_auto_subscribe: :permanent,
  190. emqx_gateway: :permanent,
  191. emqx_exhook: :permanent,
  192. emqx_bridge: :permanent,
  193. emqx_rule_engine: :permanent,
  194. emqx_modules: :permanent,
  195. emqx_management: :permanent,
  196. emqx_dashboard: :permanent,
  197. emqx_retainer: :permanent,
  198. emqx_statsd: :permanent,
  199. emqx_prometheus: :permanent,
  200. emqx_psk: :permanent,
  201. emqx_slow_subs: :permanent,
  202. emqx_plugins: :permanent,
  203. emqx_mix: :none
  204. ] ++
  205. if(enable_quicer?(), do: [quicer: :permanent], else: []) ++
  206. if(enable_bcrypt?(), do: [bcrypt: :permanent], else: []) ++
  207. if(enable_jq?(), do: [jq: :permanent], else: []) ++
  208. if(is_app(:observer),
  209. do: [observer: :load],
  210. else: []
  211. ) ++
  212. if(edition_type == :enterprise,
  213. do: [
  214. emqx_license: :permanent,
  215. emqx_enterprise_conf: :load
  216. ],
  217. else: []
  218. )
  219. end
  220. defp is_app(name) do
  221. case Application.load(name) do
  222. :ok ->
  223. true
  224. {:error, {:already_loaded, _}} ->
  225. true
  226. _ ->
  227. false
  228. end
  229. end
  230. def check_profile!() do
  231. valid_envs = [
  232. :dev,
  233. :emqx,
  234. :"emqx-pkg",
  235. :"emqx-enterprise",
  236. :"emqx-enterprise-pkg"
  237. ]
  238. if Mix.env() not in valid_envs do
  239. formatted_envs =
  240. valid_envs
  241. |> Enum.map(&" * #{&1}")
  242. |> Enum.join("\n")
  243. Mix.raise("""
  244. Invalid env #{Mix.env()}. Valid options are:
  245. #{formatted_envs}
  246. """)
  247. end
  248. {
  249. release_type,
  250. package_type,
  251. edition_type
  252. } =
  253. case Mix.env() do
  254. :dev ->
  255. {:cloud, :bin, :community}
  256. :emqx ->
  257. {:cloud, :bin, :community}
  258. :"emqx-enterprise" ->
  259. {:cloud, :bin, :enterprise}
  260. :"emqx-pkg" ->
  261. {:cloud, :pkg, :community}
  262. :"emqx-enterprise-pkg" ->
  263. {:cloud, :pkg, :enterprise}
  264. end
  265. normalize_env!()
  266. %{
  267. release_type: release_type,
  268. package_type: package_type,
  269. edition_type: edition_type
  270. }
  271. end
  272. #############################################################################
  273. # Custom Steps
  274. #############################################################################
  275. defp make_docs(release) do
  276. profile = System.get_env("MIX_ENV")
  277. os_cmd("build", [profile, "docs"])
  278. release
  279. end
  280. defp copy_files(release, release_type, package_type, edition_type) do
  281. overwrite? = Keyword.get(release.options, :overwrite, false)
  282. bin = Path.join(release.path, "bin")
  283. etc = Path.join(release.path, "etc")
  284. log = Path.join(release.path, "log")
  285. Mix.Generator.create_directory(bin)
  286. Mix.Generator.create_directory(etc)
  287. Mix.Generator.create_directory(log)
  288. Mix.Generator.create_directory(Path.join(etc, "certs"))
  289. Enum.each(
  290. ["mnesia", "configs", "patches", "scripts"],
  291. fn dir ->
  292. path = Path.join([release.path, "data", dir])
  293. Mix.Generator.create_directory(path)
  294. end
  295. )
  296. Mix.Generator.copy_file(
  297. "apps/emqx_authz/etc/acl.conf",
  298. Path.join(etc, "acl.conf"),
  299. force: overwrite?
  300. )
  301. # required by emqx_authz
  302. File.cp_r!(
  303. "apps/emqx/etc/certs",
  304. Path.join(etc, "certs")
  305. )
  306. Mix.Generator.copy_file(
  307. "apps/emqx_dashboard/etc/emqx.conf.en.example",
  308. Path.join(etc, "emqx-example.conf"),
  309. force: overwrite?
  310. )
  311. # this is required by the produced escript / nodetool
  312. Mix.Generator.copy_file(
  313. Path.join(release.version_path, "start_clean.boot"),
  314. Path.join(bin, "no_dot_erlang.boot"),
  315. force: overwrite?
  316. )
  317. assigns = template_vars(release, release_type, package_type, edition_type)
  318. # This is generated by `scripts/merge-config.escript` or `make
  319. # conf-segs`. So, this should be run before the release.
  320. # TODO: run as a "compiler" step???
  321. render_template(
  322. "apps/emqx_conf/etc/emqx.conf.all",
  323. assigns,
  324. Path.join(etc, "emqx.conf")
  325. )
  326. if edition_type == :enterprise do
  327. render_template(
  328. "apps/emqx_conf/etc/emqx_enterprise.conf.all",
  329. assigns,
  330. Path.join(etc, "emqx_enterprise.conf")
  331. )
  332. end
  333. render_template(
  334. "rel/emqx_vars",
  335. assigns,
  336. Path.join([release.path, "releases", "emqx_vars"])
  337. )
  338. vm_args_template_path =
  339. case release_type do
  340. :cloud ->
  341. "apps/emqx/etc/vm.args.cloud"
  342. end
  343. render_template(
  344. vm_args_template_path,
  345. assigns,
  346. [
  347. Path.join(etc, "vm.args"),
  348. Path.join(release.version_path, "vm.args")
  349. ]
  350. )
  351. for name <- [
  352. "emqx",
  353. "emqx_ctl"
  354. ] do
  355. Mix.Generator.copy_file(
  356. "bin/#{name}",
  357. Path.join(bin, name),
  358. force: overwrite?
  359. )
  360. # Files with the version appended are expected by the release
  361. # upgrade script `install_upgrade.escript`
  362. Mix.Generator.copy_file(
  363. Path.join(bin, name),
  364. Path.join(bin, name <> "-#{release.version}"),
  365. force: overwrite?
  366. )
  367. end
  368. for base_name <- ["emqx", "emqx_ctl"],
  369. suffix <- ["", "-#{release.version}"] do
  370. name = base_name <> suffix
  371. File.chmod!(Path.join(bin, name), 0o755)
  372. end
  373. Mix.Generator.copy_file(
  374. "bin/node_dump",
  375. Path.join(bin, "node_dump"),
  376. force: overwrite?
  377. )
  378. File.chmod!(Path.join(bin, "node_dump"), 0o755)
  379. Mix.Generator.copy_file(
  380. "bin/emqx_cluster_rescue",
  381. Path.join(bin, "emqx_cluster_rescue"),
  382. force: overwrite?
  383. )
  384. File.chmod!(Path.join(bin, "emqx_cluster_rescue"), 0o755)
  385. render_template(
  386. "rel/BUILD_INFO",
  387. assigns,
  388. Path.join(release.version_path, "BUILD_INFO")
  389. )
  390. release
  391. end
  392. defp render_template(template, assigns, target) when is_binary(target) do
  393. render_template(template, assigns, [target])
  394. end
  395. defp render_template(template, assigns, tartgets) when is_list(tartgets) do
  396. rendered =
  397. File.read!(template)
  398. |> from_rebar_to_eex_template()
  399. |> EEx.eval_string(assigns)
  400. for target <- tartgets do
  401. File.write!(target, rendered)
  402. end
  403. end
  404. # needed by nodetool and by release_handler
  405. defp create_RELEASES(release) do
  406. apps =
  407. Enum.map(release.applications, fn {app_name, app_props} ->
  408. app_vsn = Keyword.fetch!(app_props, :vsn)
  409. app_path =
  410. "./lib"
  411. |> Path.join("#{app_name}-#{app_vsn}")
  412. |> to_charlist()
  413. {app_name, app_vsn, app_path}
  414. end)
  415. release_entry = [
  416. {
  417. :release,
  418. to_charlist(release.name),
  419. to_charlist(release.version),
  420. release.erts_version,
  421. apps,
  422. :permanent
  423. }
  424. ]
  425. release.path
  426. |> Path.join("releases")
  427. |> Path.join("RELEASES")
  428. |> File.open!([:write, :utf8], fn handle ->
  429. IO.puts(handle, "%% coding: utf-8")
  430. :io.format(handle, '~tp.~n', [release_entry])
  431. end)
  432. release
  433. end
  434. defp copy_escript(release, escript_name) do
  435. [shebang, rest] =
  436. "bin/#{escript_name}"
  437. |> File.read!()
  438. |> String.split("\n", parts: 2)
  439. # the elixir version of escript + start.boot required the boot_var
  440. # RELEASE_LIB to be defined.
  441. boot_var = "%%!-boot_var RELEASE_LIB $RUNNER_ROOT_DIR/lib"
  442. # Files with the version appended are expected by the release
  443. # upgrade script `install_upgrade.escript`
  444. Enum.each(
  445. [escript_name, escript_name <> "-" <> release.version],
  446. fn name ->
  447. path = Path.join([release.path, "bin", name])
  448. File.write!(path, [shebang, "\n", boot_var, "\n", rest])
  449. end
  450. )
  451. release
  452. end
  453. # The `:tar` built-in step in Mix Release does not currently add the
  454. # `etc` directory into the resulting tarball. The workaround is to
  455. # add those to the `:overlays` key before running `:tar`.
  456. # See: https://hexdocs.pm/mix/1.13.4/Mix.Release.html#__struct__/0
  457. defp prepare_tar_overlays(release) do
  458. Map.update!(
  459. release,
  460. :overlays,
  461. &[
  462. "etc",
  463. "data",
  464. "bin/node_dump"
  465. | &1
  466. ]
  467. )
  468. end
  469. #############################################################################
  470. # Helper functions
  471. #############################################################################
  472. defp template_vars(release, release_type, :bin = _package_type, edition_type) do
  473. [
  474. platform_data_dir: "data",
  475. platform_etc_dir: "etc",
  476. platform_log_dir: "log",
  477. platform_plugins_dir: "plugins",
  478. runner_bin_dir: "$RUNNER_ROOT_DIR/bin",
  479. emqx_etc_dir: "$RUNNER_ROOT_DIR/etc",
  480. runner_lib_dir: "$RUNNER_ROOT_DIR/lib",
  481. runner_log_dir: "$RUNNER_ROOT_DIR/log",
  482. runner_user: "",
  483. release_version: release.version,
  484. erts_vsn: release.erts_version,
  485. # FIXME: this is empty in `make emqx` ???
  486. erl_opts: "",
  487. emqx_description: emqx_description(release_type, edition_type),
  488. emqx_schema_mod: emqx_schema_mod(edition_type),
  489. is_elixir: "yes",
  490. is_enterprise: if(edition_type == :enterprise, do: "yes", else: "no")
  491. ] ++ build_info()
  492. end
  493. defp template_vars(release, release_type, :pkg = _package_type, edition_type) do
  494. [
  495. platform_data_dir: "/var/lib/emqx",
  496. platform_etc_dir: "/etc/emqx",
  497. platform_log_dir: "/var/log/emqx",
  498. platform_plugins_dir: "/var/lib/emqx/plugins",
  499. runner_bin_dir: "/usr/bin",
  500. emqx_etc_dir: "/etc/emqx",
  501. runner_lib_dir: "$RUNNER_ROOT_DIR/lib",
  502. runner_log_dir: "/var/log/emqx",
  503. runner_user: "emqx",
  504. release_version: release.version,
  505. erts_vsn: release.erts_version,
  506. # FIXME: this is empty in `make emqx` ???
  507. erl_opts: "",
  508. emqx_description: emqx_description(release_type, edition_type),
  509. emqx_schema_mod: emqx_schema_mod(edition_type),
  510. is_elixir: "yes",
  511. is_enterprise: if(edition_type == :enterprise, do: "yes", else: "no")
  512. ] ++ build_info()
  513. end
  514. defp emqx_description(release_type, edition_type) do
  515. case {release_type, edition_type} do
  516. {:cloud, :enterprise} ->
  517. "EMQX Enterprise"
  518. {:cloud, :community} ->
  519. "EMQX"
  520. end
  521. end
  522. defp emqx_schema_mod(:enterprise), do: :emqx_enterprise_conf_schema
  523. defp emqx_schema_mod(:community), do: :emqx_conf_schema
  524. defp bcrypt_dep() do
  525. if enable_bcrypt?(),
  526. do: [{:bcrypt, github: "emqx/erlang-bcrypt", tag: "0.6.0", override: true}],
  527. else: []
  528. end
  529. defp jq_dep() do
  530. if enable_jq?(),
  531. do: [{:jq, github: "emqx/jq", tag: "v0.3.5", override: true}],
  532. else: []
  533. end
  534. defp quicer_dep() do
  535. if enable_quicer?(),
  536. # in conflict with emqx and emqtt
  537. do: [{:quicer, github: "emqx/quic", tag: "0.0.16", override: true}],
  538. else: []
  539. end
  540. defp enable_bcrypt?() do
  541. not win32?()
  542. end
  543. defp enable_jq?() do
  544. not Enum.any?([
  545. build_without_jq?(),
  546. win32?()
  547. ]) or "1" == System.get_env("BUILD_WITH_JQ")
  548. end
  549. defp enable_quicer?() do
  550. not Enum.any?([
  551. build_without_quic?(),
  552. win32?(),
  553. centos6?(),
  554. macos?()
  555. ]) or "1" == System.get_env("BUILD_WITH_QUIC")
  556. end
  557. defp enable_rocksdb?() do
  558. not Enum.any?([
  559. build_without_rocksdb?(),
  560. raspbian?()
  561. ]) or "1" == System.get_env("BUILD_WITH_ROCKSDB")
  562. end
  563. defp pkg_vsn() do
  564. %{edition_type: edition_type} = check_profile!()
  565. basedir = Path.dirname(__ENV__.file)
  566. script = Path.join(basedir, "pkg-vsn.sh")
  567. os_cmd(script, [Atom.to_string(edition_type)])
  568. end
  569. defp os_cmd(script, args) do
  570. {str, 0} = System.cmd("bash", [script | args])
  571. String.trim(str)
  572. end
  573. defp win32?(),
  574. do: match?({:win_32, _}, :os.type())
  575. defp centos6?() do
  576. case File.read("/etc/centos-release") do
  577. {:ok, "CentOS release 6" <> _} ->
  578. true
  579. _ ->
  580. false
  581. end
  582. end
  583. defp macos?() do
  584. {:unix, :darwin} == :os.type()
  585. end
  586. defp raspbian?() do
  587. os_cmd("./scripts/get-distro.sh", []) =~ "raspbian"
  588. end
  589. defp build_without_jq?() do
  590. opt = System.get_env("BUILD_WITHOUT_JQ", "false")
  591. String.downcase(opt) != "false"
  592. end
  593. defp build_without_quic?() do
  594. opt = System.get_env("BUILD_WITHOUT_QUIC", "false")
  595. String.downcase(opt) != "false"
  596. end
  597. defp build_without_rocksdb?() do
  598. opt = System.get_env("BUILD_WITHOUT_ROCKSDB", "false")
  599. String.downcase(opt) != "false"
  600. end
  601. defp from_rebar_to_eex_template(str) do
  602. # we must not consider surrounding space in the template var name
  603. # because some help strings contain informative variables that
  604. # should not be interpolated, and those have no spaces.
  605. Regex.replace(
  606. ~r/\{\{ ([a-zA-Z0-9_]+) \}\}/,
  607. str,
  608. "<%= \\g{1} %>"
  609. )
  610. end
  611. defp build_info() do
  612. [
  613. build_info_arch: to_string(:erlang.system_info(:system_architecture)),
  614. build_info_wordsize: wordsize(),
  615. build_info_os: os_cmd("./scripts/get-distro.sh", []),
  616. build_info_erlang: otp_release(),
  617. build_info_elixir: System.version(),
  618. build_info_relform: System.get_env("EMQX_REL_FORM", "tgz")
  619. ]
  620. end
  621. # https://github.com/erlang/rebar3/blob/e3108ac187b88fff01eca6001a856283a3e0ec87/src/rebar_utils.erl#L142
  622. defp wordsize() do
  623. size =
  624. try do
  625. :erlang.system_info({:wordsize, :external})
  626. rescue
  627. ErlangError ->
  628. :erlang.system_info(:wordsize)
  629. end
  630. to_string(8 * size)
  631. end
  632. defp normalize_env!() do
  633. env =
  634. case Mix.env() do
  635. :dev ->
  636. :emqx
  637. env ->
  638. env
  639. end
  640. Mix.env(env)
  641. end
  642. # As from Erlang/OTP 17, the OTP release number corresponds to the
  643. # major OTP version number. No erlang:system_info() argument gives
  644. # the exact OTP version.
  645. # https://www.erlang.org/doc/man/erlang.html#system_info_otp_release
  646. # https://github.com/erlang/rebar3/blob/e3108ac187b88fff01eca6001a856283a3e0ec87/src/rebar_utils.erl#L572-L577
  647. defp otp_release() do
  648. major_version = System.otp_release()
  649. root_dir = to_string(:code.root_dir())
  650. [root_dir, "releases", major_version, "OTP_VERSION"]
  651. |> Path.join()
  652. |> File.read()
  653. |> case do
  654. {:error, _} ->
  655. major_version
  656. {:ok, version} ->
  657. version
  658. |> String.trim()
  659. |> String.split("**")
  660. |> List.first()
  661. end
  662. end
  663. end