Skip to content

Commit 5331174

Browse files
essejosevalim
authored andcommitted
Allow using remote or rpc with compile_env
Signed-off-by: José Valim <[email protected]>
1 parent f4f2be6 commit 5331174

File tree

4 files changed

+104
-59
lines changed

4 files changed

+104
-59
lines changed

lib/elixir/lib/config/provider.ex

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ defmodule Config.Provider do
110110
:config_path,
111111
extra_config: [],
112112
prune_after_boot: false,
113-
reboot_after_config: true
113+
reboot_after_config: true,
114+
validate_compile_env: false
114115
]
115116

116117
@doc """
@@ -165,54 +166,74 @@ defmodule Config.Provider do
165166
# before we go around running Elixir code.
166167
{:ok, _} = :application.ensure_all_started(:elixir)
167168

168-
case :application.get_env(app, key) do
169-
{:ok, %Config.Provider{} = provider} ->
170-
path = resolve_config_path!(provider.config_path)
171-
validate_no_cyclic_boot!(path)
172-
loaded_applications = :application.loaded_applications()
173-
original_config = read_config!(path)
169+
# The key we store if the system already booted
170+
booted_key = :"#{key}_booted"
174171

175-
config =
176-
original_config
177-
|> Config.__merge__(provider.extra_config)
178-
|> run_providers(provider)
172+
case :application.get_env(app, booted_key) do
173+
{:ok, {:booted, path}} ->
174+
path && File.rm(path)
179175

180-
if provider.reboot_after_config do
181-
config
182-
|> Config.__merge__([{app, [{key, booted_key(provider, path)}]}])
183-
|> write_config!(path)
176+
with {:ok, %Config.Provider{} = provider} <- :application.get_env(app, key) do
177+
maybe_validate_compile_env(provider)
178+
end
184179

185-
restart_fun.()
186-
else
187-
for {app, _, _} <- loaded_applications, config[app] != original_config[app] do
188-
abort("""
189-
Cannot configure #{inspect(app)} because :reboot_after_config has been set \
190-
to false and #{inspect(app)} has already been loaded, meaning any further \
191-
configuration won't have an effect.
180+
:booted
192181

193-
The configuration for #{inspect(app)} before config providers was:
182+
_ ->
183+
case :application.get_env(app, key) do
184+
{:ok, %Config.Provider{} = provider} ->
185+
path = resolve_config_path!(provider.config_path)
186+
reboot_config = [{app, [{booted_key, booted_value(provider, path)}]}]
187+
boot_providers(path, provider, reboot_config, restart_fun)
188+
189+
_ ->
190+
:skip
191+
end
192+
end
193+
end
194194

195-
#{inspect(original_config[app])}
195+
defp boot_providers(path, provider, reboot_config, restart_fun) do
196+
validate_no_cyclic_boot!(path)
197+
loaded_applications = :application.loaded_applications()
198+
original_config = read_config!(path)
196199

197-
The configuration for #{inspect(app)} after config providers was:
200+
config =
201+
original_config
202+
|> Config.__merge__(provider.extra_config)
203+
|> run_providers(provider)
198204

