Skip to content

Commit 9860f96

Browse files
Notify each dep compilation from deps.compile (#13906)
1 parent 5ec9ca5 commit 9860f96

File tree

5 files changed

+119
-31
lines changed

5 files changed

+119
-31
lines changed

lib/mix/lib/mix/task.compiler.ex

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ defmodule Mix.Task.Compiler do
5555
5656
* `:app` - app which modules have been compiled.
5757
58-
* `:build_scm` - the SCM module of the compiled project.
58+
* `:scm` - the SCM module of the compiled project.
5959
6060
* `:modules_diff` - information about the compiled modules. The
6161
value is a map with keys: `:added`, `:changed`, `:removed`,
@@ -68,6 +68,21 @@ defmodule Mix.Task.Compiler do
6868
with `System.pid/0` to determine if compilation happened in
6969
the same OS process as the listener.
7070
71+
* `{:dep_compiled, info}` - delivered after a dependency is compiled.
72+
`info` is a map with the following keys:
73+
74+
* `:app` - the dependency app.
75+
76+
* `:scm` - the SCM module of the dependency.
77+
78+
* `:manager` - the dependency project management, possible values:
79+
`:rebar3`, `:mix`, `:make`, `nil`.
80+
81+
* `:os_pid` - the operating system PID of the process that run
82+
the compilation. The value is a string and it can be compared
83+
with `System.pid/0` to determine if compilation happened in
84+
the same OS process as the listener.
85+
7186
Note that the listener starts before any of the project apps are started.
7287
"""
7388

@@ -222,7 +237,7 @@ defmodule Mix.Task.Compiler do
222237
lazy_message = fn ->
223238
info = %{
224239
app: config[:app],
225-
build_scm: config[:build_scm],
240+
scm: config[:build_scm],
226241
modules_diff: lazy_modules_diff.(),
227242
os_pid: System.pid()
228243
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@ defmodule Mix.Tasks.Deps.Compile do
106106
false
107107
end
108108

109+
if compiled? do
110+
build_path = Mix.Project.build_path(config)
111+
112+
lazy_message = fn ->
113+
info = %{
114+
app: dep.app,
115+
scm: dep.scm,
116+
manager: dep.manager,
117+
os_pid: System.pid()
118+
}
119+
120+
{:dep_compiled, info}
121+
end
122+
123+
Mix.Sync.PubSub.broadcast(build_path, lazy_message)
124+
end
125+
109126
# We should touch fetchable dependencies even if they
110127
# did not compile otherwise they will always be marked
111128
# as stale, even when there is nothing to do.

lib/mix/lib/mix/tasks/deps.loadpaths.ex

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,19 @@ defmodule Mix.Tasks.Deps.Loadpaths do
2929

3030
@impl true
3131
def run(args) do
32+
# Note that we need to ensure the dependencies are compiled first,
33+
# before we can start the pub/sub listeners, since those come from
34+
# the dependencies. Theoretically, between compiling dependencies
35+
# and starting the listeners, there may be a concurrent compilation
36+
# of the dependencies, which we would miss, and we would already
37+
# have modules from our compilation loaded. To avoid this race
38+
# condition we start the pub/sub beforehand and we accumulate all
39+
# events until the listeners are started. Alternatively we could
40+
# use a lock around compilation and sterning the listeners, however
41+
# the added benefit of the current approach is that we consistently
42+
# receive events for all dependency compilations. Also, if we ever
43+
# decide to start the listeners later (e.g. after loadspaths), the
44+
# accumulation approach still works.
3245
Mix.PubSub.start()
3346

3447
if "--no-archives-check" not in args do

lib/mix/test/fixtures/compile_listeners/deps/reloader/lib/reloader.ex

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,34 @@ defmodule Reloader do
1515
%{
1616
modules_diff: %{added: added, changed: changed, removed: removed, timestamp: _timestamp},
1717
app: app,
18-
build_scm: build_scm,
18+
scm: scm,
1919
os_pid: os_pid
2020
} = info
2121

2222
IO.write("""
2323
Received :modules_compiled with
2424
added: #{inspect(Enum.sort(added))}, changed: #{inspect(Enum.sort(changed))}, removed: #{inspect(Enum.sort(removed))}
2525
app: #{inspect(app)}
26-
build_scm: #{inspect(build_scm)}
26+
scm: #{inspect(scm)}
27+
os_pid: #{inspect(os_pid)}
28+
""")
29+
30+
{:noreply, state}
31+
end
32+
33+
def handle_info({:dep_compiled, info}, state) do
34+
%{
35+
app: app,
36+
scm: scm,
37+
manager: manager,
38+
os_pid: os_pid
39+
} = info
40+
41+
IO.write("""
42+
Received :dep_compiled with
43+
app: #{inspect(app)}
44+
scm: #{inspect(scm)}
45+
manager: #{inspect(manager)}
2746
os_pid: #{inspect(os_pid)}
2847
""")
2948

lib/mix/test/mix/tasks/compile_test.exs

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -439,13 +439,13 @@ defmodule Mix.Tasks.CompileTest do
439439
assert_receive {^port, {:data, "ok\n"}}, timeout
440440
send(parent, :mix_started)
441441

442-
assert_receive {^port, {:data, output_erl}}, timeout
443-
assert_receive {^port, {:data, output_ex}}, timeout
444-
send(parent, {:output, output_erl <> output_ex})
442+
send_port_outputs_to(port, parent)
445443
end)
446444

447445
assert_receive :mix_started, timeout
448446

447+
# Project compilation
448+
449449
output = mix(["do", "compile", "+", "eval", "IO.write System.pid"])
450450
os_pid = output |> String.split("\n") |> List.last()
451451

@@ -455,12 +455,17 @@ defmodule Mix.Tasks.CompileTest do
455455
Received :modules_compiled with
456456
added: [:a, :b, :c], changed: [], removed: []
457457
app: :with_reloader
458-
build_scm: Mix.SCM.Path
458+
scm: Mix.SCM.Path
459459
os_pid: "#{os_pid}"
460+
"""
461+
462+
assert_receive {:output, output}, timeout
463+
464+
assert output == """
460465
Received :modules_compiled with
461466
added: [A, B, C], changed: [], removed: []
462467
app: :with_reloader
463-
build_scm: Mix.SCM.Path
468+
scm: Mix.SCM.Path
464469
os_pid: "#{os_pid}"
465470
"""
466471

@@ -475,26 +480,7 @@ defmodule Mix.Tasks.CompileTest do
475480
File.write!("lib/d.ex", "defmodule D do end")
476481
File.write!("src/d.erl", "-module(d).")
477482

478-
spawn_link(fn ->
479-
port =
480-
mix_port([
481-
"run",
482-
"--no-halt",
483-
"--no-compile",
484-
"--no-start",
485-
"--eval",
486-
~s/IO.puts("ok"); IO.gets(""); System.halt()/
487-
])
488-
489-
assert_receive {^port, {:data, "ok\n"}}, timeout
490-
send(parent, :mix_started)
491-
492-
assert_receive {^port, {:data, output_erl}}, timeout
493-
assert_receive {^port, {:data, output_ex}}, timeout
494-
send(parent, {:output, output_erl <> output_ex})
495-
end)
496-
497-
assert_receive :mix_started, timeout
483+
# Project recompilation
498484

499485
output = mix(["do", "compile", "+", "eval", "IO.write System.pid"])
500486
os_pid = output |> String.split("\n") |> List.last()
@@ -505,14 +491,52 @@ defmodule Mix.Tasks.CompileTest do
505491
Received :modules_compiled with
506492
added: [:d], changed: [:a], removed: [:b]
507493
app: :with_reloader
508-
build_scm: Mix.SCM.Path
494+
scm: Mix.SCM.Path
509495
os_pid: "#{os_pid}"
496+
"""
497+
498+
assert_receive {:output, output}, timeout
499+
500+
assert output == """
510501
Received :modules_compiled with
511502
added: [D], changed: [A], removed: [B]
512503
app: :with_reloader
513-
build_scm: Mix.SCM.Path
504+
scm: Mix.SCM.Path
505+
os_pid: "#{os_pid}"
506+
"""
507+
508+
# Dependency recompilation
509+
510+
output = mix(["do", "deps.compile", "--force", "+", "eval", "IO.write System.pid"])
511+
os_pid = output |> String.split("\n") |> List.last()
512+
513+
assert_receive {:output, output}, timeout
514+
515+
assert output == """
516+
Received :modules_compiled with
517+
added: [Reloader], changed: [], removed: []
518+
app: :reloader
519+
scm: Mix.SCM.Path
520+
os_pid: "#{os_pid}"
521+
"""
522+
523+
assert_receive {:output, output}, timeout
524+
525+
assert output == """
526+
Received :dep_compiled with
527+
app: :reloader
528+
scm: Mix.SCM.Path
529+
manager: :mix
514530
os_pid: "#{os_pid}"
515531
"""
516532
end)
517533
end
534+
535+
defp send_port_outputs_to(port, pid) do
536+
receive do
537+
{^port, {:data, output}} ->
538+
send(pid, {:output, output})
539+
send_port_outputs_to(port, pid)
540+
end
541+
end
518542
end

0 commit comments

Comments
 (0)