@@ -83,14 +83,14 @@ defmodule Mix.Release do
83
83
{ include_erts , opts } = Keyword . pop ( opts , :include_erts , true )
84
84
{ erts_source , erts_lib_dir , erts_version } = erts_data ( include_erts )
85
85
86
- loaded_apps = apps |> Keyword . keys ( ) |> load_apps ( % { } , erts_lib_dir )
86
+ loaded_apps = apps |> Keyword . keys ( ) |> load_apps ( % { } , erts_lib_dir , :maybe )
87
87
88
88
# Make sure IEx is either an active part of the release or add it as none.
89
89
{ loaded_apps , apps } =
90
90
if Map . has_key? ( loaded_apps , :iex ) do
91
91
{ loaded_apps , apps }
92
92
else
93
- { load_apps ( [ :iex ] , loaded_apps , erts_lib_dir ) , apps ++ [ iex: :none ] }
93
+ { load_apps ( [ :iex ] , loaded_apps , erts_lib_dir , :maybe ) , apps ++ [ iex: :none ] }
94
94
end
95
95
96
96
start_boot = build_start_boot ( loaded_apps , apps )
@@ -228,36 +228,62 @@ defmodule Mix.Release do
228
228
end
229
229
end
230
230
231
- defp load_apps ( apps , seen , otp_root ) do
232
- for app <- apps ,
233
- not Map . has_key? ( seen , app ) ,
234
- reduce: seen do
235
- seen -> load_app ( app , seen , otp_root )
231
+ defp load_apps ( apps , seen , otp_root , included ) do
232
+ for app <- apps , reduce: seen do
233
+ seen ->
234
+ if reentrant_seen = reentrant ( seen , app , included ) do
235
+ reentrant_seen
236
+ else
237
+ load_app ( app , seen , otp_root , included )
238
+ end
236
239
end
237
240
end
238
241
239
- defp load_app ( app , seen , otp_root ) do
242
+ defp reentrant ( seen , app , included ) do
243
+ properties = seen [ app ]
244
+
245
+ cond do
246
+ is_nil ( properties ) ->
247
+ nil
248
+
249
+ included != :maybe and properties [ :included ] != included ->
250
+ if properties [ :included ] == :maybe do
251
+ put_in seen [ app ] [ :included ] , included
252
+ else
253
+ Mix . raise (
254
+ "#{ inspect ( app ) } is listed both as a regular application and as an included application"
255
+ )
256
+ end
257
+
258
+ true ->
259
+ seen
260
+ end
261
+ end
262
+
263
+ defp load_app ( app , seen , otp_root , included ) do
240
264
path = Path . join ( otp_root , "#{ app } -*" )
241
265
242
266
case Path . wildcard ( path ) do
243
267
[ ] ->
244
268
case :code . lib_dir ( app ) do
245
269
{ :error , :bad_name } -> Mix . raise ( "Could not find application #{ inspect ( app ) } " )
246
- path -> do_load_app ( app , path , seen , otp_root , false )
270
+ path -> do_load_app ( app , path , seen , otp_root , false , included )
247
271
end
248
272
249
273
paths ->
250
274
path = paths |> Enum . sort ( ) |> List . last ( )
251
- do_load_app ( app , to_charlist ( path ) , seen , otp_root , true )
275
+ do_load_app ( app , to_charlist ( path ) , seen , otp_root , true , included )
252
276
end
253
277
end
254
278
255
- defp do_load_app ( app , path , seen , otp_root , otp_app? ) do
279
+ defp do_load_app ( app , path , seen , otp_root , otp_app? , included ) do
256
280
case :file . consult ( Path . join ( path , "ebin/#{ app } .app" ) ) do
257
281
{ :ok , terms } ->
258
282
[ { :application , ^ app , properties } ] = terms
259
- seen = Map . put ( seen , app , [ path: path , otp_app?: otp_app? ] ++ properties )
260
- load_apps ( Keyword . get ( properties , :applications , [ ] ) , seen , otp_root )
283
+ value = [ path: path , otp_app?: otp_app? , included: included ] ++ properties
284
+ seen = Map . put ( seen , app , value )
285
+ seen = load_apps ( Keyword . get ( properties , :applications , [ ] ) , seen , otp_root , false )
286
+ load_apps ( Keyword . get ( properties , :included_applications , [ ] ) , seen , otp_root , true )
261
287
262
288
{ :error , reason } ->
263
289
Mix . raise ( "Could not load #{ app } .app. Reason: #{ inspect ( reason ) } " )
@@ -267,12 +293,16 @@ defmodule Mix.Release do
267
293
defp build_start_boot ( all_apps , specified_apps ) do
268
294
specified_apps ++
269
295
for (
270
- { app , _props } <- all_apps ,
296
+ { app , props } <- all_apps ,
271
297
not List . keymember? ( specified_apps , app , 0 ) ,
272
- do: { app , :permanent }
298
+ do: { app , default_mode ( props ) }
273
299
)
274
300
end
275
301
302
+ defp default_mode ( props ) do
303
+ if props [ :included ] == true , do: :load , else: :permanent
304
+ end
305
+
276
306
defp build_start_clean_boot ( boot ) do
277
307
for ( { app , _mode } <- boot , do: { app , :none } )
278
308
|> Keyword . put ( :stdlib , :permanent )
0 commit comments