209 lines
5.7 KiB
Elixir
Executable File
209 lines
5.7 KiB
Elixir
Executable File
#!/usr/bin/env elixir
|
|
|
|
defmodule CheckElixirApplications do
|
|
alias EMQXUmbrella.MixProject
|
|
|
|
@default_applications [:kernel, :stdlib, :sasl]
|
|
|
|
def main() do
|
|
{:ok, _} = Application.ensure_all_started(:mix)
|
|
|
|
File.cwd!()
|
|
|> Path.join("mix.exs")
|
|
|> Code.compile_file()
|
|
|
|
inputs = MixProject.check_profile!()
|
|
profile = Mix.env()
|
|
# produce `rebar.config.rendered` to consult
|
|
|
|
File.cwd!()
|
|
|> Path.join("rebar3")
|
|
|> System.cmd(["as", to_string(profile)],
|
|
env: [{"DEBUG", "1"}]
|
|
)
|
|
|
|
mix_apps = mix_applications(inputs.edition_type)
|
|
rebar_apps = rebar_applications(profile)
|
|
results = diff_apps(mix_apps, rebar_apps)
|
|
|
|
report_discrepancy(
|
|
results[:missing_apps],
|
|
"* There are missing applications in the Elixir release",
|
|
fn %{app: app, mode: mode, after: last_app} ->
|
|
IO.puts(" * #{app}: #{inspect(mode)} should be placed after #{inspect(last_app)}")
|
|
end
|
|
)
|
|
|
|
report_discrepancy(
|
|
results[:different_modes],
|
|
"* There are applications with different application modes in the Elixir release",
|
|
fn %{app: app, rebar_mode: rebar_mode, mix_mode: mix_mode} ->
|
|
IO.puts(
|
|
" * #{inspect(app)} should have mode #{inspect(rebar_mode)}, but it has mode #{inspect(mix_mode)}"
|
|
)
|
|
end
|
|
)
|
|
|
|
report_discrepancy(
|
|
results[:different_positions],
|
|
"* There are applications in the Elixir release in the wrong order",
|
|
fn %{app: app, mode: mode, after: last_app} ->
|
|
IO.puts(" * #{app}: #{inspect(mode)} should be placed after #{inspect(last_app)}")
|
|
end
|
|
)
|
|
|
|
success? =
|
|
results
|
|
|> Map.take([:missing_apps, :different_modes, :different_positions])
|
|
|> Map.values()
|
|
|> Enum.concat()
|
|
|> Enum.empty?()
|
|
|
|
if not success? do
|
|
System.halt(1)
|
|
else
|
|
IO.puts(
|
|
IO.ANSI.green() <>
|
|
"Mix and Rebar applications OK!" <>
|
|
IO.ANSI.reset()
|
|
)
|
|
end
|
|
end
|
|
|
|
defp mix_applications(edition_type) do
|
|
EMQXUmbrella.MixProject.applications(edition_type)
|
|
end
|
|
|
|
defp rebar_applications(profile) do
|
|
{:ok, props} =
|
|
File.cwd!()
|
|
|> Path.join("rebar.config.rendered")
|
|
|> :file.consult()
|
|
|
|
props[:profiles][profile][:relx]
|
|
|> Enum.find(&(elem(&1, 0) == :release))
|
|
|> elem(2)
|
|
|> Enum.map(fn
|
|
app when is_atom(app) ->
|
|
{app, :permanent}
|
|
|
|
{app, mode} ->
|
|
{app, mode}
|
|
end)
|
|
|> Enum.reject(fn {app, _mode} ->
|
|
# Elixir already includes those implicitly
|
|
app in @default_applications
|
|
end)
|
|
end
|
|
|
|
defp diff_apps(mix_apps, rebar_apps) do
|
|
app_names = Keyword.keys(rebar_apps)
|
|
mix_apps = Keyword.filter(mix_apps, fn {app, _mode} -> app in app_names end)
|
|
|
|
acc = %{
|
|
mix_apps: mix_apps,
|
|
missing_apps: [],
|
|
different_positions: [],
|
|
different_modes: [],
|
|
last_app: nil
|
|
}
|
|
|
|
Enum.reduce(
|
|
rebar_apps,
|
|
acc,
|
|
fn
|
|
{rebar_app, rebar_mode}, acc = %{mix_apps: [], last_app: last_app} ->
|
|
missing_app = %{
|
|
app: rebar_app,
|
|
mode: rebar_mode,
|
|
after: last_app
|
|
}
|
|
|
|
acc
|
|
|> Map.update!(:missing_apps, &[missing_app | &1])
|
|
|> Map.put(:last_app, rebar_app)
|
|
|
|
{rebar_app, rebar_mode},
|
|
acc = %{mix_apps: [{mix_app, mix_mode} | rest], last_app: last_app} ->
|
|
case {rebar_app, rebar_mode} do
|
|
{^mix_app, ^mix_mode} ->
|
|
acc
|
|
|> Map.put(:mix_apps, rest)
|
|
|> Map.put(:last_app, rebar_app)
|
|
|
|
{^mix_app, _mode} ->
|
|
different_mode = %{
|
|
app: rebar_app,
|
|
rebar_mode: rebar_mode,
|
|
mix_mode: mix_mode
|
|
}
|
|
|
|
acc
|
|
|> Map.put(:mix_apps, rest)
|
|
|> Map.update!(:different_modes, &[different_mode | &1])
|
|
|> Map.put(:last_app, rebar_app)
|
|
|
|
{_app, _mode} ->
|
|
case Keyword.pop(rest, rebar_app) do
|
|
{nil, _} ->
|
|
missing_app = %{
|
|
app: rebar_app,
|
|
mode: rebar_mode,
|
|
after: last_app
|
|
}
|
|
|
|
acc
|
|
|> Map.update!(:missing_apps, &[missing_app | &1])
|
|
|> Map.put(:last_app, rebar_app)
|
|
|
|
{^rebar_mode, rest} ->
|
|
different_position = %{
|
|
app: rebar_app,
|
|
mode: rebar_mode,
|
|
after: last_app
|
|
}
|
|
|
|
acc
|
|
|> Map.update!(:different_positions, &[different_position | &1])
|
|
|> Map.put(:last_app, rebar_app)
|
|
|> Map.put(:mix_apps, [{mix_app, mix_mode} | rest])
|
|
|
|
{mode, rest} ->
|
|
different_mode = %{
|
|
app: rebar_app,
|
|
rebar_mode: rebar_mode,
|
|
mix_mode: mode
|
|
}
|
|
|
|
different_position = %{
|
|
app: rebar_app,
|
|
mode: rebar_mode,
|
|
after: last_app
|
|
}
|
|
|
|
acc
|
|
|> Map.put(:mix_apps, [{mix_app, mix_mode} | rest])
|
|
|> Map.update!(:different_modes, &[different_mode | &1])
|
|
|> Map.update!(:different_positions, &[different_position | &1])
|
|
|> Map.put(:last_app, rebar_app)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
end
|
|
|
|
defp report_discrepancy(diffs, header, line_fn) do
|
|
unless Enum.empty?(diffs) do
|
|
IO.puts(IO.ANSI.red() <> header)
|
|
|
|
diffs
|
|
|> Enum.reverse()
|
|
|> Enum.each(line_fn)
|
|
|
|
IO.puts(IO.ANSI.reset())
|
|
end
|
|
end
|
|
end
|
|
|
|
CheckElixirApplications.main()
|