Skip to content

Commit 10fabe6

Browse files
committed
Try loading and validating apps concurrently
1 parent 2db9796 commit 10fabe6

File tree

2 files changed

+80
-36
lines changed

2 files changed

+80
-36
lines changed

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

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,14 @@ defmodule Mix.Dep.Converger do
8888
def converge(acc, lock, opts, callback) do
8989
{deps, acc, lock} = all(acc, lock, opts, callback)
9090
if remote = Mix.RemoteConverger.get(), do: remote.post_converge()
91-
{topological_sort(deps), acc, lock}
91+
92+
deps =
93+
deps
94+
|> Enum.map(&Mix.Dep.Loader.validate_app_async/1)
95+
|> Enum.map(&Mix.Dep.Loader.validate_app_callback/1)
96+
|> topological_sort()
97+
98+
{deps, acc, lock}
9299
end
93100

94101
defp all(acc, lock, opts, callback) do
@@ -298,35 +305,38 @@ defmodule Mix.Dep.Converger do
298305
)
299306
end
300307

301-
cond do
302-
in_upper? && other_opts[:override] ->
303-
{:match, list}
308+
if in_upper? && other_opts[:override] do
309+
{:match, list}
310+
else
311+
other = Mix.Dep.Loader.validate_app(other)
304312

305-
not converge?(other, dep) ->
306-
tag = if in_upper?, do: :overridden, else: :diverged
307-
other = %{other | status: {tag, dep}}
308-
{:match, pre ++ [other | pos]}
313+
cond do
314+
not converge?(other, dep) ->
315+
tag = if in_upper?, do: :overridden, else: :diverged
316+
other = %{other | status: {tag, dep}}
317+
{:match, pre ++ [other | pos]}
309318

310-
vsn = req_mismatch(other, dep) ->
311-
other = %{other | status: {:divergedreq, vsn, dep}}
312-
{:match, pre ++ [other | pos]}
319+
vsn = req_mismatch(other, dep) ->
320+
other = %{other | status: {:divergedreq, vsn, dep}}
321+
{:match, pre ++ [other | pos]}
313322

314-
not in_upper? and Mix.Dep.Loader.skip?(other, env_target) and
315-
not Mix.Dep.Loader.skip?(dep, env_target) ->
316-
dep =
317-
dep
318-
|> with_matching_only_and_targets(other, in_upper?)
319-
|> merge_manager(other, in_upper?)
323+
not in_upper? and Mix.Dep.Loader.skip?(other, env_target) and
324+
not Mix.Dep.Loader.skip?(dep, env_target) ->
325+
dep =
326+
dep
327+
|> with_matching_only_and_targets(other, in_upper?)
328+
|> merge_manager(other, in_upper?)
320329

321-
{:replace, dep, pre ++ pos}
330+
{:replace, dep, pre ++ pos}
322331

323-
true ->
324-
other =
325-
other
326-
|> with_matching_only_and_targets(dep, in_upper?)
327-
|> merge_manager(dep, in_upper?)
332+
true ->
333+
other =
334+
other
335+
|> with_matching_only_and_targets(dep, in_upper?)
336+
|> merge_manager(dep, in_upper?)
328337

329-
{:match, pre ++ [other | pos]}
338+
{:match, pre ++ [other | pos]}
339+
end
330340
end
331341
end
332342
end

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

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ defmodule Mix.Dep.Loader do
106106
{dep, []}
107107
end
108108

109-
validate_app(%{dep | deps: attach_only_and_targets(children, opts)})
109+
%{dep | deps: attach_only_and_targets(children, opts)}
110110
end
111111

112112
@doc """
@@ -378,30 +378,64 @@ defmodule Mix.Dep.Loader do
378378
defp overrides(:rebar3, config), do: config[:overrides] || []
379379
defp overrides(_, _config), do: []
380380

381-
defp validate_app(%Mix.Dep{opts: opts, requirement: req, app: app} = dep) do
382-
opts_app = opts[:app]
381+
@doc """
382+
Validates the application of a dependency.
383+
"""
384+
def validate_app(dep) do
385+
validate_app_callback(init_validate_app(dep))
386+
end
383387

384-
cond do
385-
not ok?(dep) ->
388+
@doc """
389+
Validates the application of a dependency asynchronously.
390+
"""
391+
def validate_app_async(dep) do
392+
case init_validate_app(dep) do
393+
{dep, nil} ->
394+
{dep, nil}
395+
396+
{dep, callback} ->
397+
task = Task.async(callback)
398+
{dep, fn -> Task.await(task, :infinity) end}
399+
end
400+
end
401+
402+
@doc """
403+
Awaits for the result of `validate_app_async/1`.
404+
"""
405+
def validate_app_callback(pair) do
406+
case pair do
407+
{dep, nil} ->
386408
dep
387409

410+
{dep, callback} ->
411+
case callback.() do
412+
{:ok, vsn, app} -> %{dep | status: {:ok, vsn}, opts: [app_properties: app] ++ dep.opts}
413+
status -> %{dep | status: status}
414+
end
415+
end
416+
end
417+
418+
defp init_validate_app(
419+
%Mix.Dep{status: {:ok, nil}, opts: opts, requirement: req, app: app} = dep
420+
) do
421+
opts_app = opts[:app]
422+
423+
cond do
388424
recently_fetched?(dep) ->
389-
%{dep | status: :compile}
425+
{%{dep | status: :compile}, nil}
390426

391427
opts_app == false ->
392-
dep
428+
{dep, nil}
393429

394430
true ->
395431
path = if is_binary(opts_app), do: opts_app, else: "ebin/#{app}.app"
396432
path = Path.expand(path, opts[:build])
397-
398-
case app_status(path, app, req) do
399-
{:ok, vsn, app} -> %{dep | status: {:ok, vsn}, opts: [app_properties: app] ++ opts}
400-
status -> %{dep | status: status}
401-
end
433+
{dep, fn -> app_status(path, app, req) end}
402434
end
403435
end
404436

437+
defp init_validate_app(dep), do: {dep, nil}
438+
405439
defp recently_fetched?(%Mix.Dep{opts: opts, scm: scm}) do
406440
scm.fetchable?() and not File.exists?(Path.join(opts[:build], ".mix/compile.fetch"))
407441
end

0 commit comments

Comments
 (0)