diff --git a/lib/iex/lib/iex/helpers.ex b/lib/iex/lib/iex/helpers.ex index 0992ef74c2c..8964954aaab 100644 --- a/lib/iex/lib/iex/helpers.ex +++ b/lib/iex/lib/iex/helpers.ex @@ -169,10 +169,8 @@ defmodule IEx.Helpers do end defp reenable_tasks(config) do - Mix.Task.reenable("compile") - Mix.Task.reenable("compile.all") compilers = config[:compilers] || Mix.compilers() - Enum.each(compilers, &Mix.Task.reenable("compile.#{&1}")) + Mix.Task.Compiler.reenable(compilers: compilers) end @doc """ diff --git a/lib/mix/lib/mix/task.compiler.ex b/lib/mix/lib/mix/task.compiler.ex index 83fa713c984..34949fd9ca2 100644 --- a/lib/mix/lib/mix/task.compiler.ex +++ b/lib/mix/lib/mix/task.compiler.ex @@ -312,4 +312,28 @@ defmodule Mix.Task.Compiler do Mix.Sync.PubSub.broadcast(build_path, lazy_message) end + + @doc """ + Reenables given compilers so they can be executed again down the stack. + + If an umbrella project reenables compilers, they are re-enabled for all + child projects. + + Default is `:all` which effectively means all the compilers returned by + `Mix.Task.Compiler.compilers()` are to be reenabled. This task always + re-enables `"compile"` and `"compile.all"`. + """ + @doc since: "1.19.0" + @spec reenable(compilers: compilers) :: :ok when compilers: :all | [atom()] + def reenable(opts \\ []) do + compilers = + case Keyword.get(opts, :compilers, :all) do + :all -> Mix.Task.Compiler.compilers() + list when is_list(list) -> list + end + + Mix.Task.reenable("compile") + Mix.Task.reenable("compile.all") + Enum.each(compilers, &Mix.Task.reenable("compile.#{&1}")) + end end diff --git a/lib/mix/test/mix/tasks/compile_test.exs b/lib/mix/test/mix/tasks/compile_test.exs index df2bbb5b5e5..0cf2739d8b4 100644 --- a/lib/mix/test/mix/tasks/compile_test.exs +++ b/lib/mix/test/mix/tasks/compile_test.exs @@ -112,6 +112,51 @@ defmodule Mix.Tasks.CompileTest do end) end + test "reenables compilers" do + in_fixture("no_mixfile", fn -> + assert Mix.Tasks.Compile.run(["--verbose"]) == {:ok, []} + Mix.shell().flush() + + File.mkdir_p!("lib/foo") + + File.write!("lib/foo/z1.ex", """ + defmodule Z1 do + def ok, do: :ok + end + """) + + assert :ok = Mix.Task.reenable("compile") + assert {:noop, []} = Mix.Task.run("compile") + refute File.regular?("_build/dev/lib/sample/ebin/Elixir.Z1.beam") + + assert :ok = Mix.Task.Compiler.reenable(compilers: []) + assert {:noop, []} = Mix.Task.run("compile") + refute File.regular?("_build/dev/lib/sample/ebin/Elixir.Z1.beam") + + assert :ok = Mix.Task.Compiler.reenable(compilers: ["erlang"]) + assert {:noop, []} = Mix.Task.run("compile") + refute File.regular?("_build/dev/lib/sample/ebin/Elixir.Z1.beam") + + assert :ok = Mix.Task.Compiler.reenable() + assert {:ok, []} = Mix.Task.run("compile") + assert File.regular?("_build/dev/lib/sample/ebin/Elixir.Z1.beam") + + File.write!("lib/foo/z2.ex", """ + defmodule Z2 do + def ko, do: :ko + end + """) + + assert :ok = Mix.Task.Compiler.reenable(compilers: [:erlang]) + assert {:noop, []} = Mix.Task.run("compile") + refute File.regular?("_build/dev/lib/sample/ebin/Elixir.Z2.beam") + + assert :ok = Mix.Task.Compiler.reenable(compilers: [:elixir]) + assert {:ok, []} = Mix.Task.run(:compile) + assert File.regular?("_build/dev/lib/sample/ebin/Elixir.Z2.beam") + end) + end + test "recompiles app cache if manifest changes" do in_fixture("no_mixfile", fn -> Mix.Tasks.Compile.run(["--force"])