Current section

Files

Jump to
ecto lib mix ecto.ex
Raw

lib/mix/ecto.ex

defmodule Mix.Ecto do
# Conveniences for writing Mix.Tasks in Ecto.
@moduledoc false
@doc """
Parses the repository option from the given list.
If no repo option is given, we get one from the environment.
"""
@spec parse_repo([term]) :: Ecto.Repo.t
def parse_repo([key, value|_]) when key in ~w(--repo -r) do
Module.concat([value])
end
def parse_repo([_|t]) do
parse_repo(t)
end
def parse_repo([]) do
app = Mix.Project.config |> Keyword.fetch!(:app)
case Application.get_env(app, :app_namespace, app) do
^app -> app |> to_string |> Mix.Utils.camelize
mod -> mod |> inspect
end |> Module.concat(Repo)
end
@doc """
Ensures the given module is a repository.
"""
@spec ensure_repo(module, list) :: Ecto.Repo.t | no_return
def ensure_repo(repo, args) do
Mix.Task.run "loadpaths", args
unless "--no-compile" in args do
# TODO: Use Mix.Project.compile(args) with v1.1
Mix.Task.run "compile", args
end
case Code.ensure_compiled(repo) do
{:module, _} ->
if function_exported?(repo, :__repo__, 0) do
repo
else
Mix.raise "module #{inspect repo} is not a Ecto.Repo. " <>
"Please pass a proper repo with the -r option."
end
{:error, error} ->
Mix.raise "could not load #{inspect repo}, error: #{inspect error}. " <>
"Please pass a proper repo with the -r option."
end
end
@doc """
Ensures the given repository is started and running.
"""
@spec ensure_started(Ecto.Repo.t) :: Ecto.Repo.t | no_return
def ensure_started(repo) do
{:ok, _} = Application.ensure_all_started(:ecto)
case repo.start_link do
{:ok, pid} -> {:ok, pid}
{:error, {:already_started, _}} -> {:ok, nil}
{:error, error} ->
Mix.raise "could not start repo #{inspect repo}, error: #{inspect error}"
end
end
@doc """
Ensure the repository is stopped.
"""
@spec ensure_stopped(pid | nil) :: :ok
def ensure_stopped(nil), do: :ok
def ensure_stopped(pid) do
ref = Process.monitor(pid)
Process.exit(pid, :normal)
receive do
{:DOWN, ^ref, _, _, _} ->
:ok
after
30_000 ->
Mix.raise "repository did not shutdown after running command"
end
end
@doc """
Gets the migrations path from a repository.
"""
@spec migrations_path(Ecto.Repo.t) :: String.t
def migrations_path(repo) do
Path.join(repo_priv(repo), "migrations")
end
@doc """
Returns the private repository path.
"""
def repo_priv(repo) do
config = repo.config()
Application.app_dir(Keyword.fetch!(config, :otp_app),
config[:priv] || "priv/#{repo |> Module.split |> List.last |> Mix.Utils.underscore}")
end
@doc """
Asks if the user wants to open a file based on ECTO_EDITOR.
"""
@spec open?(binary) :: boolean
def open?(file) do
editor = System.get_env("ECTO_EDITOR") || ""
if editor != "" do
:os.cmd(to_char_list(editor <> " " <> inspect(file)))
true
else
false
end
end
@doc """
Gets a path relative to the application path.
Raises on umbrella application.
"""
def no_umbrella!(task) do
if Mix.Project.umbrella? do
Mix.raise "cannot run task #{inspect task} from umbrella application"
end
end
@doc """
Returns `true` if module implements behaviour.
"""
def ensure_implements(module, behaviour, message) do
all = Keyword.take(module.__info__(:attributes), [:behaviour])
unless [behaviour] in Keyword.values(all) do
Mix.raise "Expected #{inspect module} to implement #{inspect behaviour} " <>
"in order to #{message}"
end
end
end