Skip to content

Commit 983e033

Browse files
committed
Do not touch sources when external resources change
Instead we store the changed files in the checkpoint. This also address an issue where Elixir would say "mtime was set in the future" when compiled too quickly. See 7d521de. Closes #15277.
1 parent 890d9bb commit 983e033

File tree

1 file changed

+29
-37
lines changed

1 file changed

+29
-37
lines changed

lib/mix/lib/mix/compilers/elixir.ex

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ defmodule Mix.Compilers.Elixir do
66
@moduledoc false
77

88
@manifest_vsn 34
9-
@checkpoint_vsn 4
9+
@checkpoint_vsn 5
1010

1111
import Record
1212

@@ -163,8 +163,7 @@ defmodule Mix.Compilers.Elixir do
163163
removed,
164164
Map.merge(stale_modules, removed_modules),
165165
Map.merge(stale_exports, removed_modules),
166-
dest,
167-
timestamp
166+
dest
168167
)
169168
end
170169

@@ -387,36 +386,17 @@ defmodule Mix.Compilers.Elixir do
387386
removed,
388387
stale_modules,
389388
stale_exports,
390-
dest,
391-
timestamp
389+
dest
392390
) do
393-
{checkpoint_stale_modules, checkpoint_stale_exports} =
391+
{checkpoint_stale_modules, checkpoint_stale_exports, checkpoint_changed} =
394392
case parse_checkpoint(:update, manifest) do
395-
{:ok, {_, _} = data} -> data
396-
:error -> {%{}, %{}}
393+
{:ok, {_, _, _} = data} -> data
394+
:error -> {%{}, %{}, %{}}
397395
end
398396

399397
stale_modules = Map.merge(checkpoint_stale_modules, stale_modules)
400398
stale_exports = Map.merge(checkpoint_stale_exports, stale_exports)
401399

402-
# Once we added semantic recompilation, the following can happen:
403-
#
404-
# 1. The user changes config/mix.exs/__mix_recompile__?
405-
# 2. We detect the change, remove .beam files and start recompilation
406-
# 3. Recompilation fails
407-
# 4. The user reverts the change
408-
# 5. The compiler no longer recompiles and the .beam files are missing
409-
#
410-
# Therefore, it is important for us to checkpoint any state that may
411-
# have lead to a compilation and which can now be reverted.
412-
if map_size(stale_modules) != map_size(checkpoint_stale_modules) or
413-
map_size(stale_exports) != map_size(checkpoint_stale_exports) do
414-
write_checkpoint(:update, manifest, {stale_modules, stale_exports})
415-
end
416-
417-
# We don't need to store those in the checkpoint because
418-
# these changes come from modules and, when they are stale,
419-
# we remove the .beam files and touch sources.
420400
modules_to_mix_check =
421401
for {module, module(recompile?: true)} <- all_modules,
422402
not Map.has_key?(stale_modules, module),
@@ -448,33 +428,45 @@ defmodule Mix.Compilers.Elixir do
448428
# Sources that have changed on disk or
449429
# any modules associated with them need to be recompiled
450430
changed =
451-
Enum.flat_map(all_sources, fn
431+
Enum.reduce(all_sources, checkpoint_changed, fn
452432
{source,
453-
source(external: external, size: size, mtime: mtime, digest: digest, modules: modules)} ->
433+
source(external: external, size: size, mtime: mtime, digest: digest, modules: modules)},
434+
acc ->
454435
{last_mtime, last_size} = Map.fetch!(sources_stats, source)
455436

456437
cond do
457438
Enum.any?(external, &stale_external?(&1, sources_stats)) or
458439
has_any_key?(modules_to_recompile, modules) ->
459-
# Mark the source as changed so the combination of a timestamp
460-
# plus removed beam files (which are removed by update_stale_entries)
461-
# causes it to be recompiled. Note we don't raise use touch! because
462-
# in case of checkpoints the file may have been removed.
463-
File.touch(source, timestamp + 1)
464-
[source]
440+
Map.put(acc, source, true)
465441

466442
size != last_size or
467443
has_any_key?(stale_modules, modules) or
468444
(last_mtime != mtime and
469445
(missing_beam_file?(dest, modules) or digest_changed?(source, digest))) ->
470-
[source]
446+
Map.put(acc, source, true)
471447

472448
true ->
473-
[]
449+
acc
474450
end
475451
end)
476452

477-
changed = new_paths ++ changed
453+
# Once we added semantic recompilation, the following can happen:
454+
#
455+
# 1. The user changes config/mix.exs/__mix_recompile__?
456+
# 2. We detect the change, remove .beam files and start recompilation
457+
# 3. Recompilation fails
458+
# 4. The user reverts the change
459+
# 5. The compiler no longer recompiles and the .beam files are missing
460+
#
461+
# Therefore, it is important for us to checkpoint any state that may
462+
# have lead to a compilation and which can now be reverted.
463+
if map_size(stale_modules) != map_size(checkpoint_stale_modules) or
464+
map_size(stale_exports) != map_size(checkpoint_stale_exports) or
465+
map_size(changed) != map_size(checkpoint_changed) do
466+
write_checkpoint(:update, manifest, {stale_modules, stale_exports, changed})
467+
end
468+
469+
changed = new_paths ++ Map.keys(changed)
478470

479471
{modules, exports, changed} =
480472
update_stale_entries(

0 commit comments

Comments
 (0)