Skip to content

Commit 6f50980

Browse files
committed
Merge pull request #2195 from ericmj/remote-converger-children
Allow remote converger to set children of dependency
2 parents e667e2e + 1d12f3a commit 6f50980

File tree

6 files changed

+66
-35
lines changed

6 files changed

+66
-35
lines changed

lib/mix/lib/mix/dep.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ defmodule Mix.Dep do
1111
* `status` - the current status of the dependency, check `Mix.Dep.format_status/1` for more info;
1212
* `opts` - the options given by the developer
1313
* `deps` - dependencies of this dependency
14+
* `top_level` - true if dependency was defined in the top-level project
1415
* `manager` - the project management, possible values: `:rebar` | `:mix` | `:make` | `nil`
1516
* `from` - path to the file where the dependency was defined
16-
* `extra` - a slot for adding extra configuration based on the scm.
17-
the information on this field is private to the scm and
17+
* `extra` - a slot for adding extra configuration based on the manager.
18+
the information on this field is private to the manager and
1819
should not be relied on.
1920
2021
A dependency is in two specific states: loaded and unloaded.
@@ -33,7 +34,7 @@ defmodule Mix.Dep do
3334
3435
"""
3536
defstruct scm: nil, app: nil, requirement: nil, status: nil, opts: nil,
36-
deps: [], extra: nil, manager: nil, from: nil
37+
deps: [], top_level: false, extra: nil, manager: nil, from: nil
3738

3839
@doc """
3940
Returns all children dependencies for the current project,

lib/mix/lib/mix/dep/converger.ex

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,41 +43,60 @@ defmodule Mix.Dep.Converger do
4343
"""
4444
def all(acc, lock, opts, callback) do
4545
main = Mix.Dep.Loader.children(opts)
46+
main = Enum.map(main, &(%{&1 | top_level: true}))
4647
apps = Enum.map(main, &(&1.app))
4748
converger = Mix.RemoteConverger.get
4849

4950
# Run converger for all dependencies not handled by remote
5051
# converger. If `rest` is not nil we know dependencies are
5152
# being updated or fetched for the first time (only then do
5253
# we want the remote converger to run)
53-
result =
54+
{deps, rest, lock} =
5455
all(main, [], [], apps, callback, acc, lock, fn dep ->
5556
if not nil?(lock) && converger && converger.remote?(dep) do
5657
{:loaded, dep}
5758
else
58-
{:unloaded, dep}
59+
{:unloaded, dep, nil}
5960
end
6061
end)
6162

6263
# Run remote converger if one is available and rerun mix's
6364
# converger with the new information
64-
case converger && result do
65-
{deps, rest, lock} when not nil?(lock) ->
66-
new_lock = converger.converge(main, lock)
65+
if converger do
66+
Code.ensure_loaded?(converger)
6767

68-
deps = deps
69-
|> Enum.reject(&converger.remote?(&1))
70-
|> Enum.into(HashDict.new, &{&1.app, &1})
68+
unless function_exported?(converger, :deps, 2) do
69+
raise Mix.Error, message: "Update Hex to the latest version"
70+
end
71+
72+
# If there is a lock, it means we are doing a get/update
73+
# and we need to hit the remote converger which do external
74+
# requests and what not. In case of deps.check, deps and so
75+
# on, there is no lock, so we won't hit this branch.
76+
if lock do
77+
lock = converger.converge(deps, lock)
78+
end
7179

72-
all(main, [], [], apps, callback, rest, new_lock, fn dep ->
73-
if cached = deps[dep.app] do
80+
deps = deps
81+
|> Enum.reject(&converger.remote?(&1))
82+
|> Enum.into(HashDict.new, &{&1.app, &1})
83+
84+
# In case there is no lock, we will read the current lock
85+
# which is potentially stale. So converger.deps needs to
86+
# always check if the data it finds on the lock is actually
87+
# valid.
88+
lock_for_converger = lock || Mix.Dep.Lock.read
89+
90+
all(main, [], [], apps, callback, rest, lock, fn dep ->
91+
cond do
92+
cached = deps[dep.app] ->
7493
{:loaded, cached}
75-
else
76-
{:unloaded, dep}
77-
end
78-
end)
79-
_ ->
80-
result
94+
true ->
95+
{:unloaded, dep, converger.deps(dep, lock_for_converger)}
96+
end
97+
end)
98+
else
99+
{deps, rest, lock}
81100
end
82101
end
83102

@@ -129,13 +148,13 @@ defmodule Mix.Dep.Converger do
129148
case cache.(dep) do
130149
{:loaded, cached_dep} ->
131150
cached_dep
132-
{:unloaded, dep} ->
151+
{:unloaded, dep, children} ->
133152
{dep, rest, lock} = callback.(dep, rest, lock)
134153

135154
# After we invoke the callback (which may actually check out the
136155
# dependency), we load the dependency including its latest info
137156
# and children information.
138-
Mix.Dep.Loader.load(dep)
157+
Mix.Dep.Loader.load(dep, children)
139158
end
140159

141160
dep = %{dep | deps: reject_non_fullfilled_optional(dep.deps, current_breadths)}

lib/mix/lib/mix/dep/loader.ex

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,33 +36,33 @@ defmodule Mix.Dep.Loader do
3636
Loads the given dependency information, including its
3737
latest status and children.
3838
"""
39-
def load(dep) do
39+
def load(dep, children) do
4040
%Mix.Dep{manager: manager, scm: scm, opts: opts} = dep
4141
dep = %{dep | status: scm_status(scm, opts)}
4242
dest = opts[:dest]
4343

