Current section
Files
Jump to
Current section
Files
lib/shoehorn.ex
defmodule Shoehorn do
use Application
use Mix.Releases.Plugin
alias Shoehorn.Utils
alias Mix.Releases.{App, Release}
alias Mix.Releases.Utils, as: ReleaseUtils
def start(_type, _args) do
opts = [strategy: :one_for_one, name: Shoehorn.Supervisor]
Supervisor.start_link(children(), opts)
end
def children() do
:init.get_argument(:boot)
|> boot()
end
def boot({:ok, [[bootfile]]}) do
bootfile = to_string(bootfile)
if String.ends_with?(bootfile, "shoehorn") do
import Supervisor.Spec, warn: false
opts = Application.get_all_env(:shoehorn)
[
worker(Shoehorn.ApplicationController, [opts])
]
else
[]
end
end
def boot(_), do: []
# Distillery Behaviour
def before_assembly(%Release{} = release, _opts) do
release
end
def after_assembly(%Release{} = release, _opts) do
generate_boot_script(release)
release
end
def before_package(%Release{} = release, _opts) do
release
end
def after_package(%Release{} = release, _opts) do
release
end
def after_cleanup(_args, _opts) do
:noop
end
def generate_boot_script(app_release) do
Application.load(:shoehorn)
runtime_spec = Application.spec(:shoehorn)
release = Release.new(:shoehorn, runtime_spec[:vsn])
release = %{release | profile: app_release.profile}
release_apps = ReleaseUtils.get_apps(release)
release = %{release | :applications => release_apps}
rel_dir =
Path.join(["#{app_release.profile.output_dir}", "releases", "#{app_release.version}"])
erts_vsn =
case app_release.profile.include_erts do
bool when is_boolean(bool) ->
Mix.Releases.Utils.erts_version()
path ->
{:ok, vsn} = Mix.Releases.Utils.detect_erts_version(path)
vsn
end
start_apps =
Enum.filter(app_release.applications, fn %App{name: n} ->
n in Utils.shoehorn_applications()
end)
{[shoehorn], start_apps} = Enum.split_with(start_apps, &(&1.name == :shoehorn))
start_apps = [%{shoehorn | start_type: nil} | start_apps]
load_apps =
Enum.reject(app_release.applications, fn %App{name: n} ->
n in Utils.shoehorn_applications()
end)
# []
load_apps = Enum.map(load_apps, &{&1.name, '#{&1.vsn}', :none})
start_apps =
Enum.map(start_apps, fn %App{name: name, vsn: vsn, start_type: start_type} ->
case start_type do
nil ->
{name, '#{vsn}'}
t ->
{name, '#{vsn}', t}
end
end)
relfile = {:release, {'shoehorn', '0.1.0'}, {:erts, '#{erts_vsn}'}, start_apps ++ load_apps}
path = Path.join(rel_dir, "shoehorn.rel")
ReleaseUtils.write_term(path, relfile)
erts_lib_dir =
case release.profile.include_erts do
false -> :code.lib_dir()
true -> :code.lib_dir()
p -> String.to_charlist(Path.expand(Path.join(p, "lib")))
end
options = [
{:path, ['#{rel_dir}' | Release.get_code_paths(app_release)]},
{:outdir, '#{rel_dir}'},
{:variables, [{'ERTS_LIB_DIR', erts_lib_dir}]},
:no_warn_sasl,
:no_module_tests,
:silent
]
case :systools.make_script('shoehorn', options) do
{:error, _, e} ->
Logger.error(
"Shoehorn failed: " <>
inspect(e) <> "\n#{Exception.format_stacktrace(System.stacktrace())}"
)
exit({:shutdown, 1})
_ ->
%Release{profile: %{output_dir: output_dir}, name: app} = app_release
relative_output_dir = Path.relative_to_cwd(output_dir)
Logger.success("""
Generated Shoehorn Boot Script
Run using shoehorn:
Interactive: #{relative_output_dir}/bin/#{app} console_boot shoehorn
""")
end
File.cp(
Path.join(rel_dir, "shoehorn.boot"),
Path.join([app_release.profile.output_dir, "bin", "shoehorn.boot"])
)
end
end