rabbitmq-server/bazel/elixir/elixir_escript_main.exs

131 lines
3.7 KiB
Elixir

defmodule ElixirEscriptMain do
# https://github.com/elixir-lang/elixir/blob/99785cc16be096d02012ad889ca51b5045b599a4/lib/mix/lib/mix/tasks/escript.build.ex#L327
def gen_main(project, name, module, app, language) do
config_path = project[:config_path]
compile_config =
if File.regular?(config_path) do
config = Config.Reader.read!(config_path, env: Mix.env(), target: Mix.target())
Macro.escape(config)
else
[]
end
runtime_path = config_path |> Path.dirname() |> Path.join("runtime.exs")
runtime_config =
if File.regular?(runtime_path) do
File.read!(runtime_path)
end
module_body =
quote do
@spec main(OptionParser.argv()) :: any
def main(args) do
unquote(main_body_for(language, module, app, compile_config, runtime_config))
end
defp load_config(config) do
each_fun = fn {app, kw} ->
set_env_fun = fn {k, v} -> :application.set_env(app, k, v, persistent: true) end
:lists.foreach(set_env_fun, kw)
end
:lists.foreach(each_fun, config)
:ok
end
defp start_app(nil) do
:ok
end
defp start_app(app) do
case :application.ensure_all_started(app) do
{:ok, _} ->
:ok
{:error, {app, reason}} ->
formatted_error =
case :code.ensure_loaded(Application) do
{:module, Application} -> Application.format_error(reason)
{:error, _} -> :io_lib.format(~c"~p", [reason])
end
error_message = [
"ERROR! Could not start application ",
:erlang.atom_to_binary(app, :utf8),
": ",
formatted_error,
?\n
]
io_error(error_message)
:erlang.halt(1)
end
end
defp io_error(message) do
:io.put_chars(:standard_error, message)
end
end
{:module, ^name, binary, _} = Module.create(name, module_body, Macro.Env.location(__ENV__))
[{~c"#{name}.beam", binary}]
end
defp main_body_for(:elixir, module, app, compile_config, runtime_config) do
config =
if runtime_config do
quote do
runtime_config =
Config.Reader.eval!(
"config/runtime.exs",
unquote(runtime_config),
env: unquote(Mix.env()),
target: unquote(Mix.target()),
imports: :disabled
)
Config.Reader.merge(unquote(compile_config), runtime_config)
end
else
compile_config
end
quote do
case :application.ensure_all_started(:elixir) do
{:ok, _} ->
args = Enum.map(args, &List.to_string(&1))
System.argv(args)
load_config(unquote(config))
start_app(unquote(app))
Kernel.CLI.run(fn _ -> unquote(module).main(args) end)
error ->
io_error(["ERROR! Failed to start Elixir.\n", :io_lib.format(~c"error: ~p~n", [error])])
:erlang.halt(1)
end
end
end
end
output = System.get_env("OUT")
IO.puts("Will write to " <> output)
project = [
config_path: System.get_env("CONFIG_PATH", "config/config.exs"),
]
app = String.to_atom(System.get_env("APP"))
name = String.to_atom(Atom.to_string(app) <> "_escript")
module = String.to_atom(System.get_env("MAIN_MODULE"))
:application.ensure_all_started(:mix)
Mix.State.start_link(:none)
[{_, bytecode}] = ElixirEscriptMain.gen_main(project, name, module, app, :elixir)
{:ok, file} = File.open(output, [:write])
IO.binwrite(file, bytecode)
File.close(file)
IO.puts("done.")