Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 34 additions & 24 deletions lib/mix/lib/mix/dep/converger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ defmodule Mix.Dep.Converger do
def converge(acc, lock, opts, callback) do
{deps, acc, lock} = all(acc, lock, opts, callback)
if remote = Mix.RemoteConverger.get(), do: remote.post_converge()
{topological_sort(deps), acc, lock}

deps =
deps
|> Enum.map(&Mix.Dep.Loader.validate_app_async/1)
|> Enum.map(&Mix.Dep.Loader.validate_app_callback/1)
|> topological_sort()

{deps, acc, lock}
end

defp all(acc, lock, opts, callback) do
Expand Down Expand Up @@ -298,35 +305,38 @@ defmodule Mix.Dep.Converger do
)
end

cond do
in_upper? && other_opts[:override] ->
{:match, list}
if in_upper? && other_opts[:override] do
{:match, list}
else
other = Mix.Dep.Loader.validate_app(other)

not converge?(other, dep) ->
tag = if in_upper?, do: :overridden, else: :diverged
other = %{other | status: {tag, dep}}
{:match, pre ++ [other | pos]}
cond do
not converge?(other, dep) ->
tag = if in_upper?, do: :overridden, else: :diverged
other = %{other | status: {tag, dep}}
{:match, pre ++ [other | pos]}

vsn = req_mismatch(other, dep) ->
other = %{other | status: {:divergedreq, vsn, dep}}
{:match, pre ++ [other | pos]}
vsn = req_mismatch(other, dep) ->
other = %{other | status: {:divergedreq, vsn, dep}}
{:match, pre ++ [other | pos]}

not in_upper? and Mix.Dep.Loader.skip?(other, env_target) and
not Mix.Dep.Loader.skip?(dep, env_target) ->
dep =
dep
|> with_matching_only_and_targets(other, in_upper?)
|> merge_manager(other, in_upper?)
not in_upper? and Mix.Dep.Loader.skip?(other, env_target) and
not Mix.Dep.Loader.skip?(dep, env_target) ->
dep =
dep
|> with_matching_only_and_targets(other, in_upper?)
|> merge_manager(other, in_upper?)

{:replace, dep, pre ++ pos}
{:replace, dep, pre ++ pos}

true ->
other =
other
|> with_matching_only_and_targets(dep, in_upper?)
|> merge_manager(dep, in_upper?)
true ->
other =
other
|> with_matching_only_and_targets(dep, in_upper?)
|> merge_manager(dep, in_upper?)

{:match, pre ++ [other | pos]}
{:match, pre ++ [other | pos]}
end
end
end
end
Expand Down
58 changes: 46 additions & 12 deletions lib/mix/lib/mix/dep/loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ defmodule Mix.Dep.Loader do
{dep, []}
end

validate_app(%{dep | deps: attach_only_and_targets(children, opts)})
%{dep | deps: attach_only_and_targets(children, opts)}
end

@doc """
Expand Down Expand Up @@ -378,30 +378,64 @@ defmodule Mix.Dep.Loader do
defp overrides(:rebar3, config), do: config[:overrides] || []
defp overrides(_, _config), do: []

defp validate_app(%Mix.Dep{opts: opts, requirement: req, app: app} = dep) do
opts_app = opts[:app]
@doc """
Validates the application of a dependency.
"""
def validate_app(dep) do
validate_app_callback(init_validate_app(dep))
end

cond do
not ok?(dep) ->
@doc """
Validates the application of a dependency asynchronously.
"""
def validate_app_async(dep) do
case init_validate_app(dep) do
{dep, nil} ->
{dep, nil}

{dep, callback} ->
task = Task.async(callback)
{dep, fn -> Task.await(task, :infinity) end}
end
end

@doc """
Awaits for the result of `validate_app_async/1`.
"""
def validate_app_callback(pair) do
case pair do
{dep, nil} ->
dep

{dep, callback} ->
case callback.() do
{:ok, vsn, app} -> %{dep | status: {:ok, vsn}, opts: [app_properties: app] ++ dep.opts}
status -> %{dep | status: status}
end
end
end

defp init_validate_app(
%Mix.Dep{status: {:ok, nil}, opts: opts, requirement: req, app: app} = dep
) do
opts_app = opts[:app]

cond do
recently_fetched?(dep) ->
%{dep | status: :compile}
{%{dep | status: :compile}, nil}

opts_app == false ->
dep
{dep, nil}

true ->
path = if is_binary(opts_app), do: opts_app, else: "ebin/#{app}.app"
path = Path.expand(path, opts[:build])

case app_status(path, app, req) do
{:ok, vsn, app} -> %{dep | status: {:ok, vsn}, opts: [app_properties: app] ++ opts}
status -> %{dep | status: status}
end
{dep, fn -> app_status(path, app, req) end}
end
end

defp init_validate_app(dep), do: {dep, nil}

defp recently_fetched?(%Mix.Dep{opts: opts, scm: scm}) do
scm.fetchable?() and not File.exists?(Path.join(opts[:build], ".mix/compile.fetch"))
end
Expand Down
Loading