Skip to content
Snippets Groups Projects
Commit 00a8bcd1 authored by Xiangrong Hao's avatar Xiangrong Hao Committed by GitHub
Browse files

add docs and spec (#30)

* add docs and spec

* make find_executable private
parent b6392da4
No related branches found
No related tags found
No related merge requests found
defmodule FileSystem do
defmacro __using__(options) do
quote do
@file_system_module_options unquote(options)
@before_compile FileSystem.ModuleApi
end
end
@moduledoc File.read!("README.md")
@doc """
## Options
* `:dirs` ([string], requires), the dir list to monitor
* `:backend` (atom, optional), default backends: `:fs_mac`
for `macos`, `:fs_inotify` for `linux` and `freebsd`,
`:fs_windows` for `windows`
* `:listener_extra_args` (string, optional), extra args for
port backend.
* `:name` (atom, optional), `name` can be used to subscribe as
the same as pid when the `name` is given. The `name` should
be the name of worker process.
def start_link(args) do
FileSystem.Worker.start_link(args)
## Example
Simple usage:
iex> {:ok, pid} = FileSystem.start_link(dirs: ["/tmp/fs"])
iex> FileSystem.subscribe(pid)
Get nstant notifications on file changes for Mac OS X:
iex> FileSystem.start_link(dirs: ["/path/to/some/files"], listener_extra_args: "--latency=0.0")
Named monitir with specialty backend:
iex> FileSystem.start_link(backend: :fs_mac, dirs: ["/tmp/fs"], name: :worker)
iex> FileSystem.subscribe(:worker)
"""
@spec start_link(Keyword.t) :: {:ok, pid}
def start_link(options) do
FileSystem.Worker.start_link(options)
end
@doc """
Regester current process as a subscriber of file_system worker.
The pid you subscribed from will now receive messages like
{:file_event, worker_pid, {file_path, events}}
{:file_event, worker_pid, :stop}
"""
@spec subscribe(pid() | atom()) :: :ok
def subscribe(pid) do
GenServer.call(pid, :subscribe)
end
......
require Logger
defmodule FileSystem.Backend do
@moduledoc """
FileSystem Backend Behaviour.
"""
@callback bootstrap() :: :ok | {:error, atom()}
@callback supported_systems() :: [{atom(), atom()}]
@callback known_events() :: [atom()]
@doc """
Get and validate backend module, return `{:ok, backend_module}` when success and
return `{:error, reason}` when fail.
When `nil` is given, will return default backend by os.
When a custom module is given, make sure `start_link/1`, `bootstrap/0` and
`supported_system/0` are defnied.
"""
@spec backend(:atom) :: {:ok, atom()} | {:error, atom()}
def backend(backend) do
with {:ok, module} <- backend_module(backend),
:ok <- validate_os(backend, module),
......
......@@ -2,6 +2,13 @@ require Logger
alias FileSystem.Utils
defmodule FileSystem.Backends.FSInotify do
@moduledoc """
This file is a fork from https://github.com/synrc/fs.
FileSysetm backend for linux and freebsd, a GenServer receive data from Port, parse event
and send it to the worker process.
Need `inotify-tools` installed to use this backend.
"""
use GenServer
@behaviour FileSystem.Backend
@sep_char <<1>>
......@@ -24,7 +31,7 @@ defmodule FileSystem.Backends.FSInotify do
[:created, :deleted, :renamed, :closed, :modified, :isdir, :attribute, :undefined]
end
def find_executable do
defp find_executable do
System.find_executable("inotifywait")
end
......
......@@ -2,6 +2,13 @@ require Logger
alias FileSystem.Utils
defmodule FileSystem.Backends.FSMac do
@moduledoc """
This file is a fork from https://github.com/synrc/fs.
FileSysetm backend for macos, a GenServer receive data from Port, parse event
and send it to the worker process.
will compile executable the buildin executable file when file the first time it is used.
"""
use GenServer
@behaviour FileSystem.Backend
......@@ -33,10 +40,11 @@ defmodule FileSystem.Backends.FSMac do
]
end
def find_executable do
defp find_executable do
(:code.priv_dir(:file_system) ++ '/mac_listener') |> to_string
end
def start_link(args) do
GenServer.start_link(__MODULE__, args, [])
end
......
......@@ -2,6 +2,13 @@ require Logger
alias FileSystem.Utils
defmodule FileSystem.Backends.FSWindows do
@moduledoc """
This file is a fork from https://github.com/synrc/fs.
FileSysetm backend for windows, a GenServer receive data from Port, parse event
and send it to the worker process.
Need binary executable file packaged in to use this backend.
"""
use GenServer
@behaviour FileSystem.Backend
@sep_char <<1>>
......@@ -24,7 +31,7 @@ defmodule FileSystem.Backends.FSWindows do
[:created, :modified, :removed, :renamed, :undefined]
end
def find_executable do
defp find_executable do
(:code.priv_dir(:file_system) ++ '/inotifywait.exe') |> to_string
end
......
defmodule FileSystem.Utils do
@moduledoc false
@doc false
@spec format_path(String.t() | [String.t()]) :: [charlist()]
def format_path(path) when is_list(path) do
for i <- path do
i |> Path.absname |> to_charlist
end
end
def format_path(path) do
[path] |> format_path
end
@doc false
@spec format_args(nil | String.t() | [String.t()]) :: [charlist()]
def format_args(nil), do: []
def format_args(str) when is_binary(str) do
str |> String.split |> format_args
......
defmodule FileSystem.Worker do
@moduledoc """
FileSystem Worker Process with the backend GenServer, receive events from Port Process
and forward it to subscribers.
"""
use GenServer
@doc false
def start_link(args) do
{args, opts} = Keyword.split(args, [:backend, :dirs, :listener_extra_args])
GenServer.start_link(__MODULE__, args, opts)
end
@doc false
def init(args) do
case FileSystem.Backend.backend(args[:backend]) do
{:ok, backend} ->
......@@ -16,12 +23,14 @@ defmodule FileSystem.Worker do
end
end
@doc false
def handle_call(:subscribe, {pid, _}, state) do
ref = Process.monitor(pid)
state = put_in(state, [:subscribers, ref], pid)
{:reply, :ok, state}
end
@doc false
def handle_info({:backend_file_event, backend_pid, file_event}, %{backend_pid: backend_pid}=state) do
state.subscribers |> Enum.each(fn {_ref, subscriber_pid} ->
send(subscriber_pid, {:file_event, self(), file_event})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment