File file_system-0.2.10-git.patch of Package file_system
diff --git a/.gitignore b/.gitignore
index 3c4fefd..e0d1afd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,31 @@
-/_build
-/deps
-/doc
-/docs
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where third-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
+
+# Also ignore archive artifacts (built via "mix archive.build").
*.ez
-mix.lock
+
+# Ignore package tarball (built via "mix hex.build").
+file_system-*.tar
+
+# Temporary files for e.g. tests
+/tmp
+
+# Misc
/priv/mac_listener
/priv/kqueue
+mix.lock
diff --git a/README.md b/README.md
index e0d1b34..3e92fcb 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,32 @@
-FileSystem
-=========
+# FileSystem
-A file change watcher wrapper based on [fs](https://github.com/synrc/fs)
+[](https://hex.pm/packages/file_system)
+[](https://hexdocs.pm/file_system/)
+[](https://hex.pm/packages/file_system)
+[](https://github.com/falood/file_system/blob/master/LICENSE)
+[](https://github.com/falood/file_system/commits/master)
+
+An Elixir file change watcher wrapper based on
+[FS](https://github.com/synrc/fs), the native file system listener.
## System Support
-- Mac fsevent
-- Linux, FreeBSD and OpenBSD inotify
-- Windows inotify-win
+- MacOS - [fsevent](https://github.com/thibaudgg/rb-fsevent)
+- GNU/Linux, FreeBSD and OpenBSD - [inotify](https://github.com/rvoicilas/inotify-tools/wiki)
+- Windows - [inotify-win](https://github.com/thekid/inotify-win)
-NOTE:
+On MacOS 10.14, to compile `mac_listener`, run:
- On Linux, FreeBSD and OpenBSD you need to install inotify-tools.
- On Macos 10.14, you need run `open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg` to compile `mac_listener`.
+```console
+open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg
+```
## Usage
-Put `file_system` in the `deps` and `application` part of your mix.exs
+Add `file_system` to the `deps` of your mix.exs
``` elixir
-defmodule Excellent.Mixfile do
+defmodule MyApp.Mixfile do
use Mix.Project
def project do
@@ -35,7 +42,6 @@ defmodule Excellent.Mixfile do
end
```
-
### Subscription API
You can spawn a worker and subscribe to events from it:
@@ -52,17 +58,18 @@ or
FileSystem.subscribe(:my_monitor_name)
```
-The pid you subscribed from will now receive messages like
+The `pid` you subscribed from will now receive messages like:
```
{:file_event, worker_pid, {file_path, events}}
```
and
+
```
{:file_event, worker_pid, :stop}
```
-### Example with GenServer
+### Example Using GenServer
```elixir
defmodule Watcher do
@@ -78,27 +85,41 @@ defmodule Watcher do
{:ok, %{watcher_pid: watcher_pid}}
end
- def handle_info({:file_event, watcher_pid, {path, events}}, %{watcher_pid: watcher_pid}=state) do
- # YOUR OWN LOGIC FOR PATH AND EVENTS
+ def handle_info({:file_event, watcher_pid, {path, events}}, %{watcher_pid: watcher_pid} = state) do
+ # Your own logic for path and events
{:noreply, state}
end
- def handle_info({:file_event, watcher_pid, :stop}, %{watcher_pid: watcher_pid}=state) do
- # YOUR OWN LOGIC WHEN MONITOR STOP
+ def handle_info({:file_event, watcher_pid, :stop}, %{watcher_pid: watcher_pid} = state) do
+ # Your own logic when monitor stop
{:noreply, state}
end
end
```
+## Backend Options
-## Tweaking behaviour via extra arguments
-
-For each platform, you can pass extra arguments to the underlying listener process.
+For each platform, you can pass extra options to the underlying listener
+process.
-Each backend support different extra arguments, check backend module documentation for more information.
+Each backend supports different extra options, check backend module
+documentation for more details.
-Here is an example to get instant notifications on file changes for Mac OS X:
+Here is an example to get instant notifications on file changes for MacOS:
```elixir
FileSystem.start_link(dirs: ["/path/to/some/files"], latency: 0, watch_root: true)
```
+
+## License
+
+Copyright (C) 2016 Xiangrong Hao
+
+Everyone is permitted to copy and distribute verbatim or modified
+copies of this license document, and changing it is allowed as long
+as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
diff --git a/lib/file_system.ex b/lib/file_system.ex
index 5dc1903..31e22d3 100644
--- a/lib/file_system.ex
+++ b/lib/file_system.ex
@@ -1,37 +1,45 @@
defmodule FileSystem do
- @moduledoc File.read!("README.md")
+ @moduledoc """
+ A `GenServer` process to watch file system changes.
+
+ The process receives data from Port, parse event, and send it to the worker
+ process.
+ """
@doc """
+ Starts a `GenServer` process and linked to the current process.
+
## Options
- * `:dirs` ([string], required), the dir list to monitor
+ * `:dirs` ([string], required), the list of directory to monitor.
- * `:backend` (atom, optional), default backends: `:fs_mac`
- for `macos`, `:fs_inotify` for `linux`, `freebsd` and `openbsd`,
- `:fs_windows` for `windows`
+ * `:backend` (atom, optional), default backends: `:fs_mac`. Available
+ backends: `:fs_mac`, `:fs_inotify`, and `:fs_windows`.
- * `: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.
+ * `:name` (atom, optional), the `name` of the worker process to subscribe
+ to the file system listerner. Alternative to using `pid` of the worker
+ process.
- * All rest options will treated as backend options. See backend
- module documents for more details.
+ * Additional backend implementation options. See backend module documents
+ for more details.
- ## Example
+ ## Examples
- Simple usage:
+ Start monitoring `/tmp/fs` directory using the default `:fs_mac` backend of
+ the current process:
iex> {:ok, pid} = FileSystem.start_link(dirs: ["/tmp/fs"])
iex> FileSystem.subscribe(pid)
- Get instant notifications on file changes for Mac OS X:
+ Get instant (`latench: 0`) notifications on file changes:
iex> FileSystem.start_link(dirs: ["/path/to/some/files"], latency: 0)
- Named monitor with specified backend:
+ Minitor a directory by a process name:
iex> FileSystem.start_link(backend: :fs_mac, dirs: ["/tmp/fs"], name: :worker)
iex> FileSystem.subscribe(:worker)
+
"""
@spec start_link(Keyword.t) :: GenServer.on_start()
def start_link(options) do
@@ -39,11 +47,13 @@ defmodule FileSystem do
end
@doc """
- Register the current process as a subscriber of a file_system worker.
- The pid you subscribed from will now receive messages like
+ Register the current process as a subscriber of a `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(GenServer.server) :: :ok
def subscribe(pid) do
diff --git a/lib/file_system/backend.ex b/lib/file_system/backend.ex
index 2659f32..8b23760 100644
--- a/lib/file_system/backend.ex
+++ b/lib/file_system/backend.ex
@@ -2,7 +2,7 @@ require Logger
defmodule FileSystem.Backend do
@moduledoc """
- FileSystem Backend Behaviour.
+ A behaviour module for implementing different file system backend.
"""
@callback bootstrap() :: :ok | {:error, atom()}
@@ -10,9 +10,13 @@ defmodule FileSystem.Backend do
@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.
+ Get and validate backend module.
+
+ Returns `{:ok, backend_module}` upon success and `{:error, reason}` upon
+ failure.
+
+ 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.
"""
diff --git a/lib/file_system/backends/fs_inotify.ex b/lib/file_system/backends/fs_inotify.ex
index 8fd5566..876c356 100644
--- a/lib/file_system/backends/fs_inotify.ex
+++ b/lib/file_system/backends/fs_inotify.ex
@@ -2,24 +2,35 @@ require Logger
defmodule FileSystem.Backends.FSInotify do
@moduledoc """
+ File system backend for GNU/Linux, FreeBSD, and OpenBSD.
+
This file is a fork from https://github.com/synrc/fs.
- FileSystem backend for linux, freebsd and openbsd, a GenServer receive data from Port, parse event
- and send it to the worker process.
- Need `inotify-tools` installed to use this backend.
## Backend Options
- * `:recursive` (bool, default: true), monitor directories and their contents recursively
+ * `:recursive` (bool, default: true), monitor directories and their contents recursively.
## Executable File Path
- The default behaivour to find executable file is finding `inotifywait` from `$PATH`, there're two ways to custom it, useful when run `:file_system` with escript.
+ Useful when running `:file_system` with escript.
+
+ The default listener executable file is found through finding `inotifywait` from
+ `$PATH`.
+
+ Two ways to customize the executable file path:
+
+ * Module config with `config.exs`:
+
+ ```elixir
+ config :file_system, :fs_inotify,
+ executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ ```
- * config with `config.exs`
- `config :file_system, :fs_inotify, executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ * System environment variable:
- * config with `FILESYSTEM_FSINOTIFY_EXECUTABLE_FILE` os environment
- FILESYSTEM_FSINOTIFY_EXECUTABLE_FILE=YOUR_EXECUTABLE_FILE_PATH
+ ```
+ export FILESYSTEM_FSINOTIFY_EXECUTABLE_FILE="YOUR_EXECUTABLE_FILE_PATH"`
+ ```
"""
use GenServer
@@ -114,7 +125,7 @@ defmodule FileSystem.Backends.FSInotify do
port = Port.open(
{:spawn_executable, '/bin/sh'},
- [:stream, :exit_status, {:line, 16384}, {:args, all_args}, {:cd, System.tmp_dir!()}]
+ [:binary, :stream, :exit_status, {:line, 16384}, {:args, all_args}, {:cd, System.tmp_dir!()}]
)
Process.link(port)
@@ -149,7 +160,7 @@ defmodule FileSystem.Backends.FSInotify do
def parse_line(line) do
{path, flags} =
- case line |> to_string |> String.split(@sep_char, trim: true) do
+ case String.split(line, @sep_char, trim: true) do
[dir, flags, file] -> {Path.join(dir, file), flags}
[path, flags] -> {path, flags}
end
diff --git a/lib/file_system/backends/fs_mac.ex b/lib/file_system/backends/fs_mac.ex
index cd0236a..f142fbd 100644
--- a/lib/file_system/backends/fs_mac.ex
+++ b/lib/file_system/backends/fs_mac.ex
@@ -2,35 +2,52 @@ require Logger
defmodule FileSystem.Backends.FSMac do
@moduledoc """
+ File system backend for MacOS.
+
+ The built-in executable file will be compile upon first use.
+
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.
## Backend Options
* `:latency` (float, default: 0.5), latency period.
* `:no_defer` (bool, default: false), enable no-defer latency modifier.
- Works with latency parameter, Also check apple `FSEvent` api documents
- https://developer.apple.com/documentation/coreservices/kfseventstreamcreateflagnodefer
+ Works with latency parameter.
+
+ See `FSEvent` API documents
+ https://developer.apple.com/documentation/coreservices/kfseventstreamcreateflagnodefer.
* `:watch_root` (bool, default: false), watch for when the root path has changed.
Set the flag `true` to monitor events when watching `/tmp/fs/dir` and run
- `mv /tmp/fs /tmp/fx`. Also check apple `FSEvent` api documents
- https://developer.apple.com/documentation/coreservices/kfseventstreamcreateflagwatchroot
+ `mv /tmp/fs /tmp/fx`.
+
+ See `FSEvent` API documents
+ https://developer.apple.com/documentation/coreservices/kfseventstreamcreateflagwatchroot.
- * recursive is enabled by default, no option to disable it for now.
+ * recursive is enabled by default and it can'b be disabled for now.
## Executable File Path
- The default executable file is `mac_listener` in `priv` dir of `:file_system` application, there're two ways to custom it, useful when run `:file_system` with escript.
+ Useful when running `:file_system` with escript.
+
+ The default listener executable file is `priv/mac_listener` within the folder of
+ `:file_system` application.
+
+ Two ways to customize the executable file path:
+
+ * Module config with `config.exs`:
+
+ ```elixir
+ config :file_system, :fs_mac,
+ executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ ```
- * config with `config.exs`
- `config :file_system, :fs_mac, executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ * System environment variable:
- * config with `FILESYSTEM_FSMAC_EXECUTABLE_FILE` os environment
- FILESYSTEM_FSMAC_EXECUTABLE_FILE=YOUR_EXECUTABLE_FILE_PATH
+ ```
+ export FILESYSTEM_FSMAC_EXECUTABLE_FILE="YOUR_EXECUTABLE_FILE_PATH"`
+ ```
"""
use GenServer
@@ -78,7 +95,7 @@ defmodule FileSystem.Backends.FSMac do
defp executable_path(:priv) do
case :code.priv_dir(:file_system) do
{:error, _} ->
- Logger.error "`priv` dir for `:file_system` application is not avalible in current runtime, appoint executable file with `config.exs` or `FILESYSTEM_FSMAC_EXECUTABLE_FILE` env."
+ Logger.error "`priv` dir for `:file_system` application is not available in current runtime, appoint executable file with `config.exs` or `FILESYSTEM_FSMAC_EXECUTABLE_FILE` env."
nil
dir when is_list(dir) ->
Path.join(dir, @default_exec_file)
diff --git a/lib/file_system/backends/fs_poll.ex b/lib/file_system/backends/fs_poll.ex
index 362ed1d..fcacb3d 100644
--- a/lib/file_system/backends/fs_poll.ex
+++ b/lib/file_system/backends/fs_poll.ex
@@ -2,14 +2,13 @@ require Logger
defmodule FileSystem.Backends.FSPoll do
@moduledoc """
- FileSysetm backend for any OS, a GenServer that regularly scans file system to
- detect changes and send them to the worker process.
+ File system backend for any OS.
## Backend Options
* `:interval` (integer, default: 1000), polling interval
- ## Use FSPoll Backend
+ ## Using FSPoll Backend
Unlike other backends, polling backend is never automatically chosen in any
OS environment, despite being usable on all platforms.
diff --git a/lib/file_system/backends/fs_windows.ex b/lib/file_system/backends/fs_windows.ex
index 8e3d1ae..d2ed0da 100644
--- a/lib/file_system/backends/fs_windows.ex
+++ b/lib/file_system/backends/fs_windows.ex
@@ -2,24 +2,37 @@ require Logger
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.
+ File system backend for Windows.
+
Need binary executable file packaged in to use this backend.
+ This file is a fork from https://github.com/synrc/fs.
+
## Backend Options
* `:recursive` (bool, default: true), monitor directories and their contents recursively
## Executable File Path
- The default executable file is `inotifywait.exe` in `priv` dir of `:file_system` application, there're two ways to custom it, useful when run `:file_system` with escript.
+ Useful when running `:file_system` with escript.
+
+ The default listener executable file is `priv/inotifywait.exe` within the
+ folder of `:file_system` application.
+
+ Two ways to customize the executable file path:
+
+ * Module config with `config.exs`:
+
+ ```elixir
+ config :file_system, :fs_windows,
+ executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ ```
- * config with `config.exs`
- `config :file_system, :fs_windows, executable_file: "YOUR_EXECUTABLE_FILE_PATH"`
+ * System environment variable:
- * config with `FILESYSTEM_FSWINDOWS_EXECUTABLE_FILE` os environment
- FILESYSTEM_FSWINDOWS_EXECUTABLE_FILE=YOUR_EXECUTABLE_FILE_PATH
+ ```
+ export FILESYSTEM_FSWINDOWS_EXECUTABLE_FILE="YOUR_EXECUTABLE_FILE_PATH"`
+ ```
"""
use GenServer
@@ -65,7 +78,7 @@ defmodule FileSystem.Backends.FSWindows do
defp executable_path(:priv) do
case :code.priv_dir(:file_system) do
{:error, _} ->
- Logger.error "`priv` dir for `:file_system` application is not avalible in current runtime, appoint executable file with `config.exs` or `FILESYSTEM_FSWINDOWS_EXECUTABLE_FILE` env."
+ Logger.error "`priv` dir for `:file_system` application is not available in current runtime, appoint executable file with `config.exs` or `FILESYSTEM_FSWINDOWS_EXECUTABLE_FILE` env."
nil
dir when is_list(dir) ->
Path.join(dir, @default_exec_file)
diff --git a/mix.exs b/mix.exs
index 25c2257..2eae318 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,32 +1,44 @@
defmodule FileSystem.Mixfile do
use Mix.Project
+ @source_url "https://github.com/falood/file_system"
+ @version "0.2.10"
+
def project do
- [ app: :file_system,
- version: "0.2.10",
+ [
+ app: :file_system,
+ version: @version,
elixir: "~> 1.3",
deps: deps(),
- description: "A file system change watcher wrapper based on [fs](https://github.com/synrc/fs)",
- source_url: "https://github.com/falood/file_system",
+ description: description(),
package: package(),
compilers: [:file_system | Mix.compilers()],
aliases: ["compile.file_system": &file_system/1],
docs: [
extras: ["README.md"],
main: "readme",
+ source_url: @source_url,
+ source_ref: @version
]
]
end
def application do
[
- applications: [:logger],
+ applications: [:logger]
]
end
+ defp description do
+ """
+ An Elixir file system change watcher wrapper based on FS, the native file
+ system listener.
+ """
+ end
+
defp deps do
[
- { :ex_doc, "~> 0.14", only: :docs },
+ {:ex_doc, ">= 0.0.0", only: :docs}
]
end
@@ -43,13 +55,21 @@ defmodule FileSystem.Mixfile do
target = "priv/mac_listener"
if Mix.Utils.stale?(Path.wildcard(source), [target]) do
- Logger.info "Compiling file system watcher for Mac..."
- cmd = "clang -framework CoreFoundation -framework CoreServices -Wno-deprecated-declarations #{source} -o #{target}"
+ Logger.info("Compiling file system watcher for Mac...")
+
+ cmd =
+ "clang -framework CoreFoundation -framework CoreServices -Wno-deprecated-declarations #{
+ source
+ } -o #{target}"
+
if Mix.shell().cmd(cmd) > 0 do
- Logger.error "Could not compile file system watcher for Mac, try to run #{inspect cmd} manually inside the dependency."
+ Logger.error(
+ "Could not compile file system watcher for Mac, try to run #{inspect(cmd)} manually inside the dependency."
+ )
else
- Logger.info "Done."
+ Logger.info("Done.")
end
+
:ok
else
:noop
@@ -57,19 +77,22 @@ defmodule FileSystem.Mixfile do
end
defp package do
- %{ maintainers: ["Xiangrong Hao", "Max Veytsman"],
- files: [
- "lib", "README.md", "mix.exs",
- "c_src/mac/cli.c",
- "c_src/mac/cli.h",
- "c_src/mac/common.h",
- "c_src/mac/compat.c",
- "c_src/mac/compat.h",
- "c_src/mac/main.c",
- "priv/inotifywait.exe",
- ],
- licenses: ["WTFPL"],
- links: %{"Github" => "https://github.com/falood/file_system"}
- }
+ [
+ maintainers: ["Xiangrong Hao", "Max Veytsman"],
+ files: [
+ "lib",
+ "README.md",
+ "mix.exs",
+ "c_src/mac/cli.c",
+ "c_src/mac/cli.h",
+ "c_src/mac/common.h",
+ "c_src/mac/compat.c",
+ "c_src/mac/compat.h",
+ "c_src/mac/main.c",
+ "priv/inotifywait.exe"
+ ],
+ licenses: ["WTFPL"],
+ links: %{"GitHub" => @source_url}
+ ]
end
end
diff --git a/test/backends/fs_inotify_test.exs b/test/backends/fs_inotify_test.exs
index 1482eff..a499654 100644
--- a/test/backends/fs_inotify_test.exs
+++ b/test/backends/fs_inotify_test.exs
@@ -25,11 +25,16 @@ defmodule FileSystem.Backends.FSInotifyTest do
'-e', 'delete', '-e', 'attrib', '--format', [37, 119, 1, 37, 101, 1, 37, 102],
'--quiet', '-m', '/tmp']} ==
parse_options(dirs: ["/tmp"], recursive: false, unsupported: :options)
+
+ assert {:ok, ['-e', 'modify', '-e', 'close_write', '-e', 'moved_to', '-e', 'moved_from', '-e', 'create',
+ '-e', 'delete', '-e', 'attrib', '--format', [37, 119, 1, 37, 101, 1, 37, 102],
+ '--quiet', '-m', '-r', '/tmp']} ==
+ parse_options(dirs: ["/tmp"], recursive: :unknown_value)
end
end
describe "port line parse test" do
- defp to_port_line(list), do: list |> Enum.join(<<1>>) |> to_charlist
+ defp to_port_line(list), do: list |> Enum.join(<<1>>)
test "dir write close" do
assert {"/one/two/file", [:modified, :closed]} ==