Packages
exrm
1.0.0-rc3
1.0.8
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc8
1.0.0-rc7
1.0.0-rc6
1.0.0-rc5
1.0.0-rc4
1.0.0-rc3
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.8
0.18.7
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.3
0.15.2
0.15.1
0.15.0
0.14.17
0.14.16
0.14.15
0.14.14
0.14.13
0.14.12
0.14.11
0.14.10
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.3
0.14.2
0.14.1
0.14.0
0.12.12
0.12.11
0.12.10
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.1
0.10.0
0.9.2
0.9.1
0.8.1
0.8.0
0.7.3
0.7.2
0.7.1
0.7.0
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.7
Exrm, or Elixir Release Manager, provides mix tasks for building, upgrading, and controlling release packages for your application.
Current section
Files
Jump to
Current section
Files
lib/exrm/appups.ex
defmodule ReleaseManager.Appups do
@moduledoc """
Module for auto-generating appups between releases.
"""
import ReleaseManager.Utils, only: [write_term: 2]
@doc """
Generate a .appup for the given application, start version, and upgrade version.
## Parameter information
application: the application name as an atom
v1: the start version, such as "0.0.1"
v2: the upgrade version, such as "0.0.2"
v1_path: the path to the v1 artifacts (rel/<app>/lib/<app>-0.0.1)
v2_path: the path to the v2 artifacts (_build/prod/lib/<app>)
"""
def make(application, v1, v2, v1_path, v2_path) do
v1_release =
v1_path
|> Path.join("/ebin/")
|> Path.join(Atom.to_string(application) <> ".app")
|> String.to_char_list
v2_release =
v2_path
|> Path.join("/ebin/")
|> Path.join(Atom.to_string(application) <> ".app")
|> String.to_char_list
case :file.consult(v1_release) do
{ :ok, [ { :application, ^application, v1_props } ] } ->
case vsn(v1_props) === v1 do
true ->
case :file.consult(v2_release) do
{ :ok, [ { :application, ^application, v2_props } ] } ->
case vsn(v2_props) === v2 do
true ->
make_appup(application, v1, v1_path, v1_props, v2, v2_path, v2_props)
false ->
{ :error, :bad_new_appvsn }
end
_ ->
{ :error, :bad_new_appfile }
end
false ->
{ :error, :bad_old_appvsn }
end
_ ->
{ :error, :bad_old_appfile }
end
end
defp make_appup(application, v1, v1_path, _v1_props, v2, v2_path, _v2_props) do
{only_v1, only_v2, different} =
:beam_lib.cmp_dirs(to_char_list(Path.join(v1_path, "ebin")), to_char_list(Path.join(v2_path, "ebin")))
appup =
{ v2 |> String.to_char_list,
[ { v1 |> String.to_char_list,
(for file <- only_v2, do: generate_instruction(:added, file)) ++
(for {file, _} <- different, do: generate_instruction(:changed, file)) ++
(for file <- only_v1, do: generate_instruction(:deleted, file))
}
],
[ { v1 |> String.to_char_list,
(for file <- only_v2, do: generate_instruction(:deleted, file)) ++
(for {file, _} <- different, do: generate_instruction(:changed, file)) ++
(for file <- only_v1, do: generate_instruction(:added, file))
}
]
}
# Save the appup to the upgrade's build directory
v2_path
|> Path.join("ebin")
|> Path.join((application |> Atom.to_string) <> ".appup")
|> write_term(appup)
{ :ok, appup }
end
defp generate_instruction(:added, file) do
{:add_module, module_name(file)}
end
defp generate_instruction(:deleted, file) do
{:delete_module, module_name(file)}
end
defp generate_instruction(:changed, file) do
{:ok, {module_name, list}} = :beam_lib.chunks(file, [:attributes, :exports])
behaviour = get_in(list, [:attributes, :behavior]) || get_in(list, [:attributes, :behaviour])
is_code_change = get_in(list, [:exports, :code_change]) != nil
generate_instruction_advanced(module_name, behaviour, is_code_change)
end
defp generate_instruction_advanced(module_name, [:supervisor], _) do
# supervisor
{:update, module_name, :supervisor}
end
defp generate_instruction_advanced(module_name, _behaviour, true) do
# exports code_change
{:update, module_name, {:advanced, []}}
end
defp generate_instruction_advanced(module_name, _behaviour, false) do
# code_change not exported
{:load_module, module_name}
end
defp module_name(file) do
:beam_lib.info(file) |> Keyword.fetch!(:module)
end
defp vsn(props) do
{ :value, { :vsn, vsn } } = :lists.keysearch(:vsn, 1, props)
vsn |> List.to_string
end
end