| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376 |
- defmodule EMQXUmbrella.MixProject do
- use Mix.Project
- @moduledoc """
- The purpose of this file is to configure the release of EMQX under
- Mix. Since EMQX uses its own configuration conventions and startup
- procedures, one cannot simply use `iex -S mix`. Instead, it's
- recommended to build and use the release.
- ## Profiles
- To control the profile and edition to build, we case split on the
- MIX_ENV value.
- The following profiles are valid:
- * `emqx`
- * `emqx-enterprise`
- * `emqx-pkg`
- * `emqx-enterprise-pkg`
- * `dev` -> same as `emqx`, for convenience
- ## Release Environment Variables
- The release build is controlled by a few environment variables.
- * `ELIXIR_MAKE_TAR` - If set to `yes`, will produce a `.tar.gz`
- tarball along with the release.
- """
- # TODO: remove once we switch to the new mix build
- def new_mix_build?() do
- System.get_env("NEW_MIX_BUILD") == "1"
- end
- def project() do
- profile_info = check_profile!()
- version = pkg_vsn()
- if new_mix_build?() do
- [
- apps_path: "apps",
- erlc_options: erlc_options(profile_info, version),
- version: version,
- deps: deps(profile_info, version),
- releases: releases(),
- aliases: aliases()
- ]
- else
- # TODO: this check and clause will be removed when we switch to using mix as the
- # manager for all umbrella apps.
- [
- app: :emqx_mix,
- erlc_options: erlc_options(profile_info, version),
- version: version,
- deps: deps(profile_info, version),
- releases: releases(),
- aliases: aliases()
- ]
- end
- end
- @doc """
- Please try to add dependencies that used by a single umbrella application in the
- application's own `mix.exs` file, if possible. If it's shared by more than one
- application, or if the dependency requires an `override: true` option, add a new clause
- to `common_dep/1` so that we centralize versions in this root `mix.exs` file as much as
- possible.
- Here, transitive dependencies from our app dependencies should be placed when there's a
- need to override them. For example, since `jsone` is a dependency to `rocketmq` and to
- `erlavro`, which are both dependencies and not umbrella apps, we need to add the
- override here. Also, there are cases where adding `override: true` to the umbrella
- application dependency simply won't satisfy mix. In such cases, it's fine to add it
- here.
- """
- def deps(profile_info, version) do
- # we need several overrides here because dependencies specify
- # other exact versions, and not ranges.
- if new_mix_build?() do
- new_deps()
- else
- old_deps(profile_info, version)
- end
- end
- def new_deps() do
- common_deps() ++
- quicer_dep() ++
- jq_dep() ++
- extra_release_apps() ++
- overridden_deps()
- end
- ## TODO: this should be removed once we migrate the release build to mix
- defp old_deps(profile_info, version) do
- rebar3_umbrella_apps = emqx_apps(profile_info, version) ++ enterprise_deps(profile_info)
- common_deps() ++
- extra_release_apps() ++
- overridden_deps() ++
- jq_dep() ++
- quicer_dep() ++ rebar3_umbrella_apps
- end
- def overridden_deps() do
- [
- common_dep(:lc),
- common_dep(:typerefl),
- common_dep(:ehttpc),
- common_dep(:gproc),
- common_dep(:jiffy),
- common_dep(:cowboy),
- common_dep(:esockd),
- common_dep(:rocksdb),
- common_dep(:ekka),
- common_dep(:gen_rpc),
- common_dep(:grpc),
- common_dep(:minirest),
- common_dep(:ecpool),
- common_dep(:replayq),
- common_dep(:pbkdf2),
- # maybe forbid to fetch quicer
- common_dep(:emqtt),
- common_dep(:rulesql),
- common_dep(:telemetry),
- # in conflict by emqtt and hocon
- common_dep(:getopt),
- common_dep(:snabbkaffe),
- common_dep(:hocon),
- common_dep(:emqx_http_lib),
- common_dep(:jose),
- # in conflict by ehttpc and emqtt
- common_dep(:gun),
- # in conflict by emqx_connector and system_monitor
- common_dep(:epgsql),
- # in conflict by emqx and observer_cli
- {:recon, github: "ferd/recon", tag: "2.5.1", override: true},
- common_dep(:jsx),
- # in conflict by erlavro and rocketmq
- common_dep(:jsone),
- # dependencies of dependencies; we choose specific refs to match
- # what rebar3 chooses.
- # in conflict by gun and emqtt
- common_dep(:cowlib),
- # in conflict by cowboy_swagger and cowboy
- common_dep(:ranch),
- # in conflict by grpc and eetcd
- common_dep(:gpb),
- {:hackney, github: "emqx/hackney", tag: "1.18.1-1", override: true},
- # set by hackney (dependency)
- {:ssl_verify_fun, "1.1.7", override: true},
- common_dep(:rfc3339),
- common_dep(:bcrypt),
- common_dep(:uuid),
- {:quickrand, github: "okeuday/quickrand", tag: "v2.0.6", override: true},
- common_dep(:ra),
- {:mimerl, "1.2.0", override: true},
- common_dep(:sasl_auth),
- # avlizer currently uses older :erlavro version
- common_dep(:erlavro),
- common_dep(:crc32cer)
- ]
- end
- def extra_release_apps() do
- [
- common_dep(:redbug),
- common_dep(:observer_cli),
- common_dep(:system_monitor)
- ]
- end
- def common_dep(dep_name, overrides) do
- case common_dep(dep_name) do
- {^dep_name, opts} ->
- {dep_name, Keyword.merge(opts, overrides)}
- {^dep_name, tag, opts} when is_binary(tag) ->
- {dep_name, tag, Keyword.merge(opts, overrides)}
- end
- end
- def common_dep(:ekka), do: {:ekka, github: "emqx/ekka", tag: "0.19.6", override: true}
- def common_dep(:esockd), do: {:esockd, github: "emqx/esockd", tag: "5.12.0", override: true}
- def common_dep(:gproc), do: {:gproc, github: "emqx/gproc", tag: "0.9.0.1", override: true}
- def common_dep(:hocon), do: {:hocon, github: "emqx/hocon", tag: "0.43.4", override: true}
- def common_dep(:lc), do: {:lc, github: "emqx/lc", tag: "0.3.2", override: true}
- # in conflict by ehttpc and emqtt
- def common_dep(:gun), do: {:gun, github: "emqx/gun", tag: "1.3.11", override: true}
- # in conflict by cowboy_swagger and cowboy
- def common_dep(:ranch), do: {:ranch, github: "emqx/ranch", tag: "1.8.1-emqx", override: true}
- def common_dep(:ehttpc),
- do: {:ehttpc, github: "emqx/ehttpc", tag: "0.5.0", override: true}
- def common_dep(:jiffy), do: {:jiffy, github: "emqx/jiffy", tag: "1.0.6", override: true}
- def common_dep(:grpc),
- do:
- {:grpc,
- github: "emqx/grpc-erl", tag: "0.6.12", override: true, system_env: emqx_app_system_env()}
- def common_dep(:cowboy), do: {:cowboy, github: "emqx/cowboy", tag: "2.9.2", override: true}
- def common_dep(:jsone), do: {:jsone, github: "emqx/jsone", tag: "1.7.1", override: true}
- def common_dep(:ecpool), do: {:ecpool, github: "emqx/ecpool", tag: "0.5.10", override: true}
- def common_dep(:replayq), do: {:replayq, github: "emqx/replayq", tag: "0.3.8", override: true}
- def common_dep(:jsx), do: {:jsx, github: "talentdeficit/jsx", tag: "v3.1.0", override: true}
- # in conflict by emqtt and hocon
- def common_dep(:getopt), do: {:getopt, "1.0.2", override: true}
- def common_dep(:telemetry), do: {:telemetry, "1.1.0", override: true}
- # in conflict by grpc and eetcd
- def common_dep(:gpb), do: {:gpb, "4.19.9", override: true, runtime: false}
- def common_dep(:ra), do: {:ra, github: "emqx/ra", tag: "v2.14.0-emqx-1", override: true}
- # in conflict by emqx_connector and system_monitor
- def common_dep(:epgsql), do: {:epgsql, github: "emqx/epgsql", tag: "4.7.1.3", override: true}
- def common_dep(:sasl_auth), do: {:sasl_auth, "2.3.3", override: true}
- def common_dep(:gen_rpc), do: {:gen_rpc, github: "emqx/gen_rpc", tag: "3.4.0", override: true}
- def common_dep(:system_monitor),
- do: {:system_monitor, github: "ieQu1/system_monitor", tag: "3.0.5"}
- def common_dep(:uuid), do: {:uuid, github: "okeuday/uuid", tag: "v2.0.6", override: true}
- def common_dep(:redbug), do: {:redbug, github: "emqx/redbug", tag: "2.0.10"}
- def common_dep(:observer_cli), do: {:observer_cli, "1.7.5"}
- def common_dep(:jose),
- do: {:jose, github: "potatosalad/erlang-jose", tag: "1.11.2", override: true}
- def common_dep(:rulesql), do: {:rulesql, github: "emqx/rulesql", tag: "0.2.1"}
- def common_dep(:pbkdf2),
- do: {:pbkdf2, github: "emqx/erlang-pbkdf2", tag: "2.0.4", override: true}
- def common_dep(:bcrypt),
- do: {:bcrypt, github: "emqx/erlang-bcrypt", tag: "0.6.2", override: true}
- # hex version 0.2.2 used by `jesse` has buggy mix.exs
- def common_dep(:rfc3339), do: {:rfc3339, github: "emqx/rfc3339", tag: "0.2.3", override: true}
- def common_dep(:minirest),
- do: {:minirest, github: "emqx/minirest", tag: "1.4.3", override: true}
- # maybe forbid to fetch quicer
- def common_dep(:emqtt),
- do:
- {:emqtt,
- github: "emqx/emqtt", tag: "1.13.0", override: true, system_env: maybe_no_quic_env()}
- def common_dep(:typerefl),
- do: {:typerefl, github: "ieQu1/typerefl", tag: "0.9.1", override: true}
- def common_dep(:rocksdb),
- do: {:rocksdb, github: "emqx/erlang-rocksdb", tag: "1.8.0-emqx-6", override: true}
- def common_dep(:emqx_http_lib),
- do: {:emqx_http_lib, github: "emqx/emqx_http_lib", tag: "0.5.3", override: true}
- def common_dep(:cowlib),
- do:
- {:cowlib,
- github: "ninenines/cowlib", ref: "c6553f8308a2ca5dcd69d845f0a7d098c40c3363", override: true}
- def common_dep(:snabbkaffe),
- do: {
- :snabbkaffe,
- ## without this, snabbkaffe is compiled with `-define(snk_kind, '$kind')`, which
- ## will basically make events in tests never match any predicates.
- github: "kafka4beam/snabbkaffe",
- tag: "1.0.10",
- override: true,
- system_env: emqx_app_system_env()
- }
- def common_dep(:influxdb),
- do: {:influxdb, github: "emqx/influxdb-client-erl", tag: "1.1.13", override: true}
- def common_dep(:wolff), do: {:wolff, "4.0.0"}
- def common_dep(:brod_gssapi), do: {:brod_gssapi, "0.1.3"}
- def common_dep(:kafka_protocol),
- do: {:kafka_protocol, "4.1.8", override: true}
- def common_dep(:brod), do: {:brod, github: "kafka4beam/brod", tag: "3.18.0"}
- ## TODO: remove `mix.exs` from `wolff` and remove this override
- ## TODO: remove `mix.exs` from `pulsar` and remove this override
- def common_dep(:snappyer), do: {:snappyer, "1.2.9", override: true}
- def common_dep(:crc32cer), do: {:crc32cer, "0.1.8", override: true}
- def common_dep(:jesse), do: {:jesse, github: "emqx/jesse", tag: "1.8.0.1"}
- def common_dep(:erlavro), do: {:erlavro, github: "emqx/erlavro", tag: "2.10.0", override: true}
- ###############################################################################################
- # BEGIN DEPRECATED FOR MIX BLOCK
- # These should be removed once we fully migrate to mix
- ###############################################################################################
- defp emqx_apps(profile_info, version) do
- apps = umbrella_apps(profile_info) ++ enterprise_apps(profile_info)
- set_emqx_app_system_env(apps, profile_info, version)
- end
- defp umbrella_apps(profile_info = %{release_type: release_type}) do
- enterprise_apps = enterprise_umbrella_apps(release_type)
- excluded_apps = excluded_apps(release_type)
- "apps/*"
- |> Path.wildcard()
- |> Enum.map(fn path ->
- app =
- path
- |> Path.basename()
- |> String.to_atom()
- {app, path: path, manager: :rebar3, override: true}
- end)
- |> Enum.reject(fn dep_spec ->
- dep_spec
- |> elem(0)
- |> then(&MapSet.member?(enterprise_apps, &1))
- end)
- |> Enum.reject(fn {app, _} ->
- case profile_info do
- %{edition_type: :enterprise} ->
- app == :emqx_telemetry
- _ ->
- false
- end
- end)
- |> Enum.reject(fn {app, _} -> app == :emqx_mix_utils end)
- |> Enum.reject(fn {app, _} -> app in excluded_apps end)
- end
- defp enterprise_apps(_profile_info = %{release_type: release_type, edition_type: :enterprise}) do
- Enum.map(enterprise_umbrella_apps(release_type), fn app_name ->
- path = "apps/#{app_name}"
- {app_name, path: path, manager: :rebar3, override: true}
- end)
- end
- defp enterprise_apps(_profile_info) do
- []
- end
- # need to remove those when listing `/apps/`...
- defp enterprise_umbrella_apps(_release_type) do
- MapSet.new([
- :emqx_connector_aggregator,
- :emqx_bridge_kafka,
- :emqx_bridge_confluent,
- :emqx_bridge_gcp_pubsub,
- :emqx_bridge_cassandra,
- :emqx_bridge_opents,
- :emqx_bridge_dynamo,
- :emqx_bridge_greptimedb,
- :emqx_bridge_hstreamdb,
- :emqx_bridge_influxdb,
- :emqx_bridge_iotdb,
- :emqx_bridge_es,
- :emqx_bridge_matrix,
- :emqx_bridge_mongodb,
- :emqx_bridge_mysql,
- :emqx_bridge_pgsql,
- :emqx_bridge_redis,
- :emqx_bridge_rocketmq,
- :emqx_bridge_tdengine,
- :emqx_bridge_timescale,
- :emqx_bridge_sqlserver,
- :emqx_bridge_pulsar,
- :emqx_oracle,
- :emqx_bridge_oracle,
- :emqx_bridge_rabbitmq,
- :emqx_bridge_clickhouse,
- :emqx_ft,
- :emqx_license,
- :emqx_s3,
- :emqx_bridge_s3,
- :emqx_bridge_azure_blob_storage,
- :emqx_bridge_couchbase,
- :emqx_bridge_snowflake,
- :emqx_schema_registry,
- :emqx_schema_validation,
- :emqx_message_transformation,
- :emqx_enterprise,
- :emqx_bridge_kinesis,
- :emqx_bridge_azure_event_hub,
- :emqx_gcp_device,
- :emqx_dashboard_rbac,
- :emqx_dashboard_sso,
- :emqx_audit,
- :emqx_gateway_gbt32960,
- :emqx_gateway_ocpp,
- :emqx_gateway_jt808,
- :emqx_bridge_syskeeper,
- :emqx_ds_shared_sub,
- :emqx_auth_ext,
- :emqx_cluster_link,
- :emqx_ds_builtin_raft,
- :emqx_auth_kerberos,
- :emqx_bridge_datalayers,
- :emqx_auth_cinfo
- ])
- end
- defp enterprise_deps(_profile_info = %{edition_type: :enterprise}) do
- [
- {:hstreamdb_erl,
- github: "hstreamdb/hstreamdb_erl", tag: "0.5.18+v0.18.1+ezstd-v1.0.5-emqx1"},
- common_dep(:influxdb),
- common_dep(:wolff),
- common_dep(:kafka_protocol),
- common_dep(:brod_gssapi),
- common_dep(:brod),
- common_dep(:snappyer),
- common_dep(:crc32cer),
- {:opentsdb, github: "emqx/opentsdb-client-erl", tag: "v0.5.1", override: true},
- {:greptimedb,
- github: "GreptimeTeam/greptimedb-ingester-erl", tag: "v0.1.8", override: true},
- # The following two are dependencies of rabbit_common. They are needed here to
- # make mix not complain about conflicting versions
- {:thoas, github: "emqx/thoas", tag: "v1.0.0", override: true},
- {:credentials_obfuscation,
- github: "emqx/credentials-obfuscation", tag: "v3.2.0", override: true},
- {:rabbit_common,
- github: "emqx/rabbitmq-server",
- tag: "v3.11.13.2",
- sparse: "deps/rabbit_common",
- override: true},
- {:amqp_client,
- github: "emqx/rabbitmq-server",
- tag: "v3.11.13.2",
- sparse: "deps/amqp_client",
- override: true}
- ]
- end
- defp enterprise_deps(_profile_info) do
- []
- end
- defp set_emqx_app_system_env(apps, profile_info, version) do
- system_env = emqx_app_system_env(profile_info, version) ++ maybe_no_quic_env()
- Enum.map(
- apps,
- fn {app, opts} ->
- {app,
- Keyword.update(
- opts,
- :system_env,
- system_env,
- &Keyword.merge(&1, system_env)
- )}
- end
- )
- end
- def emqx_app_system_env(profile_info, version) do
- erlc_options(profile_info, version)
- |> dump_as_erl()
- |> then(&[{"ERL_COMPILER_OPTIONS", &1}])
- end
- def emqx_app_system_env() do
- k = {__MODULE__, :emqx_app_system_env}
- get_memoized(k, fn ->
- emqx_app_system_env(profile_info(), pkg_vsn())
- end)
- end
- ###############################################################################################
- # END DEPRECATED FOR MIX BLOCK
- ###############################################################################################
- defp erlc_options(%{edition_type: edition_type}, version) do
- [
- :debug_info,
- {:compile_info, [{:emqx_vsn, String.to_charlist(version)}]},
- {:d, :EMQX_RELEASE_EDITION, erlang_edition(edition_type)},
- {:d, :EMQX_ELIXIR},
- {:d, :snk_kind, :msg}
- ] ++
- singleton(test_env?(), {:d, :TEST}) ++
- singleton(not enable_quicer?(), {:d, :BUILD_WITHOUT_QUIC}) ++
- singleton(store_state_in_ds?(), {:d, :STORE_STATE_IN_DS, true})
- end
- defp store_state_in_ds?() do
- "1" == System.get_env("STORE_STATE_IN_DS")
- end
- defp singleton(false, _value), do: []
- defp singleton(true, value), do: [value]
- def profile_info() do
- k = {__MODULE__, :profile_info}
- get_memoized(k, &check_profile!/0)
- end
- def pkg_vsn() do
- k = {__MODULE__, :pkg_vsn}
- get_memoized(k, &do_pkg_vsn/0)
- end
- def common_deps() do
- if test_env?() do
- [
- {:bbmustache, "1.10.0"},
- {:cth_readable, "1.5.1"},
- {:proper, "1.4.0"},
- {:meck, "0.9.2"}
- ]
- else
- []
- end
- end
- def extra_applications() do
- k = {__MODULE__, :extra_applications}
- get_memoized(k, fn ->
- if test_env?() do
- [:eunit, :common_test, :dialyzer, :mnesia]
- else
- []
- end
- end)
- end
- def erlc_paths() do
- k = {__MODULE__, :erlc_paths}
- get_memoized(k, fn ->
- if test_env?() do
- ["src", "test"]
- else
- ["src"]
- end
- end)
- end
- def erlc_options() do
- k = {__MODULE__, :erlc_options}
- get_memoized(k, fn ->
- profile_info = profile_info()
- version = pkg_vsn()
- erlc_options(profile_info, version)
- end)
- end
- def test_env?() do
- k = {__MODULE__, :test_env?}
- get_memoized(k, fn ->
- env = to_string(Mix.env())
- System.get_env("TEST") == "1" || env =~ ~r/-test$/
- end)
- end
- defp set_test_env!(test_env?) do
- k = {__MODULE__, :test_env?}
- :persistent_term.put(k, test_env?)
- end
- defp get_memoized(k, compute_fn) do
- case :persistent_term.get(k, :undefined) do
- :undefined ->
- res = compute_fn.()
- :persistent_term.put(k, res)
- res
- res ->
- res
- end
- end
- def maybe_no_quic_env() do
- if not enable_quicer?() do
- [{"BUILD_WITHOUT_QUIC", "true"}]
- else
- []
- end
- end
- defp releases() do
- [
- emqx: fn ->
- %{
- release_type: release_type,
- package_type: package_type,
- edition_type: edition_type
- } = check_profile!()
- base_steps = [
- &merge_config/1,
- &make_docs/1,
- :assemble,
- &create_RELEASES/1,
- ©_files(&1, release_type, package_type, edition_type),
- ©_escript(&1, "nodetool"),
- ©_escript(&1, "install_upgrade.escript")
- ]
- steps =
- if System.get_env("ELIXIR_MAKE_TAR") == "yes" do
- base_steps ++ [&prepare_tar_overlays/1, :tar]
- else
- base_steps
- end
- [
- applications: applications(release_type, edition_type),
- skip_mode_validation_for: [
- :emqx_mix,
- :emqx_machine,
- :emqx_gateway,
- :emqx_gateway_stomp,
- :emqx_gateway_mqttsn,
- :emqx_gateway_coap,
- :emqx_gateway_lwm2m,
- :emqx_gateway_exproto,
- :emqx_dashboard,
- :emqx_dashboard_sso,
- :emqx_audit,
- :emqx_resource,
- :emqx_connector,
- :emqx_exhook,
- :emqx_bridge,
- :emqx_bridge_mqtt,
- :emqx_modules,
- :emqx_management,
- :emqx_retainer,
- :emqx_prometheus,
- :emqx_rule_engine,
- :emqx_auto_subscribe,
- :emqx_slow_subs,
- :emqx_plugins,
- :emqx_ft,
- :emqx_s3,
- :emqx_opentelemetry,
- :emqx_durable_storage,
- :emqx_ds_builtin_local,
- :emqx_ds_builtin_raft,
- :rabbit_common,
- :emqx_eviction_agent,
- :emqx_node_rebalance
- ],
- steps: steps,
- strip_beams: false
- ]
- end
- ]
- end
- def applications(release_type, edition_type) do
- {:ok,
- [
- %{
- db_apps: db_apps,
- system_apps: system_apps,
- common_business_apps: common_business_apps,
- ee_business_apps: ee_business_apps,
- ce_business_apps: ce_business_apps
- }
- ]} = :file.consult("apps/emqx_machine/priv/reboot_lists.eterm")
- edition_specific_apps =
- if edition_type == :enterprise do
- ee_business_apps
- else
- ce_business_apps
- end
- business_apps = common_business_apps ++ edition_specific_apps
- excluded_apps = excluded_apps(release_type)
- system_apps =
- Enum.map(system_apps, fn app ->
- if is_atom(app), do: {app, :permanent}, else: app
- end)
- db_apps = Enum.map(db_apps, &{&1, :load})
- business_apps = Enum.map(business_apps, &{&1, :load})
- [system_apps, db_apps, [emqx_ctl: :permanent, emqx_machine: :permanent], business_apps]
- |> List.flatten()
- |> Keyword.reject(fn {app, _type} ->
- app in excluded_apps ||
- (edition_type == :enterprise && app == :emqx_telemetry)
- end)
- end
- defp excluded_apps(_release_type) do
- %{
- mnesia_rocksdb: enable_rocksdb?(),
- quicer: enable_quicer?(),
- jq: enable_jq?(),
- observer: is_app?(:observer)
- }
- |> Enum.reject(&elem(&1, 1))
- |> Enum.map(&elem(&1, 0))
- end
- defp is_app?(name) do
- case Application.load(name) do
- :ok ->
- true
- {:error, {:already_loaded, _}} ->
- true
- _ ->
- false
- end
- end
- def check_profile!() do
- valid_envs = [
- :emqx,
- :"emqx-test",
- :"emqx-pkg",
- :"emqx-enterprise",
- :"emqx-enterprise-test",
- :"emqx-enterprise-pkg"
- ]
- if Mix.env() == :dev do
- env_profile = System.get_env("PROFILE")
- if env_profile do
- # copy from PROFILE env var
- System.get_env("PROFILE")
- |> String.to_atom()
- |> Mix.env()
- else
- Mix.shell().info([
- :yellow,
- "Warning: env var PROFILE is unset; defaulting to emqx"
- ])
- Mix.env(:emqx)
- end
- end
- if Mix.env() not in valid_envs do
- formatted_envs =
- valid_envs
- |> Enum.map(&" * #{&1}")
- |> Enum.join("\n")
- Mix.raise("""
- Invalid env #{Mix.env()}. Valid options are:
- #{formatted_envs}
- """)
- end
- mix_env = Mix.env()
- {
- release_type,
- package_type,
- edition_type
- } =
- case mix_env do
- :dev ->
- {:standard, :bin, :community}
- :emqx ->
- {:standard, :bin, :community}
- :"emqx-test" ->
- {:standard, :bin, :community}
- :"emqx-enterprise" ->
- {:standard, :bin, :enterprise}
- :"emqx-enterprise-test" ->
- {:standard, :bin, :enterprise}
- :"emqx-pkg" ->
- {:standard, :pkg, :community}
- :"emqx-enterprise-pkg" ->
- {:standard, :pkg, :enterprise}
- end
- test? = to_string(mix_env) =~ ~r/-test$/ || test_env?()
- normalize_env!(test?)
- # Mix.debug(true)
- if Mix.debug?() do
- Mix.shell().info([
- :blue,
- "mix_env: #{Mix.env()}",
- "; release type: #{release_type}",
- "; package type: #{package_type}",
- "; edition type: #{edition_type}",
- "; test env?: #{test?}"
- ])
- end
- test? = to_string(mix_env) =~ ~r/-test$/ || test_env?()
- normalize_env!(test?)
- # Mix.debug(true)
- if Mix.debug?() do
- Mix.shell().info([
- :blue,
- "mix_env: #{Mix.env()}",
- "; release type: #{release_type}",
- "; package type: #{package_type}",
- "; edition type: #{edition_type}",
- "; test env?: #{test?}"
- ])
- end
- %{
- release_type: release_type,
- package_type: package_type,
- edition_type: edition_type,
- test?: test?
- }
- end
- #############################################################################
- # Custom Steps
- #############################################################################
- # Gathers i18n files and merge them before producing docs and schemas.
- defp merge_config(release) do
- {_, 0} = System.cmd("bash", ["-c", "./scripts/merge-config.escript"])
- release
- end
- defp make_docs(release) do
- profile = System.get_env("MIX_ENV")
- os_cmd("build", [profile, "docs"])
- release
- end
- defp copy_files(release, release_type, package_type, edition_type) do
- overwrite? = Keyword.get(release.options, :overwrite, false)
- bin = Path.join(release.path, "bin")
- etc = Path.join(release.path, "etc")
- log = Path.join(release.path, "log")
- plugins = Path.join(release.path, "plugins")
- Mix.Generator.create_directory(bin)
- Mix.Generator.create_directory(etc)
- Mix.Generator.create_directory(log)
- Mix.Generator.create_directory(plugins)
- Mix.Generator.create_directory(Path.join(etc, "certs"))
- Enum.each(
- ["mnesia", "configs", "patches", "scripts"],
- fn dir ->
- path = Path.join([release.path, "data", dir])
- Mix.Generator.create_directory(path)
- end
- )
- Mix.Generator.copy_file(
- "apps/emqx_auth/etc/acl.conf",
- Path.join(etc, "acl.conf"),
- force: overwrite?
- )
- # required by emqx_auth
- File.cp_r!(
- "apps/emqx/etc/certs",
- Path.join(etc, "certs")
- )
- profile = System.get_env("MIX_ENV")
- File.cp_r!(
- "rel/config/examples",
- Path.join(etc, "examples"),
- force: overwrite?
- )
- # copy /rel/config/ee-examples if profile is enterprise
- case profile do
- "emqx-enterprise" ->
- File.cp_r!(
- "rel/config/ee-examples",
- Path.join(etc, "examples"),
- force: overwrite?
- )
- _ ->
- :ok
- end
- # this is required by the produced escript / nodetool
- Mix.Generator.copy_file(
- Path.join(release.version_path, "start_clean.boot"),
- Path.join(bin, "no_dot_erlang.boot"),
- force: overwrite?
- )
- assigns = template_vars(release, release_type, package_type, edition_type)
- # This is generated by `scripts/merge-config.escript` or `make merge-config`
- # So, this should be run before the release.
- # TODO: run as a "compiler" step???
- render_template(
- "apps/emqx_conf/etc/emqx.conf.all",
- assigns,
- Path.join(etc, "emqx.conf")
- )
- render_template(
- "rel/emqx_vars",
- assigns,
- Path.join([release.path, "releases", "emqx_vars"])
- )
- vm_args_template_path =
- case release_type do
- _ ->
- "apps/emqx/etc/vm.args.cloud"
- end
- render_template(
- vm_args_template_path,
- assigns,
- [
- Path.join(etc, "vm.args"),
- Path.join(release.version_path, "vm.args")
- ]
- )
- for name <- [
- "emqx",
- "emqx_ctl"
- ] do
- Mix.Generator.copy_file(
- "bin/#{name}",
- Path.join(bin, name),
- force: overwrite?
- )
- # Files with the version appended are expected by the release
- # upgrade script `install_upgrade.escript`
- Mix.Generator.copy_file(
- Path.join(bin, name),
- Path.join(bin, name <> "-#{release.version}"),
- force: overwrite?
- )
- end
- for base_name <- ["emqx", "emqx_ctl"],
- suffix <- ["", "-#{release.version}"] do
- name = base_name <> suffix
- File.chmod!(Path.join(bin, name), 0o755)
- end
- Mix.Generator.copy_file(
- "bin/node_dump",
- Path.join(bin, "node_dump"),
- force: overwrite?
- )
- File.chmod!(Path.join(bin, "node_dump"), 0o755)
- Mix.Generator.copy_file(
- "bin/emqx_cluster_rescue",
- Path.join(bin, "emqx_cluster_rescue"),
- force: overwrite?
- )
- File.chmod!(Path.join(bin, "emqx_cluster_rescue"), 0o755)
- render_template(
- "rel/BUILD_INFO",
- assigns,
- Path.join(release.version_path, "BUILD_INFO")
- )
- release
- end
- defp render_template(template, assigns, target) when is_binary(target) do
- render_template(template, assigns, [target])
- end
- defp render_template(template, assigns, tartgets) when is_list(tartgets) do
- rendered =
- File.read!(template)
- |> from_rebar_to_eex_template()
- |> EEx.eval_string(assigns)
- for target <- tartgets do
- File.write!(target, rendered)
- end
- end
- # needed by nodetool and by release_handler
- defp create_RELEASES(release) do
- apps =
- Enum.map(release.applications, fn {app_name, app_props} ->
- app_vsn = Keyword.fetch!(app_props, :vsn)
- app_path =
- "./lib"
- |> Path.join("#{app_name}-#{app_vsn}")
- |> to_charlist()
- {app_name, app_vsn, app_path}
- end)
- release_entry = [
- {
- :release,
- to_charlist(release.name),
- to_charlist(release.version),
- release.erts_version,
- apps,
- :permanent
- }
- ]
- release.path
- |> Path.join("releases")
- |> Path.join("RELEASES")
- |> File.open!([:write, :utf8], fn handle ->
- IO.puts(handle, "%% coding: utf-8")
- :io.format(handle, ~c"~tp.~n", [release_entry])
- end)
- release
- end
- defp copy_escript(release, escript_name) do
- [shebang, rest] =
- "bin/#{escript_name}"
- |> File.read!()
- |> String.split("\n", parts: 2)
- # the elixir version of escript + start.boot required the boot_var
- # RELEASE_LIB to be defined.
- # enable-feature is not required when 1.6.x
- boot_var = "%%!-boot_var RELEASE_LIB $RUNNER_ROOT_DIR/lib -enable-feature maybe_expr"
- # Files with the version appended are expected by the release
- # upgrade script `install_upgrade.escript`
- Enum.each(
- [escript_name, escript_name <> "-" <> release.version],
- fn name ->
- path = Path.join([release.path, "bin", name])
- File.write!(path, [shebang, "\n", boot_var, "\n", rest])
- end
- )
- release
- end
- # The `:tar` built-in step in Mix Release does not currently add the
- # `etc` directory into the resulting tarball. The workaround is to
- # add those to the `:overlays` key before running `:tar`.
- # See: https://hexdocs.pm/mix/1.13.4/Mix.Release.html#__struct__/0
- defp prepare_tar_overlays(release) do
- Map.update!(
- release,
- :overlays,
- &[
- "etc",
- "data",
- "plugins",
- "bin/node_dump"
- | &1
- ]
- )
- end
- #############################################################################
- # Helper functions
- #############################################################################
- defp template_vars(release, release_type, :bin = _package_type, edition_type) do
- [
- emqx_default_erlang_cookie: default_cookie(),
- emqx_configuration_doc: emqx_configuration_doc(edition_type, :root),
- emqx_configuration_doc_log: emqx_configuration_doc(edition_type, :log),
- platform_data_dir: "data",
- platform_etc_dir: "etc",
- platform_plugins_dir: "plugins",
- runner_bin_dir: "$RUNNER_ROOT_DIR/bin",
- emqx_etc_dir: "$RUNNER_ROOT_DIR/etc",
- runner_lib_dir: "$RUNNER_ROOT_DIR/lib",
- runner_log_dir: "$RUNNER_ROOT_DIR/log",
- runner_user: "",
- release_version: release.version,
- erts_vsn: release.erts_version,
- # FIXME: this is empty in `make emqx` ???
- erl_opts: "",
- emqx_description: emqx_description(release_type, edition_type),
- emqx_schema_mod: emqx_schema_mod(edition_type),
- is_elixir: "yes",
- is_enterprise: if(edition_type == :enterprise, do: "yes", else: "no")
- ] ++ build_info()
- end
- defp template_vars(release, release_type, :pkg = _package_type, edition_type) do
- [
- emqx_default_erlang_cookie: default_cookie(),
- emqx_configuration_doc: emqx_configuration_doc(edition_type, :root),
- emqx_configuration_doc_log: emqx_configuration_doc(edition_type, :log),
- platform_data_dir: "/var/lib/emqx",
- platform_etc_dir: "/etc/emqx",
- platform_plugins_dir: "/var/lib/emqx/plugins",
- runner_bin_dir: "/usr/bin",
- emqx_etc_dir: "/etc/emqx",
- runner_lib_dir: "$RUNNER_ROOT_DIR/lib",
- runner_log_dir: "/var/log/emqx",
- runner_user: "emqx",
- release_version: release.version,
- erts_vsn: release.erts_version,
- # FIXME: this is empty in `make emqx` ???
- erl_opts: "",
- emqx_description: emqx_description(release_type, edition_type),
- emqx_schema_mod: emqx_schema_mod(edition_type),
- is_elixir: "yes",
- is_enterprise: if(edition_type == :enterprise, do: "yes", else: "no")
- ] ++ build_info()
- end
- defp default_cookie() do
- "emqx50elixir"
- end
- defp emqx_description(release_type, edition_type) do
- case {release_type, edition_type} do
- {_, :enterprise} ->
- "EMQX Enterprise"
- {_, :community} ->
- "EMQX"
- end
- end
- defp emqx_configuration_doc(:enterprise, :root),
- do: "https://docs.emqx.com/en/enterprise/latest/configuration/configuration.html"
- defp emqx_configuration_doc(:enterprise, :log),
- do: "https://docs.emqx.com/en/enterprise/latest/configuration/logs.html"
- defp emqx_configuration_doc(:community, :root),
- do: "https://www.emqx.io/docs/en/latest/configuration/configuration.html"
- defp emqx_configuration_doc(:community, :log),
- do: "https://www.emqx.io/docs/en/latest/configuration/logs.html"
- defp emqx_schema_mod(:enterprise), do: :emqx_enterprise_schema
- defp emqx_schema_mod(:community), do: :emqx_conf_schema
- def jq_dep() do
- if enable_jq?(),
- do: [{:jq, github: "emqx/jq", tag: "v0.3.12", override: true}],
- else: []
- end
- def quicer_dep() do
- if enable_quicer?(),
- # in conflict with emqx and emqtt
- do: [
- {:quicer, github: "emqx/quic", tag: "0.1.0", override: true}
- ],
- else: []
- end
- defp enable_jq?() do
- not Enum.any?([
- build_without_jq?()
- ])
- end
- def enable_quicer?() do
- "1" == System.get_env("BUILD_WITH_QUIC") or
- not Enum.any?([
- macos?(),
- build_without_quic?()
- ])
- end
- defp enable_rocksdb?() do
- not Enum.any?([
- raspbian?(),
- build_without_rocksdb?()
- ])
- end
- defp do_pkg_vsn() do
- %{edition_type: edition_type} = check_profile!()
- basedir = Path.dirname(__ENV__.file)
- script = Path.join(basedir, "pkg-vsn.sh")
- os_cmd(script, [Atom.to_string(edition_type)])
- end
- defp os_cmd(script, args) do
- {str, 0} = System.cmd("bash", [script | args])
- String.trim(str)
- end
- def macos?() do
- {:unix, :darwin} == :os.type()
- end
- defp raspbian?() do
- os_cmd("./scripts/get-distro.sh", []) =~ "raspbian"
- end
- defp build_without_jq?() do
- opt = System.get_env("BUILD_WITHOUT_JQ", "false")
- String.downcase(opt) != "false"
- end
- def build_without_quic?() do
- opt = System.get_env("BUILD_WITHOUT_QUIC", "false")
- String.downcase(opt) != "false"
- end
- defp build_without_rocksdb?() do
- opt = System.get_env("BUILD_WITHOUT_ROCKSDB", "false")
- String.downcase(opt) != "false"
- end
- defp from_rebar_to_eex_template(str) do
- # we must not consider surrounding space in the template var name
- # because some help strings contain informative variables that
- # should not be interpolated, and those have no spaces.
- Regex.replace(
- ~r/\{\{ ([a-zA-Z0-9_]+) \}\}/,
- str,
- "<%= \\g{1} %>"
- )
- end
- defp build_info() do
- [
- build_info_arch: to_string(:erlang.system_info(:system_architecture)),
- build_info_wordsize: wordsize(),
- build_info_os: os_cmd("./scripts/get-distro.sh", []),
- build_info_erlang: otp_release(),
- build_info_elixir: System.version(),
- build_info_relform: System.get_env("EMQX_REL_FORM", "tgz")
- ]
- end
- # https://github.com/erlang/rebar3/blob/e3108ac187b88fff01eca6001a856283a3e0ec87/src/rebar_utils.erl#L142
- defp wordsize() do
- size =
- try do
- :erlang.system_info({:wordsize, :external})
- rescue
- ErlangError ->
- :erlang.system_info(:wordsize)
- end
- to_string(8 * size)
- end
- defp normalize_env!(test_env?) do
- env =
- case Mix.env() do
- :dev ->
- :emqx
- env ->
- env
- end
- if test_env? do
- ensure_test_mix_env!()
- end
- Mix.env(env)
- end
- # As from Erlang/OTP 17, the OTP release number corresponds to the
- # major OTP version number. No erlang:system_info() argument gives
- # the exact OTP version.
- # https://www.erlang.org/doc/man/erlang.html#system_info_otp_release
- # https://github.com/erlang/rebar3/blob/e3108ac187b88fff01eca6001a856283a3e0ec87/src/rebar_utils.erl#L572-L577
- defp otp_release() do
- major_version = System.otp_release()
- root_dir = to_string(:code.root_dir())
- [root_dir, "releases", major_version, "OTP_VERSION"]
- |> Path.join()
- |> File.read()
- |> case do
- {:error, _} ->
- major_version
- {:ok, version} ->
- version
- |> String.trim()
- |> String.split("**")
- |> List.first()
- end
- end
- defp dump_as_erl(term) do
- term
- |> then(&:io_lib.format("~0p", [&1]))
- |> :erlang.iolist_to_binary()
- end
- defp erlang_edition(:community), do: :ce
- defp erlang_edition(:enterprise), do: :ee
- defp aliases() do
- [
- ct: &do_ct/1,
- eunit: &do_eunit/1,
- proper: &do_proper/1,
- dialyzer: &do_dialyzer/1
- ]
- end
- defp do_ct(args) do
- IO.inspect(args)
- Mix.shell().info("testing")
- ensure_test_mix_env!()
- set_test_env!(true)
- Mix.Task.run("emqx.ct", args)
- end
- defp do_eunit(args) do
- ensure_test_mix_env!()
- set_test_env!(true)
- Mix.Task.run("emqx.eunit", args)
- end
- defp do_proper(args) do
- ensure_test_mix_env!()
- set_test_env!(true)
- Mix.Task.run("emqx.proper", args)
- end
- defp do_dialyzer(args) do
- Mix.Task.run("emqx.dialyzer", args)
- end
- defp ensure_test_mix_env!() do
- Mix.env()
- |> to_string()
- |> then(fn env ->
- if String.ends_with?(env, "-test") do
- env
- else
- env <> "-test"
- end
- end)
- |> String.to_atom()
- |> Mix.env()
- end
- end
|