Skip to content

Commit 832c8da

Browse files
committed
Load all children before parent, closes #12598
1 parent f814cd7 commit 832c8da

File tree

4 files changed

+48
-21
lines changed

4 files changed

+48
-21
lines changed

lib/mix/lib/mix/app_loader.ex

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,13 @@ defmodule Mix.AppLoader do
5252
end
5353

5454
@doc """
55-
Loads the given app from path in an optimized format and returns its contents.
55+
Reads the given app from path in an optimized format and returns its contents.
5656
"""
57-
def load_app(app, app_path) do
57+
def read_app(app, app_path) do
5858
case File.read(app_path) do
5959
{:ok, bin} ->
6060
with {:ok, tokens, _} <- :erl_scan.string(String.to_charlist(bin)),
61-
{:ok, {:application, ^app, properties} = app_data} <- :erl_parse.parse_term(tokens),
62-
:ok <- ensure_loaded(app_data) do
61+
{:ok, {:application, ^app, properties}} <- :erl_parse.parse_term(tokens) do
6362
{:ok, properties}
6463
else
6564
_ -> :invalid
@@ -70,11 +69,16 @@ defmodule Mix.AppLoader do
7069
end
7170
end
7271

73-
defp ensure_loaded(app_data) do
74-
case :application.load(app_data) do
75-
:ok -> :ok
76-
{:error, {:already_loaded, _}} -> :ok
77-
{:error, error} -> {:error, error}
72+
@doc """
73+
Loads the given app from path in an optimized format and returns its contents.
74+
"""
75+
def load_app(app, app_path) do
76+
with {:ok, properties} <- read_app(app, app_path) do
77+
case :application.load({:application, app, properties}) do
78+
:ok -> {:ok, properties}
79+
{:error, {:already_loaded, _}} -> {:ok, properties}
80+
{:error, _} -> :invalid
81+
end
7882
end
7983
end
8084

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,10 @@ defmodule Mix.Dep.Converger do
205205
all(t, [dep | acc], upper, breadths, optional, rest, lock, state)
206206

207207
:nomatch ->
208-
{%{app: app, deps: deps, opts: opts} = dep, rest, lock} =
208+
{%{app: app, deps: deps, opts: opts} = dep, app_properties, rest, lock} =
209209
case state.cache.(dep) do
210210
{:loaded, cached_dep} ->
211-
{cached_dep, rest, lock}
211+
{cached_dep, nil, rest, lock}
212212

213213
{:unloaded, dep, children} ->
214214
{dep, rest, lock} = state.callback.(put_lock(dep, lock), rest, lock)
@@ -217,7 +217,8 @@ defmodule Mix.Dep.Converger do
217217
# After we invoke the callback (which may actually check out the
218218
# dependency), we load the dependency including its latest info
219219
# and children information.
220-
{Mix.Dep.Loader.load(dep, children, state.locked?), rest, lock}
220+
{dep, app_properties} = Mix.Dep.Loader.load(dep, children, state.locked?)
221+
{dep, app_properties, rest, lock}
221222
end)
222223
end
223224

@@ -228,11 +229,29 @@ defmodule Mix.Dep.Converger do
228229
{acc, optional, rest, lock} =
229230
all(no_longer_optional ++ t, [dep | acc], upper, breadths, optional, rest, lock, state)
230231

232+
# Now traverse all parent dependencies and see if we have any optional dependency.
231233
{discarded, deps} =
232234
split_non_fulfilled_optional(deps, Enum.map(acc, & &1.app), opts[:from_umbrella])
233235

234236
new_breadths = Enum.map(deps, & &1.app) ++ breadths
235-
all(deps, acc, breadths, new_breadths, discarded ++ optional, rest, lock, state)
237+
res = all(deps, acc, breadths, new_breadths, discarded ++ optional, rest, lock, state)
238+
239+
# After we traverse all of our children, we can load ourselves.
240+
# This is important in case of included application.
241+
if app_properties do
242+
case :application.load({:application, app, app_properties}) do
243+
:ok ->
244+
:ok
245+
246+
{:error, {:already_loaded, _}} ->
247+
:ok
248+
249+
{:error, error} ->
250+
Mix.raise("Could not start application #{inspect(app)}: #{inspect(error)}")
251+
end
252+
end
253+
254+
res
236255
end
237256
end
238257

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

Lines changed: 11 additions & 7 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+
validate_app(%{dep | deps: attach_only_and_targets(children, opts)})
110110
end
111111

112112
@doc """
@@ -383,18 +383,22 @@ defmodule Mix.Dep.Loader do
383383

384384
cond do
385385
not ok?(dep) ->
386-
dep
386+
{dep, nil}
387387

388388
recently_fetched?(dep) ->
389-
%{dep | status: :compile}
389+
{%{dep | status: :compile}, nil}
390390

391391
opts_app == false ->
392-
dep
392+
{dep, nil}
393393

394394
true ->
395395
path = if is_binary(opts_app), do: opts_app, else: "ebin/#{app}.app"
396396
path = Path.expand(path, opts[:build])
397-
%{dep | status: app_status(path, app, req)}
397+
398+
case app_status(path, app, req) do
399+
{:ok, vsn, app} -> {%{dep | status: {:ok, vsn}}, app}
400+
status -> {%{dep | status: status}, nil}
401+
end
398402
end
399403
end
400404

@@ -411,7 +415,7 @@ defmodule Mix.Dep.Loader do
411415
end
412416

413417
defp app_status(app_path, app, req) do
414-
case Mix.AppLoader.load_app(app, app_path) do
418+
case Mix.AppLoader.read_app(app, app_path) do
415419
{:ok, properties} ->
416420
case List.keyfind(properties, :vsn, 0) do
417421
{:vsn, actual} when is_list(actual) ->
@@ -446,7 +450,7 @@ defmodule Mix.Dep.Loader do
446450
false <- Config.Provider.valid_compile_env?(compile_env) do
447451
:compile
448452
else
449-
_ -> {:ok, vsn}
453+
_ -> {:ok, vsn, properties}
450454
end
451455
end
452456
end

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

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

6161
Enum.map(deps, fn umbrella_dep ->
62-
umbrella_dep = Mix.Dep.Loader.load(umbrella_dep, nil, false)
62+
{umbrella_dep, _} = Mix.Dep.Loader.load(umbrella_dep, nil, false)
6363

6464
deps =
6565
Enum.filter(umbrella_dep.deps, fn dep ->

0 commit comments

Comments
 (0)