Skip to content

Commit fb2657a

Browse files
Fix compile env change triggering full recompilation of path dependencies (#15188)
1 parent 4021272 commit fb2657a

6 files changed

Lines changed: 42 additions & 14 deletions

File tree

lib/mix/lib/mix/dep.ex

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ defmodule Mix.Dep do
338338
"the dependency build is outdated, please run \"#{mix_env_var()}mix deps.compile\""
339339
end
340340

341+
def format_status(%Mix.Dep{status: :envoutdated}) do
342+
"the dependency compile environment is outdated, please run \"#{mix_env_var()}mix deps.compile\""
343+
end
344+
341345
def format_status(%Mix.Dep{app: app, status: {:divergedreq, vsn, other}} = dep) do
342346
"the dependency #{app} #{vsn}\n" <>
343347
dep_status(dep) <>
@@ -505,11 +509,20 @@ defmodule Mix.Dep do
505509
@doc """
506510
Returns `true` if the dependency is compilable.
507511
"""
508-
def compilable?(%Mix.Dep{status: {:vsnlock, _}}), do: true
509-
def compilable?(%Mix.Dep{status: {:noappfile, {_, _}}}), do: true
510-
def compilable?(%Mix.Dep{status: {:scmlock, _}}), do: true
511-
def compilable?(%Mix.Dep{status: :compile}), do: true
512-
def compilable?(_), do: false
512+
def compilable?(%Mix.Dep{status: :envoutdated}), do: true
513+
def compilable?(dep), do: force_compilable?(dep)
514+
515+
@doc """
516+
Returns `true` if the dependency is force compilable.
517+
518+
This is a subset of compilable. This is used in `deps.compile` to
519+
clean the build path before compiling.
520+
"""
521+
def force_compilable?(%Mix.Dep{status: {:vsnlock, _}}), do: true
522+
def force_compilable?(%Mix.Dep{status: {:noappfile, {_, _}}}), do: true
523+
def force_compilable?(%Mix.Dep{status: {:scmlock, _}}), do: true
524+
def force_compilable?(%Mix.Dep{status: :compile}), do: true
525+
def force_compilable?(_), do: false
513526

514527
@doc """
515528
Formats a dependency for printing.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ defmodule Mix.Dep.Loader do
444444
defp compile_env_status(vsn, properties) do
445445
with [_ | _] = compile_env <- properties[:compile_env],
446446
false <- Config.Provider.valid_compile_env?(compile_env) do
447-
:compile
447+
:envoutdated
448448
else
449449
_ -> {:ok, vsn, properties}
450450
end

lib/mix/lib/mix/tasks/compile.app.ex

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,13 @@ defmodule Mix.Tasks.Compile.App do
161161
|> max(Mix.Utils.last_modified(compile_path))
162162

163163
current_properties = current_app_properties(target)
164+
current_compile_env = Mix.ProjectStack.compile_env(nil)
164165

165166
{changed?, modules} =
166167
cond do
167-
opts[:force] || new_mtime > Mix.Utils.last_modified(target) ->
168+
opts[:force] || new_mtime > Mix.Utils.last_modified(target) ||
169+
(current_compile_env != nil and
170+
current_compile_env != Keyword.get(current_properties, :compile_env, [])) ->
168171
{true, nil}
169172

170173
Keyword.get(config, :reliable_dir_mtime, fn -> not match?({:win32, _}, :os.type()) end) ->
@@ -184,7 +187,7 @@ defmodule Mix.Tasks.Compile.App do
184187
]
185188
|> merge_project_application(project)
186189
|> handle_extra_applications(config)
187-
|> add_compile_env(current_properties)
190+
|> add_compile_env(current_compile_env, current_properties)
188191
|> add_modules(modules, compile_path)
189192

190193
contents =
@@ -389,12 +392,12 @@ defmodule Mix.Tasks.Compile.App do
389392
defp typed_app?({app, type}) when is_atom(app) and type in [:required, :optional], do: true
390393
defp typed_app?(_), do: false
391394

392-
defp add_compile_env(properties, current_properties) do
395+
defp add_compile_env(properties, current_compile_env, current_properties) do
393396
# If someone calls compile.elixir and then compile.app across two
394397
# separate OS calls, then the compile_env won't be properly reflected.
395398
# This is ok because compile_env is not used for correctness. It is
396399
# simply to catch possible errors early.
397-
case Mix.ProjectStack.compile_env(nil) do
400+
case current_compile_env do
398401
nil -> Keyword.take(current_properties, [:compile_env]) ++ properties
399402
[] -> properties
400403
compile_env -> Keyword.put(properties, :compile_env, compile_env)

lib/mix/lib/mix/tasks/deps.compile.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ defmodule Mix.Tasks.Deps.Compile do
125125

126126
# If a dependency was marked as fetched or with an out of date lock
127127
# or missing the app file, we always compile it from scratch.
128-
if force? or Mix.Dep.compilable?(dep) do
128+
if force? or Mix.Dep.force_compilable?(dep) do
129129
File.rm_rf!(Path.join([Mix.Project.build_path(), "lib", Atom.to_string(dep.app)]))
130130
end
131131

lib/mix/test/fixtures/deps_status/custom/raw_repo/lib/raw_repo.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Application.compile_env(:raw_repo, :compile_env)
1+
Application.compile_env(:anyapp, :anything)
22

33
defmodule RawRepo do
44
def hello do

lib/mix/test/mix/tasks/deps_test.exs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -837,16 +837,23 @@ defmodule Mix.Tasks.DepsTest do
837837

838838
test "checks if compile env changed" do
839839
in_fixture("deps_status", fn ->
840+
# Write another file, it should not be recompiled upon compiled env change.
841+
File.write!("custom/raw_repo/lib/foo.ex", """
842+
defmodule RawRepo.Foo do
843+
end
844+
""")
845+
840846
Mix.Project.push(RawRepoDepApp)
841847
Mix.Tasks.Deps.Loadpaths.run([])
848+
assert_receive {:mix_shell, :info, ["Compiling 2 files (.ex)"]}
842849
assert_receive {:mix_shell, :info, ["Generated raw_repo app"]}
843850
assert Application.spec(:raw_repo, :vsn)
844851

845852
File.mkdir_p!("config")
846853

847854
File.write!("config/config.exs", """
848855
import Config
849-
config :raw_repo, :compile_env, :new_value
856+
config :anyapp, :anything, :anyvalue
850857
""")
851858

852859
Application.unload(:raw_repo)
@@ -859,10 +866,15 @@ defmodule Mix.Tasks.DepsTest do
859866
Mix.Tasks.Deps.run([])
860867

861868
assert_receive {:mix_shell, :info,
862-
[" the dependency build is outdated, please run \"mix deps.compile\""]}
869+
[
870+
" the dependency compile environment is outdated, please run \"mix deps.compile\""
871+
]}
872+
873+
Mix.shell().flush()
863874

864875
Mix.Tasks.Deps.Loadpaths.run([])
865876

877+
assert_receive {:mix_shell, :info, ["Compiling 1 file (.ex)"]}
866878
assert_receive {:mix_shell, :info, ["Generated raw_repo app"]}
867879
assert Application.spec(:raw_repo, :vsn)
868880
end)

0 commit comments

Comments
 (0)