<commit_before># The GenServer used by the CodeReloader.
defmodule Phoenix.CodeReloader.Server do
  @moduledoc false
  use GenServer

  require Logger
  alias Phoenix.CodeReloader.Proxy

  def start_link(app, root, paths, compilers, opts \\ []) do
    GenServer.start_link(__MODULE__, {app, root, paths, compilers}, opts)
  end

  def reload!(endpoint) do
    children = Supervisor.which_children(endpoint)

    case List.keyfind(children, __MODULE__, 0) do
      {__MODULE__, pid, _, _} ->
        GenServer.call(pid, :reload!, :infinity)
      _ ->
        raise "Code reloader was invoked for #{inspect endpoint} but no code reloader " <>
              "server was started. Be sure to move `plug Phoenix.CodeReloader` inside " <>
              "a `if code_reloading? do` block in your endpoint"
    end
  end

  ## Callbacks

  def init({app, root, paths, compilers}) do
    all = Mix.Project.config[:compilers] || Mix.compilers
    compilers = all -- (all -- compilers)
    {:ok, {app, root, paths, compilers}}
  end

  def handle_call(:reload!, from, {app, root, paths, compilers} = state) do
    froms = all_waiting([from])
    reply = mix_compile(Code.ensure_loaded(Mix.Task), app, root, paths, compilers)
    Enum.each(froms, &GenServer.reply(&1, reply))
    {:noreply, state}
  end

  defp all_waiting(acc) do
    receive do
      {:"$gen_call", from, :reload!} -> all_waiting([from | acc])
    after
      0 -> acc
    end
  end

  defp mix_compile({:error, _reason}, _, _, _, _) do
    Logger.error "If you want to use the code reload plug in production or " <>
                 "inside an escript, add :mix to your list of dependencies or " <>
                 "disable code reloading"
    :ok
  end

  defp mix_compile({:module, Mix.Task}, app, root, paths, compilers) do
    if Mix.Project.umbrella? do
      Mix.Project.in_project(app, root, fn _ -> mix_compile(paths, compilers) end)
    else
      mix_compile(paths, compilers)
    end
  end

  defp mix_compile(paths, compilers) do
    opts = Enum.flat_map(paths, &["--elixirc-paths", &1])
    Enum.each compilers, &Mix.Task.reenable("compile.#{&1}")

    {res, out} =
      proxy_io(fn ->
        try do
          # We call build_structure mostly for Windows so any
          # new assets in priv is copied to the build directory.
          Mix.Project.build_structure
          res = Enum.flat_map(compilers, &mix_compile_each(&1, opts))

          if :ok in res && consolidate_protocols? do
            Mix.Task.reenable("compile.protocols")
            mix_compile_each("protocols", [])
          else
            res
          end
        catch
          _, _ -> :error
        end
      end)
<commit_msg>Do not compile if config files changed, closes #1421<commit_after># The GenServer used by the CodeReloader.
defmodule Phoenix.CodeReloader.Server do
  @moduledoc false
  use GenServer

  require Logger
  alias Phoenix.CodeReloader.Proxy

  def start_link(app, root, paths, compilers, opts \\ []) do
    GenServer.start_link(__MODULE__, {app, root, paths, compilers}, opts)
  end

  def reload!(endpoint) do
    children = Supervisor.which_children(endpoint)

    case List.keyfind(children, __MODULE__, 0) do
      {__MODULE__, pid, _, _} ->
        case GenServer.call(pid, :reload!, :infinity) do
          {:raise, error} -> raise error
          other -> other
        end
      _ ->
        raise "Code reloader was invoked for #{inspect endpoint} but no code reloader " <>
              "server was started. Be sure to move `plug Phoenix.CodeReloader` inside " <>
              "a `if code_reloading? do` block in your endpoint"
    end
  end

  ## Callbacks

  def init({app, root, paths, compilers}) do
    all = Mix.Project.config[:compilers] || Mix.compilers
    compilers = all -- (all -- compilers)
    {:ok, {app, root, paths, compilers}}
  end

  def handle_call(:reload!, from, {app, root, paths, compilers} = state) do
    froms = all_waiting([from])
    reply = mix_compile(Code.ensure_loaded(Mix.Task), app, root, paths, compilers)
    Enum.each(froms, &GenServer.reply(&1, reply))
    {:noreply, state}
  end

  defp all_waiting(acc) do
    receive do
      {:"$gen_call", from, :reload!} -> all_waiting([from | acc])
    after
      0 -> acc
    end
  end

  defp mix_compile({:error, _reason}, _, _, _, _) do
    message = "If you want to use the code reload plug in production or " <>
              "inside an escript, add :mix to your list of dependencies or " <>
              "disable code reloading"
    {:raise, RuntimeError.exception(message)}
  end

  defp mix_compile({:module, Mix.Task}, app, root, paths, compilers) do
    if Mix.Project.umbrella? do
      Mix.Project.in_project(app, root, fn _ ->
        mix_compile_unless_stale_config(paths, compilers)
      end)
    else
      mix_compile_unless_stale_config(paths, compilers)
    end
  end

  defp mix_compile_unless_stale_config(paths, compilers) do
    manifests = Mix.Tasks.Compile.Elixir.manifests
    configs   = Mix.Project.config_files
    case Mix.Utils.extract_stale(configs, manifests) do
      [] ->
        mix_compile(paths, compilers)
      files ->
        message = """
        you must restart your servder after changing the following configuration files:

          * #{Enum.map_join(files, "\n  * ", &Path.relative_to_cwd/1)}
        """
        {:raise, RuntimeError.exception(message)}
    end
  end

  defp mix_compile(paths, compilers) do
    opts = Enum.flat_map(paths, &["--elixirc-paths", &1])
    Enum.each compilers, &Mix.Task.reenable("compile.#{&1}")

    {res, out} =
      proxy_io(fn ->
        try do
          # We call build_structure mostly for Windows so any
          # new assets in priv is copied to the build directory.
          Mix.Project.build_structure
          res = Enum.flat_map(compilers, &mix_compile_each(&1, opts))

          if :ok in res && consolidate_protocols? do
            Mix.Task.reenable("compile.protocols")
            mix_compile_each("protocols", [])
          else
            res
          end
        catch
          _, _ -> :error
        end
      end)

{'fraction_non_alphanumeric': 0.1118766404199475, 'fraction_numerical': 0.002788713910761155, 'mean_word_length': 2.5717633274751024, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1062758', 'n_tokens_mistral': 1945, 'n_tokens_neox': 1879, 'n_words': 544}