C+
Packages · View as Markdown

fswatch

Filesystem watching with typed, owner-thread change events. macOS, Linux, Android and Windows.

[dependencies]
fswatch     = "*"
events      = "*"
facet       = "*"
flex_layout = "*"
stdlib      = "*"
import "fswatch/fswatch" as fswatch;
import "facet/services" as facet;
import "stdlib/result" as result;

fn changed(event: fswatch::Change, ctx: *u8) {
    // event.path is borrowed for this callback.
}

var options: fswatch::Options = fswatch::Options::new();
options.depth(fswatch::WatchDepth::Recursive);
let _a = options.ignore(".git/**");
let _b = options.ignore("*.tmp");

var task: fswatch::WatchTask =
    match fswatch::watch("src", options, changed, deliver: facet::run_on_main) {
        result::Result[fswatch::WatchTask, fswatch::WatchError]::Ok(t) => t,
        result::Result[fswatch::WatchTask, fswatch::WatchError]::Err(e) => { return; }
    };
// The task owns the background thread: `task.stop()` ends it, and dropping
// the task stops it the same way.

watch validates the root immediately, then polls on its own thread and hands each change to the callback through deliver — any (work, ctx) executor. facet::run_on_main lands callbacks on the main thread with the change's strings copied for the flight; omit deliver and callbacks run on the watcher thread. For a loop you drive yourself, use the low-level Watcher (Watcher::new + on_change + poll() / run()).

Scope

  • three backends behind one seam — kqueue vnode notifications on macOS, inotify on Linux and Android, ReadDirectoryChangesW on Windows;
  • individual file or directory roots;
  • shallow immediate-child or recursive nested snapshots;
  • glob ignores with ignored-directory pruning;
  • created, modified, removed, renamed, metadata, and overflow events;
  • synchronous poll() and cooperative async run() delivery.

Callbacks execute on the thread that drives poll() / run(). The package does not call events::Signal from a worker thread.

Ignore patterns

Patterns match slash-normalized paths relative to the watched root.

Pattern Meaning
*.tmp that basename pattern at any watched depth
.git/** the .git directory and its complete tree
build/* immediate entries below build
**/*.swp swap files at the root or any nested depth
src/?.cplus one-byte filename before .cplus

* and ? do not cross /; ** does. Nothing is ignored by default.

Docs

Tests

cd vendor/fswatch
../../target/debug/cpc test

The package tests exercise the real platform notifications in temporary paths. The imported stdlib currently has an unrelated sandbox-sensitive TCP bind test; the fswatch-specific tests are listed under src::fswatch and src::test_main.

One platform difference worth knowing: Windows stamps LastWriteTime from a clock that advances about every 13ms, so two writes of the same size inside one tick look identical to a snapshot differ — macOS, Linux and Android stamp from a high-resolution clock and do not collide. The Windows backend closes that gap with the NTFS USN, a per-file counter that moves on every change, carried as Metadata::version; macOS, Linux and Android answer a constant 0. On a volume with no journal (FAT32, exFAT, a network share) it degrades back to mtime rather than reporting spurious changes. The guide has the measurement.