4444
{dep, children} =
4545
cond do
4646
not ok?(dep.status) ->
47-
{dep, []}
47+
{dep, children}
4848

4949
manager == :rebar ->
50-
rebar_dep(dep)
50+
rebar_dep(dep, children)
5151

5252
mix?(dest) ->
53-
mix_dep(%{dep | manager: :mix})
53+
mix_dep(%{dep | manager: :mix}, children)
5454

5555
rebar?(dest) ->
56-
rebar_dep(%{dep | manager: :rebar})
56+
rebar_dep(%{dep | manager: :rebar}, children)
5757

5858
make?(dest) ->
59-
{%{dep | manager: :make}, []}
59+
{%{dep | manager: :make}, children}
6060

6161
true ->
62-
{dep, []}
62+
{dep, children}
6363
end
6464

65-
%{validate_path(validate_app(dep)) | deps: children}
65+
%{validate_path(validate_app(dep)) | deps: children || []}
6666
end
6767

6868
@doc """
@@ -205,7 +205,7 @@ defmodule Mix.Dep.Loader do
205205

206206
## Fetching
207207

208-
defp mix_dep(%Mix.Dep{opts: opts} = dep) do
208+
defp mix_dep(%Mix.Dep{opts: opts} = dep, children) do
209209
Mix.Dep.in_dependency(dep, fn _ ->
210210
config = Mix.project
211211
umbrella? = Mix.Project.umbrella?
@@ -219,18 +219,17 @@ defmodule Mix.Dep.Loader do
219219
"but you are running on v#{System.version}"
220220
end
221221

222-
children = children(env: opts[:env] || :prod)
223222
dep = %{dep | manager: :mix, opts: opts, extra: [umbrella: umbrella?]}
224-
{dep, children}
223+
{dep, children || children(env: opts[:env] || :prod)}
225224
end)
226225
end
227226

228-
defp rebar_dep(%Mix.Dep{} = dep) do
227+
defp rebar_dep(%Mix.Dep{} = dep, children) do
229228
Mix.Dep.in_dependency(dep, fn _ ->
230229
rebar = Mix.Rebar.load_config(".")
231230
extra = Dict.take(rebar, [:sub_dirs])
232231
dep = %{dep | manager: :rebar, extra: extra}
233-
{dep, rebar_children(rebar)}
232+
{dep, children || rebar_children(rebar)}
234233
end)
235234
end
236235

lib/mix/lib/mix/dep/umbrella.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ defmodule Mix.Dep.Umbrella do
2929
apps = Enum.map(deps, &(&1.app))
3030

3131
Enum.map(deps, fn umbrella_dep ->
32-
umbrella_dep = Mix.Dep.Loader.load(umbrella_dep)
32+
umbrella_dep = Mix.Dep.Loader.load(umbrella_dep, nil)
3333
deps = Enum.filter(umbrella_dep.deps, fn dep ->
3434
Mix.Dep.available?(dep) and dep.app in apps
3535
end)

lib/mix/lib/mix/remote_converger.ex

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ defmodule Mix.RemoteConverger do
1919
"""
2020
defcallback converge([Mix.Dep.t], map) :: map
2121

22+
@doc """
23+
Returns a loaded list of child dependencies the converger has
24+
for the dependency. This list should override what is specified
25+
in mix.exs or rebar.config.
26+
"""
27+
defcallback deps(Mix.Dep.t, map) :: [Mix.Dep.t]
28+
29+
2230
@doc """
2331
Get registered remote converger.
2432
"""

lib/mix/test/mix/dep_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ defmodule Mix.DepTest do
189189
Process.put(:remote_converger, true)
190190
lock
191191
end
192+
193+
def deps(_deps, _lock) do
194+
[]
195+
end
192196
end
193197

194198
test "remote converger" do

0 commit comments

Comments
 (0)