mix.exs 23 KB

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