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.
73 lines
1.9 KiB
Swift
73 lines
1.9 KiB
Swift
import Inotify
|
|
|
|
enum RecursivKind {
|
|
case nonrecursive
|
|
case recursive
|
|
case withAutomaticSubtreeWatching
|
|
}
|
|
|
|
/// The file system events an instance delivers around `trigger`.
|
|
func getEventsForTrigger(
|
|
in dir: String,
|
|
mask: InotifyEventMask,
|
|
recursive: RecursivKind = .nonrecursive,
|
|
exclude: [String] = [],
|
|
excludePatterns: [String] = [],
|
|
trigger: @escaping (String) async throws -> Void,
|
|
) async throws -> [FileSystemEvent] {
|
|
let events = try await getInotifyEventsForTrigger(
|
|
in: dir,
|
|
mask: mask,
|
|
recursive: recursive,
|
|
exclude: exclude,
|
|
excludePatterns: excludePatterns,
|
|
trigger: trigger
|
|
)
|
|
return events.compactMap(\.fileSystemEvent)
|
|
}
|
|
|
|
/// Everything an instance delivers around `trigger`, including the
|
|
/// events that are not about a file system item.
|
|
func getInotifyEventsForTrigger(
|
|
in dir: String,
|
|
mask: InotifyEventMask,
|
|
recursive: RecursivKind = .nonrecursive,
|
|
exclude: [String] = [],
|
|
excludePatterns: [String] = [],
|
|
trigger: @escaping (String) async throws -> Void,
|
|
) async throws -> [InotifyEvent] {
|
|
let watcher = try Inotify()
|
|
await watcher.exclude(names: exclude)
|
|
await watcher.exclude(patterns: excludePatterns)
|
|
switch recursive {
|
|
case .nonrecursive:
|
|
try await watcher.addWatch(path: dir, mask: mask)
|
|
case .recursive:
|
|
try await watcher.addRecursiveWatch(forDirectory: dir, mask: mask)
|
|
case .withAutomaticSubtreeWatching:
|
|
try await watcher.addWatchWithAutomaticSubtreeWatching(forDirectory: dir, mask: mask)
|
|
}
|
|
|
|
let eventTask = Task {
|
|
var events: [InotifyEvent] = []
|
|
for await event in await watcher.events {
|
|
events.append(event)
|
|
}
|
|
return events
|
|
}
|
|
|
|
try await Task.sleep(for: .milliseconds(100))
|
|
try await trigger(dir)
|
|
try await Task.sleep(for: .milliseconds(500))
|
|
|
|
eventTask.cancel()
|
|
return await eventTask.value
|
|
}
|
|
|
|
extension InotifyEvent {
|
|
var fileSystemEvent: FileSystemEvent? {
|
|
if case .fileSystem(let event) = self { return event }
|
|
return nil
|
|
}
|
|
}
|