mix.exs 21 KB

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