defmodule Heimdallr do @moduledoc """ Documentation for `Heimdallr`. """ alias Mix.Tasks.Compile.Elixir, as: ElixirCompiler @compile_opts ~W(--docs --ignore-module-conflict) def reload(files) do mix_changed? = "./mix.exs" in files deps_changed? = "./mix.lock" in files code = Enum.filter(files, &String.starts_with?(&1, "./lib/")) test = Enum.filter(files, &String.starts_with?(&1, "./test/")) IO.puts( "#{Enum.count(files)} changes and mix #{inspect(mix_changed?)} and deps #{ inspect(deps_changed?) }" ) if mix_changed?, do: reload_mix() case ElixirCompiler.run(@compile_opts) do {:noop, _} -> :ok {:ok, diagnostics} -> process_code_reload(code, diagnostics) {:error, _} -> :ok end # After re-index, see what depends process_test_change(test ++ Enum.flat_map(code, &Heimdallr.Indexer.tests/1)) end alias Mix.{Project, ProjectStack} alias Mix.Tasks.Deps.{Compile, Get} defp reload_mix do IO.puts("mix.exs recompiling project config.") pre_deps = current_deps() ProjectStack.pop() try do Code.compile_file("./mix.exs") rescue _ -> :ok end unless pre_deps == current_deps() do lock = File.read!("./mix.lock") IO.puts("Dependencies have changed, fetching dependencies.") Get.run([]) unless File.read!("./mix.lock") == lock do IO.puts("Dependencies have been update/pulled, recompiling.") Compile.run([]) # Add support for unloading end end end defp current_deps, do: Project.config()[:deps] defp process_code_reload(files, _diagnostics) do if files != [] and Application.get_env(:heimdallr, :run_checks, true) do Credo.CLI.main(["--mute-exit-status", "--strict", "list" | files]) end Enum.each(files, &Heimdallr.Indexer.i/1) :heimdallr |> Application.get_env(:after_compile, []) |> Enum.each(& &1.(files)) :ok end defp process_test_change(tests) do if tests != [] do IO.puts(elem(execute("mix", ["test", "--color" | tests]), 0)) end :ok end @spec execute(String.t(), [String.t()]) :: {String.t(), integer} defp execute(command, options) do case :os.type() do {:unix, :darwin} -> commands = ["-q", "/dev/null", command] ++ options System.cmd("script", commands) {:unix, _} -> System.cmd(command, options, stderr_to_stdout: true) end end end