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