@@ -95,32 +95,50 @@ defmodule Mix.Tasks.Compile.All do
95
95
96
96
defp load_apps ( config , validate_compile_env? ) do
97
97
{ runtime , optional } = Mix.Tasks.Compile.App . project_apps ( config )
98
+ parent = self ( )
99
+ opts = [ ordered: false , timeout: :infinity ]
98
100
99
- % { }
100
- |> load_apps ( runtime , validate_compile_env? )
101
- |> load_apps ( optional , validate_compile_env? )
101
+ stream_apps ( runtime ++ optional )
102
+ |> Task . async_stream ( & load_app ( & 1 , parent , validate_compile_env? ) , opts )
103
+ |> Stream . run ( )
104
+ end
105
+
106
+ defp load_app ( app , parent , validate_compile_env? ) do
107
+ case load_app ( app , validate_compile_env? ) do
108
+ :ok ->
109
+ send ( parent , { :done , app , Application . spec ( app , :applications ) ++ Application . spec ( app , :included_applications ) } )
110
+
111
+ :error ->
112
+ send ( parent , { :done , app , [ ] } )
113
+ end
102
114
103
115
:ok
104
116
end
105
117
106
- defp load_apps ( seen , apps , validate_compile_env? ) do
107
- Enum . reduce ( apps , seen , fn app , seen ->
108
- if Map . has_key? ( seen , app ) do
109
- seen
110
- else
111
- seen = Map . put ( seen , app , true )
118
+ defp stream_apps ( initial ) do
119
+ Stream . unfold ( { initial , % { } , % { } } , & stream_app / 1 )
120
+ end
112
121
113
- case load_app ( app , validate_compile_env? ) do
114
- :ok ->
115
- seen
116
- |> load_apps ( Application . spec ( app , :applications ) , validate_compile_env? )
117
- |> load_apps ( Application . spec ( app , :included_applications ) , validate_compile_env? )
122
+ # We already processed this app, skip it.
123
+ defp stream_app ( { [ app | apps ] , seen , done } ) when is_map_key ( seen , app ) do
124
+ stream_app ( { apps , seen , done } )
125
+ end
118
126
119
- :error ->
120
- seen
121
- end
122
- end
123
- end )
127
+ # We haven't processed this app, emit it.
128
+ defp stream_app ( { [ app | apps ] , seen , done } ) do
129
+ { app , { apps , Map . put ( seen , app , true ) , done } }
130
+ end
131
+
132
+ # We have processed all apps and all seen have been done.
133
+ defp stream_app ( { [ ] , seen , done } ) when map_size ( seen ) == map_size ( done ) do
134
+ nil
135
+ end
136
+
137
+ # We have processed all apps but there is work being done.
138
+ defp stream_app ( { [ ] , seen , done } ) do
139
+ receive do
140
+ { :done , app , children } -> stream_app ( { children , seen , Map . put ( done , app , true ) } )
141
+ end
124
142
end
125
143
126
144
defp load_app ( app , validate_compile_env? ) do
0 commit comments