Skip to content

Commit 4e6261a

Browse files
author
José Valim
committed
Support included applications, closes #9163
1 parent f10cf8b commit 4e6261a

File tree

2 files changed

+93
-15
lines changed

2 files changed

+93
-15
lines changed

lib/mix/lib/mix/release.ex

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,14 @@ defmodule Mix.Release do
8383
{include_erts, opts} = Keyword.pop(opts, :include_erts, true)
8484
{erts_source, erts_lib_dir, erts_version} = erts_data(include_erts)
8585

86-
loaded_apps = apps |> Keyword.keys() |> load_apps(%{}, erts_lib_dir)
86+
loaded_apps = apps |> Keyword.keys() |> load_apps(%{}, erts_lib_dir, :maybe)
8787

8888
# Make sure IEx is either an active part of the release or add it as none.
8989
{loaded_apps, apps} =
9090
if Map.has_key?(loaded_apps, :iex) do
9191
{loaded_apps, apps}
9292
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]}
9494
end
9595

9696
start_boot = build_start_boot(loaded_apps, apps)
@@ -228,36 +228,62 @@ defmodule Mix.Release do
228228
end
229229
end
230230

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
236239
end
237240
end
238241

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
240264
path = Path.join(otp_root, "#{app}-*")
241265

242266
case Path.wildcard(path) do
243267
[] ->
244268
case :code.lib_dir(app) do
245269
{: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)
247271
end
248272

249273
paths ->
250274
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)
252276
end
253277
end
254278

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
256280
case :file.consult(Path.join(path, "ebin/#{app}.app")) do
257281
{:ok, terms} ->
258282
[{: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)
261287

262288
{:error, reason} ->
263289
Mix.raise("Could not load #{app}.app. Reason: #{inspect(reason)}")
@@ -267,12 +293,16 @@ defmodule Mix.Release do
267293
defp build_start_boot(all_apps, specified_apps) do
268294
specified_apps ++
269295
for(
270-
{app, _props} <- all_apps,
296+
{app, props} <- all_apps,
271297
not List.keymember?(specified_apps, app, 0),
272-
do: {app, :permanent}
298+
do: {app, default_mode(props)}
273299
)
274300
end
275301

302+
defp default_mode(props) do
303+
if props[:included] == true, do: :load, else: :permanent
304+
end
305+
276306
defp build_start_clean_boot(boot) do
277307
for({app, _mode} <- boot, do: {app, :none})
278308
|> Keyword.put(:stdlib, :permanent)

lib/mix/test/mix/release_test.exs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,54 @@ defmodule Mix.ReleaseTest do
569569
end
570570
end
571571

572+
describe "included applications" do
573+
test "are included in the release", context do
574+
in_tmp(context.test, fn ->
575+
app =
576+
{:application, :my_sample1,
577+
applications: [:kernel, :stdlib, :elixir],
578+
description: 'my_sample1',
579+
modules: [],
580+
vsn: '1.0.0',
581+
included_applications: [:runtime_tools]}
582+
583+
File.mkdir_p!("my_sample1/ebin")
584+
Code.prepend_path("my_sample1/ebin")
585+
format = :io_lib.format("%% coding: utf-8~n~p.~n", [app])
586+
File.write!("my_sample1/ebin/my_sample1.app", format)
587+
588+
release = release(applications: [my_sample1: :permanent])
589+
assert release.applications.runtime_tools[:included]
590+
assert release.boot_scripts.start[:runtime_tools] == :load
591+
592+
release = release(applications: [my_sample1: :permanent, runtime_tools: :none])
593+
assert release.applications.runtime_tools[:included]
594+
assert release.boot_scripts.start[:runtime_tools] == :none
595+
end)
596+
end
597+
598+
test "raise on conflict", context do
599+
in_tmp(context.test, fn ->
600+
app =
601+
{:application, :my_sample2,
602+
applications: [:kernel, :stdlib, :elixir, :runtime_tools],
603+
description: 'my_sample',
604+
modules: [],
605+
vsn: '1.0.0',
606+
included_applications: [:runtime_tools]}
607+
608+
File.mkdir_p!("my_sample2/ebin")
609+
Code.prepend_path("my_sample2/ebin")
610+
format = :io_lib.format("%% coding: utf-8~n~p.~n", [app])
611+
File.write!("my_sample2/ebin/my_sample2.app", format)
612+
613+
assert_raise Mix.Error,
614+
":runtime_tools is listed both as a regular application and as an included application",
615+
fn -> release(applications: [my_sample2: :permanent]) end
616+
end)
617+
end
618+
end
619+
572620
defp size!(path) do
573621
File.stat!(path).size
574622
end

0 commit comments

Comments
 (0)