Files
swift-inotify/Sources/Inotify/Inotify.docc/WatchingDirectoryTrees.md
T
T. R. Bernstein 3c852a565c Deliver an event enum with the queue overflow as its own case
The stream's element is now the enum InotifyEvent, and the struct that
describes a change to a watched item is FileSystemEvent. A queue
overflow was an event with descriptor -1 and an empty path that every
consumer had to know about; as a case, the compiler makes them handle
it. The enum is also where failed watches of a growing tree will be
reported, since no call site can catch them.
2026-09-19 00:10:35 +02:00

62 lines
3.1 KiB
Markdown

# Watching Directory Trees
Monitor an entire directory hierarchy for filesystem events.
## Overview
The Linux inotify API watches individual directories — it does not descend into subdirectories automatically. The ``Inotify/Inotify`` actor offers two convenience methods that handle the recursion for you.
### Recursive Watch
Call ``Inotify/Inotify/addRecursiveWatch(forDirectory:mask:)`` to walk the directory tree once and install a watch on every subdirectory that exists at the time of the call:
```swift
let inotify = try Inotify()
let descriptors = try await inotify.addRecursiveWatch(
forDirectory: "/home/user/project",
mask: [.create, .modify, .delete]
)
```
The returned array contains one watch descriptor per directory. Subdirectories created **after** this call are not covered.
### Automatic Subtree Watching
When you also want future subdirectories to be picked up, use ``Inotify/Inotify/addWatchWithAutomaticSubtreeWatching(forDirectory:mask:)`` instead:
```swift
let descriptors = try await inotify.addWatchWithAutomaticSubtreeWatching(
forDirectory: "/home/user/project",
mask: [.create, .modify, .delete]
)
```
Internally this listens for `CREATE` and `MOVED_TO` events carrying the ``InotifyEventMask/isDir`` flag and installs new watches with the same mask on the subdirectory and its subtree whenever one appears. Items that already exist inside such a subdirectory are reported with ``FileSystemEvent/synthesized`` set to `true`, since the kernel never produces events for them; a synthesized event may duplicate a kernel event for the same item.
When a directory is moved out of the watched tree, the watches on it and on its subdirectories are removed, so no events are reported under the stale path.
### Excluding Directories
When watching large trees you often want to skip certain subdirectories entirely — version-control metadata, build artefacts, dependency caches, and so on. Call ``Inotify/Inotify/exclude(names:)`` or ``Inotify/Inotify/exclude(patterns:)`` **before** adding a recursive or automatic-subtree watch:
```swift
let inotify = try Inotify()
await inotify.exclude(names: ".git", "node_modules", ".build")
await inotify.exclude(patterns: ".*", "*.tmp")
try await inotify.addWatchWithAutomaticSubtreeWatching(
forDirectory: "/home/user/project",
mask: .allEvents
)
```
Excluded names and patterns are matched against the last path component of each directory during resolution, against a directory that appears later before a watch is extended to it, and against every event, so you never receive events for excluded items. A pattern is matched the way the shell matches file names: `*` and `?` stand for any characters and `[…]` for a set of characters; a leading dot needs no special treatment.
### Choosing the Right Method
| Method | Covers existing subdirectories | Covers new subdirectories |
|--------|:----:|:----:|
| ``Inotify/Inotify/addWatch(path:mask:)`` | No | No |
| ``Inotify/Inotify/addRecursiveWatch(forDirectory:mask:)`` | Yes | No |
| ``Inotify/Inotify/addWatchWithAutomaticSubtreeWatching(forDirectory:mask:)`` | Yes | Yes |