199-
#{inspect(config[app])}
200-
""")
201-
end
205+
if provider.reboot_after_config do
206+
config
207+
|> Config.__merge__(reboot_config)
208+
|> write_config!(path)
202209

203-
_ = Application.put_all_env(config, persistent: true)
204-
:ok
205-
end
210+
restart_fun.()
211+
else
212+
for {app, _, _} <- loaded_applications, config[app] != original_config[app] do
213+
abort("""
214+
Cannot configure #{inspect(app)} because :reboot_after_config has been set \
215+
to false and #{inspect(app)} has already been loaded, meaning any further \
216+
configuration won't have an effect.
206217
207-
{:ok, {:booted, path}} ->
208-
File.rm(path)
209-
:booted
218+
The configuration for #{inspect(app)} before config providers was:
210219
211-
{:ok, :booted} ->
212-
:booted
220+
#{inspect(original_config[app])}
213221
214-
_ ->
215-
:skip
222+
The configuration for #{inspect(app)} after config providers was:
223+
224+
#{inspect(config[app])}
225+
""")
226+
end
227+
228+
_ = Application.put_all_env(config, persistent: true)
229+
maybe_validate_compile_env(provider)
230+
:ok
231+
end
232+
end
233+
234+
defp maybe_validate_compile_env(provider) do
235+
with [_ | _] = compile_env <- provider.validate_compile_env do
236+
validate_compile_env(compile_env)
216237
end
217238
end
218239

@@ -283,8 +304,8 @@ defmodule Config.Provider do
283304
Process.sleep(:infinity)
284305
end
285306

286-
defp booted_key(%{prune_after_boot: true}, path), do: {:booted, path}
287-
defp booted_key(%{prune_after_boot: false}, _path), do: :booted
307+
defp booted_value(%{prune_after_boot: true}, path), do: {:booted, path}
308+
defp booted_value(%{prune_after_boot: false}, _path), do: {:booted, nil}
288309

289310
defp validate_no_cyclic_boot!(path) do
290311
if System.get_env("ELIXIR_CONFIG_PROVIDER_BOOTED") do

lib/elixir/test/elixir/config/provider_test.exs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ defmodule Config.ProviderTest do
2020

2121
on_exit(fn ->
2222
Application.delete_env(@config_app, :config_providers)
23+
Application.delete_env(@config_app, :config_providers_booted)
2324
System.delete_env(@env_var)
2425
end)
2526
end
@@ -79,7 +80,7 @@ defmodule Config.ProviderTest do
7980
init_and_assert_boot()
8081
config = consult(@sys_config)
8182
assert config[:my_app] == [key: :value]
82-
assert config[@config_app] == [config_providers: :booted]
83+
assert config[@config_app] == [config_providers_booted: {:booted, nil}]
8384
end
8485

8586
@tag sys_config: [my_app: [encoding: {:"£", "£", '£'}]]
@@ -113,6 +114,18 @@ defmodule Config.ProviderTest do
113114
refute File.exists?(@sys_config)
114115
end
115116

117+
test "returns :booted if already booted and runs validate_compile_env" do
118+
init_and_assert_boot(
119+
prune_after_boot: true,
120+
validate_compile_env: [{:elixir, [:unknown], {:ok, :value}}]
121+
)
122+
123+
Application.put_all_env(Keyword.take(consult(@sys_config), [@config_app]))
124+
125+
assert capture_abort(fn -> boot() end) =~
126+
"the application :elixir has a different value set for key :unknown"
127+
end
128+
116129
test "raises if booting twice in a row" do
117130
init_and_assert_boot()
118131

lib/mix/lib/mix/release.ex

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -425,13 +425,29 @@ defmodule Mix.Release do
425425
opts = [
426426
extra_config: initial_config,
427427
prune_after_boot: prune_after_boot,
428-
reboot_after_config: reboot?
428+
reboot_after_config: reboot?,
429+
validate_compile_env: validate_compile_env(release)
429430
]
430431

431432
init = Config.Provider.init(release.config_providers, config_path, opts)
432433
{Config.Reader.merge(sys_config, [elixir: [config_providers: init]] ++ extra_config), reboot?}
433434
end
434435

436+
defp validate_compile_env(release) do
437+
with true <- Keyword.get(release.options, :validate_compile_env, true),
438+
[_ | _] = compile_env <- compile_env(release) do
439+
compile_env
440+
else
441+
_ -> false
442+
end
443+
end
444+
445+
defp compile_env(release) do
446+
for {_, properties} <- release.applications,
447+
triplet <- Keyword.get(properties, :compile_env, []),
448+
do: triplet
449+
end
450+
435451
defp start_distribution(%{options: opts}) do
436452
reboot? = Keyword.get(opts, :reboot_system_after_config, true)
437453
early_distribution? = Keyword.get(opts, :start_distribution_during_config, false)
@@ -613,8 +629,7 @@ defmodule Mix.Release do
613629
&(not match?({:apply, {:application, :start_boot, [:stdlib, _]}}, &1))
614630
)
615631

616-
pre ++
617-
[stdlib] ++ config_provider_apply(release) ++ validate_compile_env_apply(release) ++ post
632+
pre ++ [stdlib] ++ config_provider_apply(release) ++ post
618633
end
619634

620635
defp config_provider_apply(%{config_providers: []}),
@@ -623,21 +638,6 @@ defmodule Mix.Release do
623638
defp config_provider_apply(_),
624639
do: [{:apply, {Config.Provider, :boot, [:elixir, :config_providers]}}]
625640

626-
defp validate_compile_env_apply(release) do
627-
with true <- Keyword.get(release.options, :validate_compile_env, true),
628-
[_ | _] = compile_env <- compile_env(release) do
629-
[{:apply, {Config.Provider, :validate_compile_env, [compile_env]}}]
630-
else
631-
_ -> []
632-
end
633-
end
634-
635-
defp compile_env(release) do
636-
for {_, properties} <- release.applications,
637-
triplet <- Keyword.get(properties, :compile_env, []),
638-
do: triplet
639-
end
640-
641641
defp prepend_paths_to_script(instructions, []), do: instructions
642642

643643
defp prepend_paths_to_script(instructions, prepend_paths) do

lib/mix/test/mix/tasks/release_test.exs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,18 @@ defmodule Mix.Tasks.ReleaseTest do
514514
in_fixture("release_test", fn ->
515515
config = [releases: [permanent1: [include_erts: false]]]
516516

517+
# We write the compile env to guarantee rpc still works
518+
File.write!("lib/compile_env.ex", """
519+
_ = Application.compile_env(:release_test, :static)
520+
""")
521+
517522
Mix.Project.in_project(:release_test, ".", config, fn _ ->
523+
Mix.Task.run("loadconfig", [])
524+
525+
File.write!("config/releases.exs", """
526+
import Config
527+
""")
528+
518529
root = Path.absname("_build/dev/rel/permanent1")
519530
Mix.Task.run("release")
520531
script = Path.join(root, "bin/permanent1")

0 commit comments

Comments
 (0)