Current section
Files
Jump to
Current section
Files
lib/edeliver.ex
defmodule Edeliver do
def run_command([command_name, application_name = [_|_] | arguments]) when is_atom(command_name) do
application_name = to_string(application_name)
application_name = String.to_atom(to_string(application_name))
{^application_name, _description, application_version} = :application.which_applications |> List.keyfind(application_name, 0)
application_version = to_string application_version
apply __MODULE__, command_name, [application_name, application_version | arguments]
end
def release_version(application_name, _application_version \\ nil) do
releases = :release_handler.which_releases
application_name = Atom.to_char_list application_name
case (for {name, version, _apps, status} <- releases, status == :current and name == application_name, do: to_string(version)) do
[current_version] -> current_version
_ ->
case (for {name, version, _apps, status} <- releases, status == :permanent and name == application_name, do: to_string(version)) do
[permanent_version] -> String.to_char_list(permanent_version)
end
end
end
def list_pending_migrations(application_name, application_version) do
repository = ecto_repository!
versions = Ecto.Migrator.migrated_versions(repository)
pending_migrations = migrations_for(migrations_dir(application_name, application_version))
|> Enum.filter(fn {version, _name, _file} -> not (version in versions) end)
|> Enum.reverse
|> Enum.map(fn {version, name, _file} -> {version, name} end)
pending_migrations |> Enum.each(fn {version, name} ->
warning "pending: #{name} (#{version})"
end)
end
def migrate(application_name, application_version, direction, migration_version \\ :all) when is_atom(direction) do
options = if migration_version == :all, do: [all: true], else: [to: to_string(migration_version)]
Ecto.Migrator.run(ecto_repository!, migrations_dir(application_name, application_version), direction, options)
end
def migrations_dir(application_name, application_version) do
# use priv dir from installed version
lib_dir = :code.priv_dir(application_name) |> to_string |> Path.dirname |> Path.dirname
application_with_version = "#{Atom.to_string(application_name)}-#{application_version}"
Path.join([lib_dir, application_with_version, "priv", "repo", "migrations"])
end
def ecto_repository! do
case System.get_env "ECTO_REPOSITORY" do
ecto_repository = <<_,_::binary>> ->
ecto_repository_module = ecto_repository |> to_char_list |> List.to_atom
if maybe_ecto_repo?(ecto_repository_module) do
ecto_repository_module
else
error! "Module '#{ecto_repository_module}' is not an ecto repository.\n Please set the correct repository module in the edeliver config as ECTO_REPOSITORY env\n or remove that value to use autodetection of that module."
end
_ ->
case Enum.filter(:erlang.loaded |> Enum.reverse, &maybe_ecto_repo?/1) do
[ecto_repository_module] -> ecto_repository_module
[] -> error! "No ecto repository module found.\n Please specify the repository in the edeliver config as ECTO_REPOSITORY env."
modules =[_|_] -> error! "Found several ecto repository modules (#{inspect modules}).\n Please specify the repository to use in the edeliver config as ECTO_REPOSITORY env."
end
end
end
defp maybe_ecto_repo?(module) do
if :erlang.module_loaded(module) do
exports = module.module_info(:exports)
# :__adapter__ for ecto versions >= 2.0, :__repo__ for ecto versions < 2.0
Dict.get(exports, :__adapter__, nil) || Dict.get(exports, :__repo__, nil)
else
false
end
end
# taken from https://github.com/elixir-lang/ecto/blob/master/lib/ecto/migrator.ex#L183
defp migrations_for(directory) do
query = Path.join(directory, "*")
for entry <- Path.wildcard(query),
info = extract_migration_info(entry),
do: info
end
defp extract_migration_info(file) do
base = Path.basename(file)
ext = Path.extname(base)
case Integer.parse(Path.rootname(base)) do
{integer, "_" <> name} when ext == ".exs" -> {integer, name, file}
_ -> nil
end
end
# defp info(message), do: IO.puts "==> #{IO.ANSI.green}#{message}#{IO.ANSI.reset}"
defp warning(message), do: IO.puts "==> #{IO.ANSI.yellow}#{message}#{IO.ANSI.reset}"
defp error!(message) do
IO.puts "==> #{IO.ANSI.red}#{message}#{IO.ANSI.reset}"
throw "error"
end
end