Current section
Files
Jump to
Current section
Files
lib/heimdallr/watcher.ex
defmodule Heimdallr.Watcher do
@moduledoc false
use GenServer
@stagger 100
def start_link(dirs) do
GenServer.start_link(__MODULE__, dirs, name: __MODULE__)
end
def init(dirs) do
{:ok, pid} = FileSystem.start_link(dirs: dirs)
FileSystem.subscribe(pid)
{:ok, %{fs: pid, changed: [], timer: nil}}
end
def handle_info(:process, state = %{changed: changes}) do
spawn(fn -> Heimdallr.reload(changes) end)
{:noreply, %{state | changed: [], timer: nil}}
end
def handle_info({:file_event, fs, {f, events}}, state = %{fs: fs, changed: c, timer: t}) do
file = "./" <> Path.relative_to_cwd(f)
{changed?, changes} = new_changes(file, events, {false, c})
if changed? do
t && Process.cancel_timer(t, async: false, info: false)
timer = Process.send_after(self(), :process, @stagger)
{:noreply, %{fs: fs, changed: changes, timer: timer}}
else
{:noreply, state}
end
end
defp new_changes(file, events, {changed?, acc}) do
if Enum.any?(events, &(&1 in [:created, :modified, :deleted])) and file not in acc do
{true, [file | acc]}
else
{changed?, acc}
end
end
def terminate(reason, %{fs: fs}) do
GenServer.stop(fs, reason)
:ok
end
# watch = dirs |> Enum.map(&inspect/1) |> Enum.join(" ")
# cmd = ~s|inotifywait -r -m -e move,modify,create,delete #{watch}|
# port = Port.open({:spawn, cmd}, [:binary, :use_stdio, :stderr_to_stdout, :exit_status])
# {:ok, %{port: port, changed: [], timer: nil}}
# def handle_info({port, {:data, change}}, state = %{port: port, changed: c, timer: t}) do
# {changed?, changes} =
# change |> String.split(~r/\r?\n/, trim: true) |> Enum.reduce({false, c}, &new_changes/2)
# if changed? do
# t && Process.cancel_timer(t, async: false, info: false)
# timer = Process.send_after(self(), :process, @stagger)
# {:noreply, %{port: port, changed: changes, timer: timer}}
# else
# {:noreply, state}
# end
# end
# defp new_changes(line, {changed?, acc}) do
# {file, type} =
# case line |> String.trim() |> String.split(" ") do
# [dir, change] -> {dir, change}
# [dir, change, file] -> {to_string(Path.join(dir, file)), change}
# _ -> {nil, nil}
# end
# if type != nil and type in ~W(CREATE MODIFY DELETE) and file not in acc do
# {true, [file | acc]}
# else
# {changed?, acc}
# end
# end
end