mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-06 15:37:52 +01:00
451 lines
16 KiB
Elixir
451 lines
16 KiB
Elixir
defmodule Ejabberd.MixProject do
|
|
use Mix.Project
|
|
|
|
def project do
|
|
[app: :ejabberd,
|
|
source_url: "https://github.com/processone/ejabberd",
|
|
version: version(),
|
|
description: description(),
|
|
elixir: elixir_required_version(),
|
|
elixirc_paths: ["lib"],
|
|
compile_path: ".",
|
|
compilers: [:asn1, :yecc] ++ Mix.compilers(),
|
|
erlc_options: erlc_options(),
|
|
erlc_paths: ["asn1", "src"],
|
|
# Elixir tests are starting the part of ejabberd they need
|
|
aliases: [test: "test --no-start"],
|
|
start_permanent: Mix.env() == :prod,
|
|
language: :erlang,
|
|
dialyzer: dialyzer(),
|
|
releases: releases(),
|
|
package: package(),
|
|
docs: docs(),
|
|
deps: deps()]
|
|
end
|
|
|
|
def version do
|
|
case config(:vsn) do
|
|
:false -> "0.0.0" # ./configure wasn't run: vars.config not created
|
|
~c"0.0" -> "0.0.0" # the full git repository wasn't downloaded
|
|
~c"latest.0" -> "0.0.0" # running 'docker-ejabberd/ecs/build.sh latest'
|
|
[_, _, ?., _, _] = x ->
|
|
head = String.replace(:erlang.list_to_binary(x), ~r/\.0+([0-9])/, ".\\1")
|
|
"#{head}.0"
|
|
vsn -> String.replace(:erlang.list_to_binary(vsn), ~r/\.0+([0-9])/, ".\\1")
|
|
end
|
|
end
|
|
|
|
def description do
|
|
"""
|
|
Robust, Ubiquitous and Massively Scalable Messaging Platform (XMPP, MQTT, SIP Server)
|
|
"""
|
|
end
|
|
|
|
def application do
|
|
[mod: {:ejabberd_app, []},
|
|
applications: [:idna, :inets, :kernel, :sasl, :ssl, :stdlib, :mix,
|
|
:fast_tls, :fast_xml, :fast_yaml, :jose,
|
|
:p1_utils, :stringprep, :syntax_tools, :yconf, :xmpp]
|
|
++ cond_apps(),
|
|
included_applications: [:mnesia, :os_mon,
|
|
:cache_tab, :eimp, :mqtree, :p1_acme,
|
|
:p1_oauth2, :pkix]
|
|
++ cond_included_apps()]
|
|
end
|
|
|
|
defp dialyzer do
|
|
[
|
|
plt_add_apps: [
|
|
:mnesia, :odbc, :os_mon, :stdlib,
|
|
:eredis, :luerl,
|
|
:cache_tab, :eimp, :epam, :esip, :ezlib, :mqtree,
|
|
:p1_acme, :p1_mysql, :p1_oauth2, :p1_pgsql, :pkix,
|
|
:sqlite3, :stun, :xmpp],
|
|
]
|
|
end
|
|
|
|
defp if_version_above(ver, okResult) do
|
|
if :erlang.system_info(:otp_release) > ver do
|
|
okResult
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
|
|
defp if_version_below(ver, okResult) do
|
|
if :erlang.system_info(:otp_release) < ver do
|
|
okResult
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
|
|
defp if_type_exported(module, typeDef, okResult) do
|
|
try do
|
|
{:ok, concrete} = :dialyzer_utils.get_core_from_beam(:code.which(module))
|
|
{:ok, types} = :dialyzer_utils.get_record_and_type_info(concrete)
|
|
if Map.has_key?(types, typeDef) do
|
|
okResult
|
|
else
|
|
[]
|
|
end
|
|
rescue
|
|
_ -> []
|
|
end
|
|
end
|
|
|
|
defp erlc_options do
|
|
# Use our own includes + includes from all dependencies
|
|
includes = ["include", deps_include()]
|
|
result = [{:d, :ELIXIR_ENABLED}] ++
|
|
cond_options() ++
|
|
Enum.map(includes, fn (path) -> {:i, path} end) ++
|
|
if_version_above(~c"20", [{:d, :DEPRECATED_GET_STACKTRACE}]) ++
|
|
if_version_above(~c"20", [{:d, :HAVE_URI_STRING}]) ++
|
|
if_version_above(~c"20", [{:d, :HAVE_ERL_ERROR}]) ++
|
|
if_version_below(~c"21", [{:d, :USE_OLD_HTTP_URI}]) ++
|
|
if_version_below(~c"22", [{:d, :LAGER}]) ++
|
|
if_version_below(~c"21", [{:d, :NO_CUSTOMIZE_HOSTNAME_CHECK}]) ++
|
|
if_version_below(~c"23", [{:d, :USE_OLD_CRYPTO_HMAC}]) ++
|
|
if_version_below(~c"23", [{:d, :USE_OLD_PG2}]) ++
|
|
if_version_below(~c"24", [{:d, :COMPILER_REPORTS_ONLY_LINES}]) ++
|
|
if_version_below(~c"24", [{:d, :SYSTOOLS_APP_DEF_WITHOUT_OPTIONAL}]) ++
|
|
if_version_below(~c"24", [{:d, :OTP_BELOW_24}]) ++
|
|
if_version_below(~c"25", [{:d, :OTP_BELOW_25}]) ++
|
|
if_version_below(~c"26", [{:d, :OTP_BELOW_26}]) ++
|
|
if_version_below(~c"27", [{:d, :OTP_BELOW_27}]) ++
|
|
if_type_exported(:odbc, {:opaque, :connection_reference, 0}, [{:d, :ODBC_HAS_TYPES}])
|
|
defines = for {:d, value} <- result, do: {:d, value}
|
|
result ++ [{:d, :ALL_DEFS, defines}]
|
|
end
|
|
|
|
defp cond_options do
|
|
for {:true, option} <- [{config(:sip), {:d, :SIP}},
|
|
{config(:stun), {:d, :STUN}},
|
|
{config(:debug), :debug_info},
|
|
{not config(:debug), {:debug_info, false}},
|
|
{config(:roster_gateway_workaround), {:d, :ROSTER_GATEWAY_WORKAROUND}},
|
|
{config(:new_sql_schema), {:d, :NEW_SQL_SCHEMA}}
|
|
], do:
|
|
option
|
|
end
|
|
|
|
defp deps do
|
|
[{:cache_tab, "~> 1.0"},
|
|
{:dialyxir, "~> 1.2", only: [:test], runtime: false},
|
|
{:eimp, "~> 1.0"},
|
|
{:ex_doc, "~> 0.31", only: [:dev, :edoc], runtime: false},
|
|
{:fast_tls, ">= 1.1.18"},
|
|
{:fast_xml, ">= 1.1.51"},
|
|
{:fast_yaml, "~> 1.0"},
|
|
{:idna, "~> 6.0"},
|
|
{:mqtree, "~> 1.0"},
|
|
{:p1_acme, "~> 1.0"},
|
|
{:p1_oauth2, "~> 0.6"},
|
|
{:p1_utils, "~> 1.0"},
|
|
{:pkix, "~> 1.0"},
|
|
{:stringprep, ">= 1.0.26"},
|
|
{:xmpp, ">= 1.8.2"},
|
|
{:yconf, "~> 1.0"}]
|
|
++ cond_deps()
|
|
end
|
|
|
|
defp deps_include() do
|
|
if Mix.Project.umbrella?() do
|
|
"../../deps"
|
|
else
|
|
case Mix.Project.deps_paths()[:ejabberd] do
|
|
nil -> "deps"
|
|
_ -> ".."
|
|
end
|
|
end
|
|
end
|
|
|
|
defp cond_deps do
|
|
for {:true, dep} <- [{config(:pam), {:epam, "~> 1.0"}},
|
|
{Mix.env() == :translations,
|
|
{:ejabberd_po, git: "https://github.com/processone/ejabberd-po.git"}},
|
|
{Mix.env() == :dev,
|
|
{:exsync, "~> 0.2"}},
|
|
{config(:redis), {:eredis, "~> 1.2.0"}},
|
|
{config(:sip), {:esip, "~> 1.0"}},
|
|
{config(:zlib), {:ezlib, "~> 1.0"}},
|
|
{if_version_above(~c"23", true), {:jose, "~> 1.11.10"}},
|
|
{if_version_below(~c"24", true), {:jose, "1.11.1", override: true}},
|
|
{if_version_below(~c"27", true), {:jiffy, "~> 1.1.1"}},
|
|
{if_version_below(~c"22", true), {:lager, "~> 3.9.1"}},
|
|
{config(:lua), {:luerl, "~> 1.2.0"}},
|
|
{config(:mysql), {:p1_mysql, ">= 1.0.24"}},
|
|
{config(:pgsql), {:p1_pgsql, ">= 1.1.26"}},
|
|
{config(:sqlite), {:sqlite3, "~> 1.1"}},
|
|
{config(:stun), {:stun, "~> 1.0"}}], do:
|
|
dep
|
|
end
|
|
|
|
defp cond_apps do
|
|
for {:true, app} <- [{config(:stun), :stun},
|
|
{Map.has_key?(System.get_env(), "RELIVE"), :exsync},
|
|
{if_version_below(~c"27", true), :jiffy},
|
|
{config(:tools), :observer}], do:
|
|
app
|
|
end
|
|
|
|
defp cond_included_apps do
|
|
for {:true, app} <- [{config(:pam), :epam},
|
|
{config(:lua), :luerl},
|
|
{config(:redis), :eredis},
|
|
{Mix.env() == :edoc, :ex_doc},
|
|
{Mix.env() == :test, :dialyxir},
|
|
{if_version_below(~c"22", true), :lager},
|
|
{config(:mysql), :p1_mysql},
|
|
{config(:sip), :esip},
|
|
{config(:odbc), :odbc},
|
|
{config(:pgsql), :p1_pgsql},
|
|
{config(:sqlite), :sqlite3}], do:
|
|
app
|
|
end
|
|
|
|
defp package do
|
|
[# These are the default files included in the package
|
|
files: ["include", "lib", "priv", "sql", "src",
|
|
"COPYING", "README.md",
|
|
"mix.exs", "rebar.config", "rebar.config.script", "vars.config"],
|
|
maintainers: ["ProcessOne"],
|
|
licenses: ["GPL-2.0-or-later"],
|
|
links: %{"ejabberd.im" => "https://www.ejabberd.im",
|
|
"ejabberd Docs" => "http://docs.ejabberd.im",
|
|
"GitHub" => "https://github.com/processone/ejabberd",
|
|
"ProcessOne" => "http://www.process-one.net/"}]
|
|
end
|
|
|
|
defp vars do
|
|
filepath = case Application.fetch_env(:ejabberd, :vars_config_path) do
|
|
:error ->
|
|
"vars.config"
|
|
{:ok, path} ->
|
|
path
|
|
end
|
|
config2 = case :file.consult(filepath) do
|
|
{:ok,config} -> config
|
|
_ -> [stun: true, zlib: true]
|
|
end
|
|
case Mix.env() do
|
|
:dev -> List.keystore(config2, :tools, 0, {:tools, true})
|
|
_ -> config2
|
|
end
|
|
end
|
|
|
|
defp config(key) do
|
|
case vars()[key] do
|
|
nil -> false
|
|
value -> value
|
|
end
|
|
end
|
|
|
|
defp elixir_required_version do
|
|
case {Map.get(System.get_env(), "RELIVE", "false"),
|
|
MapSet.member?(MapSet.new(System.argv()), "release")}
|
|
do
|
|
{"true", _} ->
|
|
case Version.match?(System.version(), "~> 1.11") do
|
|
false ->
|
|
IO.puts("ERROR: To use 'make relive', Elixir 1.11.0 or higher is required.")
|
|
_ -> :ok
|
|
end
|
|
"~> 1.11"
|
|
{_, true} ->
|
|
case Version.match?(System.version(), "~> 1.10") do
|
|
false ->
|
|
IO.puts("ERROR: To build releases, Elixir 1.10.0 or higher is required.")
|
|
_ -> :ok
|
|
end
|
|
case Version.match?(System.version(), "< 1.11.4")
|
|
and :erlang.system_info(:otp_release) > ~c"23" do
|
|
true ->
|
|
IO.puts("ERROR: To build releases with Elixir lower than 1.11.4, Erlang/OTP lower than 24 is required.")
|
|
_ -> :ok
|
|
end
|
|
"~> 1.10"
|
|
_ ->
|
|
"~> 1.4"
|
|
end
|
|
end
|
|
|
|
defp releases do
|
|
maybe_tar = case Mix.env() do
|
|
:prod -> [:tar]
|
|
_ -> []
|
|
end
|
|
[
|
|
ejabberd: [
|
|
include_executables_for: [:unix],
|
|
# applications: [runtime_tools: :permanent]
|
|
steps: [©_extra_files/1, :assemble | maybe_tar]
|
|
]
|
|
]
|
|
end
|
|
|
|
defp copy_extra_files(release) do
|
|
assigns = [
|
|
version: version(),
|
|
rootdir: config(:rootdir),
|
|
installuser: config(:installuser),
|
|
libdir: config(:libdir),
|
|
sysconfdir: config(:sysconfdir),
|
|
localstatedir: config(:localstatedir),
|
|
config_dir: config(:config_dir),
|
|
logs_dir: config(:logs_dir),
|
|
spool_dir: config(:spool_dir),
|
|
vsn: version(),
|
|
iexpath: config(:iexpath),
|
|
erl: config(:erl),
|
|
epmd: config(:epmd),
|
|
bindir: Path.join([config(:release_dir), "releases", version()]),
|
|
release_dir: config(:release_dir),
|
|
erts_dir: config(:erts_dir),
|
|
erts_vsn: "erts-#{release.erts_version}"
|
|
]
|
|
ro = "rel/overlays"
|
|
File.rm_rf(ro)
|
|
|
|
# Elixir lower than 1.12.0 don't have System.shell
|
|
execute = fn(command) ->
|
|
case function_exported?(System, :shell, 1) do
|
|
true ->
|
|
System.shell(command, into: IO.stream())
|
|
false ->
|
|
:os.cmd(to_charlist(command))
|
|
end
|
|
end
|
|
|
|
# Mix/Elixir lower than 1.11.0 use config/releases.exs instead of runtime.exs
|
|
case Version.match?(System.version(), "~> 1.11") do
|
|
true ->
|
|
:ok
|
|
false ->
|
|
execute.("cp config/runtime.exs config/releases.exs")
|
|
end
|
|
|
|
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.template > ejabberdctl.example1")
|
|
Mix.Generator.copy_template("ejabberdctl.example1", "ejabberdctl.example2", assigns)
|
|
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.example2> ejabberdctl.example2a")
|
|
Mix.Generator.copy_template("ejabberdctl.example2a", "ejabberdctl.example2b", assigns)
|
|
execute.("sed -e 's|{{\\(\[_a-z\]*\\)}}|<%= @\\1 %>|g' ejabberdctl.example2b > ejabberdctl.example4")
|
|
execute.("sed -e 's|^ERLANG_OPTS=\"|ERLANG_OPTS=\"-boot ../releases/#{release.version}/start_clean -boot_var RELEASE_LIB ../lib |' ejabberdctl.example4 > ejabberdctl.example5")
|
|
execute.("sed -e 's|^INSTALLUSER=|ERL_OPTIONS=\"-setcookie \\$\\(cat \"\\${SCRIPT_DIR%/*}/releases/COOKIE\")\"\\nINSTALLUSER=|g' ejabberdctl.example5 > ejabberdctl.example6")
|
|
Mix.Generator.copy_template("ejabberdctl.example6", "#{ro}/bin/ejabberdctl", assigns)
|
|
File.chmod("#{ro}/bin/ejabberdctl", 0o755)
|
|
|
|
File.rm("ejabberdctl.example1")
|
|
File.rm("ejabberdctl.example2")
|
|
File.rm("ejabberdctl.example2a")
|
|
File.rm("ejabberdctl.example2b")
|
|
File.rm("ejabberdctl.example3")
|
|
File.rm("ejabberdctl.example4")
|
|
File.rm("ejabberdctl.example5")
|
|
File.rm("ejabberdctl.example6")
|
|
|
|
suffix = case Mix.env() do
|
|
:dev ->
|
|
Mix.Generator.copy_file("test/ejabberd_SUITE_data/ca.pem", "#{ro}/conf/ca.pem")
|
|
Mix.Generator.copy_file("test/ejabberd_SUITE_data/cert.pem", "#{ro}/conf/cert.pem")
|
|
".example"
|
|
_ -> ""
|
|
end
|
|
|
|
Mix.Generator.copy_file("ejabberd.yml.example", "#{ro}/conf/ejabberd.yml#{suffix}")
|
|
Mix.Generator.copy_file("ejabberdctl.cfg.example", "#{ro}/conf/ejabberdctl.cfg#{suffix}")
|
|
Mix.Generator.copy_file("inetrc", "#{ro}/conf/inetrc")
|
|
|
|
Enum.each(File.ls!("sql"),
|
|
fn x ->
|
|
Mix.Generator.copy_file("sql/#{x}", "#{ro}/lib/ejabberd-#{release.version}/priv/sql/#{x}")
|
|
end)
|
|
|
|
File.cp_r!("include", "#{ro}/lib/ejabberd-#{release.version}/include")
|
|
for {name, details} <- Map.to_list(release.applications) do
|
|
{_, is_otp_app} = List.keyfind(details, :otp_app?, 0)
|
|
{_, vsn} = List.keyfind(details, :vsn, 0)
|
|
{_, path} = List.keyfind(details, :path, 0)
|
|
source_dir = case is_otp_app do
|
|
:true -> "#{path}/include"
|
|
:false -> "deps/#{name}/include"
|
|
end
|
|
target_dir = "#{ro}/lib/#{name}-#{vsn}/include"
|
|
File.exists?(source_dir)
|
|
&& File.mkdir_p(target_dir)
|
|
&& File.cp_r!(source_dir, target_dir)
|
|
end
|
|
|
|
case Mix.env() do
|
|
:dev -> execute.("REL_DIR_TEMP=$PWD/rel/overlays/ rel/setup-dev.sh mix")
|
|
_ -> :ok
|
|
end
|
|
|
|
release
|
|
end
|
|
|
|
defp docs do
|
|
[
|
|
main: "readme",
|
|
logo: "_build/edoc/logo.png",
|
|
source_ref: "master",
|
|
extra_section: "", # No need for Pages section name, it's the only one
|
|
api_reference: false, # API section has just Elixir, hide it
|
|
filter_modules: "aaaaa", # Module section has just Elixir modules, hide them
|
|
extras: [
|
|
"README.md": [title: "Readme"],
|
|
"COMPILE.md": [title: "Compile and Install"],
|
|
"CONTAINER.md": [title: "Container Image"],
|
|
"CONTRIBUTING.md": [title: "Contributing"],
|
|
"CONTRIBUTORS.md": [title: "Contributors"],
|
|
"CODE_OF_CONDUCT.md": [title: "Code of Conduct"],
|
|
"CHANGELOG.md": [title: "ChangeLog"],
|
|
"COPYING": [title: "Copying License"],
|
|
"_build/edoc/docs.md": [title: "⟹ ejabberd Docs"]
|
|
],
|
|
groups_for_extras: [
|
|
"": Path.wildcard("*.md") ++ ["COPYING"],
|
|
"For more documentation": "_build/edoc/docs.md"
|
|
]
|
|
]
|
|
end
|
|
end
|
|
|
|
defmodule Mix.Tasks.Compile.Asn1 do
|
|
use Mix.Task
|
|
alias Mix.Compilers.Erlang
|
|
|
|
@recursive true
|
|
@manifest ".compile.asn1"
|
|
|
|
def run(args) do
|
|
{opts, _, _} = OptionParser.parse(args, switches: [force: :boolean])
|
|
|
|
project = Mix.Project.config()
|
|
source_paths = project[:asn1_paths] || ["asn1"]
|
|
dest_paths = project[:asn1_target] || ["src"]
|
|
mappings = Enum.zip(source_paths, dest_paths)
|
|
options = project[:asn1_options] || []
|
|
|
|
force = case opts[:force] do
|
|
:true -> [force: true]
|
|
_ -> [force: false]
|
|
end
|
|
|
|
Erlang.compile(manifest(), mappings, :asn1, :erl, force, fn
|
|
input, output ->
|
|
options = options ++ [:noobj, outdir: Erlang.to_erl_file(Path.dirname(output))]
|
|
case :asn1ct.compile(Erlang.to_erl_file(input), options) do
|
|
:ok -> {:ok, :done}
|
|
error -> error
|
|
end
|
|
end)
|
|
end
|
|
|
|
def manifests, do: [manifest()]
|
|
defp manifest, do: Path.join(Mix.Project.manifest_path(), @manifest)
|
|
|
|
def clean, do: Erlang.clean(manifest())
|
|
end
|