defmodule Mix.Mnesia do
@moduledoc """
Helpers functions for Mnesia tasks
"""
alias Ecto.Adapters.Mnesia.Migrator
@doc """
Ensures the given module is an Ecto.Repo.
"""
@spec ensure_repo(module, list) :: Ecto.Repo.t()
def ensure_repo(repo, args) do
# Do not pass the --force switch used by some tasks downstream
args = List.delete(args, "--force")
# TODO: Use only app.config when we depend on Elixir v1.11+.
if Code.ensure_loaded?(Mix.Tasks.App.Config) do
Mix.Task.run("app.config", args)
else
Mix.Task.run("loadpaths", args)
"--no-compile" not in args && Mix.Task.run("compile", args)
end
case Code.ensure_compiled(repo) do
{:module, _} ->
if function_exported?(repo, :__adapter__, 0) do
repo
else
Mix.raise(
"Module #{inspect(repo)} is not an Ecto.Repo. " <>
"Please configure your app accordingly or pass a repo with the -r option."
)
end
{:error, error} ->
Mix.raise(
"Could not load #{inspect(repo)}, error: #{inspect(error)}. " <>
"Please configure your app accordingly or pass a repo with the -r option."
)
end
end
@doc """
Returns migrations from environment
"""
def get_migrations(args) do
if Code.ensure_loaded?(Mix.Tasks.App.Config) do
Mix.Task.run("app.config", args)
else
Mix.Task.run("loadpaths", args)
"--no-compile" not in args && Mix.Task.run("compile", args)
end
apps =
if apps_paths = Mix.Project.apps_paths() do
# TODO: Use the proper ordering from Mix.Project.deps_apps
# when we depend on Elixir v1.11+.
apps_paths |> Map.keys() |> Enum.sort()
else
[Mix.Project.config()[:app]]
end
apps
|> Enum.flat_map(fn app ->
Application.load(app)
app
|> Application.get_env(:ecto_migrations, [])
|> Migrator.compile()
end)
|> Enum.uniq()
end
@doc """
Parses the repository option from the given command line args list.
If no repo option is given, it is retrieved from the application environment.
"""
@spec parse_repo([term]) :: [Ecto.Repo.t()]
def parse_repo(args) do
parse_repo(args, [])
end
defp parse_repo([key, value | t], acc) when key in ~w(--repo -r) do
parse_repo(t, [Module.concat([value]) | acc])
end
defp parse_repo([_ | t], acc) do
parse_repo(t, acc)
end
defp parse_repo([], []) do
apps =
if apps_paths = Mix.Project.apps_paths() do
# TODO: Use the proper ordering from Mix.Project.deps_apps
# when we depend on Elixir v1.11+.
apps_paths |> Map.keys() |> Enum.sort()
else
[Mix.Project.config()[:app]]
end
apps
|> Enum.flat_map(fn app ->
Application.load(app)
Application.get_env(app, :ecto_repos, [])
end)
|> Enum.uniq()
|> case do
[] ->
Mix.shell().error("""
warning: could not find Ecto repos in any of the apps: #{inspect(apps)}.
You can avoid this warning by passing the -r flag or by setting the
repositories managed by those applications in your config/config.exs:
config #{inspect(hd(apps))}, ecto_repos: [...]
""")
[]
repos ->
repos
end
end
defp parse_repo([], acc) do
Enum.reverse(acc)
end
end