-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
ecto.ex
123 lines (108 loc) · 3.39 KB
/
ecto.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
defmodule Mix.Ecto do
@moduledoc """
Conveniences for writing Ecto related Mix tasks.
"""
@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
@doc """
Ensures the given module is an Ecto.Repo.
"""
@spec ensure_repo(module, list) :: Ecto.Repo.t
def ensure_repo(repo, args) do
# 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 """
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_charlist(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 project root. " <>
"Change directory to one of the umbrella applications and try again"
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