feat: add backend flags for rename events
This commit is contained in:
parent
99dec3f689
commit
f6158c8240
7 changed files with 64 additions and 5 deletions
|
|
@ -7,6 +7,8 @@ const ObjectType = types.ObjectType;
|
|||
pub const watches_recursively = true; // FSEventStreamCreate watches the entire subtree
|
||||
pub const detects_file_modifications = true;
|
||||
pub const emits_close_events = false;
|
||||
pub const emits_rename_for_files = true;
|
||||
pub const emits_rename_for_dirs = true;
|
||||
|
||||
handler: *Handler,
|
||||
stream: ?*anyopaque, // FSEventStreamRef
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ pub fn Create(comptime variant: InterfaceType) type {
|
|||
pub const watches_recursively = false;
|
||||
pub const detects_file_modifications = true;
|
||||
pub const emits_close_events = true;
|
||||
pub const emits_rename_for_files = true;
|
||||
pub const emits_rename_for_dirs = true;
|
||||
pub const polling = variant == .polling;
|
||||
|
||||
const WatchEntry = struct { path: []u8, is_dir: bool };
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const ObjectType = types.ObjectType;
|
|||
pub const watches_recursively = false;
|
||||
pub const detects_file_modifications = true;
|
||||
pub const emits_close_events = false;
|
||||
pub const emits_rename_for_files = false;
|
||||
pub const emits_rename_for_dirs = true;
|
||||
|
||||
handler: *Handler,
|
||||
kq: std.posix.fd_t,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const ObjectType = types.ObjectType;
|
|||
pub const watches_recursively = false;
|
||||
pub const detects_file_modifications = false;
|
||||
pub const emits_close_events = false;
|
||||
pub const emits_rename_for_files = false;
|
||||
pub const emits_rename_for_dirs = true;
|
||||
pub const WatchEntry = struct { fd: std.posix.fd_t, is_file: bool };
|
||||
|
||||
handler: *Handler,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ const ObjectType = types.ObjectType;
|
|||
pub const watches_recursively = true; // ReadDirectoryChangesW with bWatchSubtree=1
|
||||
pub const detects_file_modifications = true;
|
||||
pub const emits_close_events = false;
|
||||
pub const emits_rename_for_files = true;
|
||||
pub const emits_rename_for_dirs = true;
|
||||
|
||||
const windows = std.os.windows;
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,8 @@ pub fn Create(comptime variant: Variant) type {
|
|||
/// modifications.
|
||||
pub const detects_file_modifications = Backend.detects_file_modifications;
|
||||
pub const emits_close_events = Backend.emits_close_events;
|
||||
pub const emits_rename_for_files = Backend.emits_rename_for_files;
|
||||
pub const emits_rename_for_dirs = Backend.emits_rename_for_dirs;
|
||||
|
||||
/// Create a new watcher.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -394,15 +394,56 @@ fn testRenameFile(comptime Watcher: type, allocator: std.mem.Allocator) !void {
|
|||
try std.fs.renameAbsolute(src_path, dst_path);
|
||||
try drainEvents(Watcher, &watcher);
|
||||
|
||||
if (builtin.os.tag == .linux) {
|
||||
try std.testing.expect(th.hasRename(src_path, dst_path));
|
||||
if (comptime Watcher.emits_rename_for_files) {
|
||||
// INotify delivers a paired atomic rename callback; FSEvents/Windows
|
||||
// deliver individual .renamed change events per path.
|
||||
const has_rename = th.hasRename(src_path, dst_path) or
|
||||
th.hasChange(src_path, .renamed, .file);
|
||||
try std.testing.expect(has_rename);
|
||||
} else {
|
||||
const has_old = th.hasChange(src_path, .renamed, .file) or th.hasChange(src_path, .deleted, .file);
|
||||
const has_new = th.hasChange(dst_path, .renamed, .file) or th.hasChange(dst_path, .created, .file);
|
||||
try std.testing.expect(has_old or has_new);
|
||||
// KQueue/KQueueDir: file rename appears as delete + create.
|
||||
try std.testing.expect(th.hasChange(src_path, .deleted, .file));
|
||||
try std.testing.expect(th.hasChange(dst_path, .created, .file));
|
||||
}
|
||||
}
|
||||
|
||||
fn testRenameDir(comptime Watcher: type, allocator: std.mem.Allocator) !void {
|
||||
if (comptime !Watcher.emits_rename_for_dirs) return error.SkipZigTest;
|
||||
|
||||
const TH = MakeTestHandler(Watcher);
|
||||
|
||||
const tmp = try makeTempDir(allocator);
|
||||
defer {
|
||||
removeTempDir(tmp);
|
||||
allocator.free(tmp);
|
||||
}
|
||||
|
||||
const th = try TH.init(allocator);
|
||||
defer th.deinit();
|
||||
|
||||
const src_path = try std.fs.path.join(allocator, &.{ tmp, "before" });
|
||||
defer allocator.free(src_path);
|
||||
const dst_path = try std.fs.path.join(allocator, &.{ tmp, "after" });
|
||||
defer allocator.free(dst_path);
|
||||
|
||||
try std.fs.makeDirAbsolute(src_path);
|
||||
|
||||
var watcher = try Watcher.init(allocator, &th.handler);
|
||||
defer watcher.deinit();
|
||||
try watcher.watch(tmp);
|
||||
|
||||
try std.fs.renameAbsolute(src_path, dst_path);
|
||||
try drainEvents(Watcher, &watcher);
|
||||
|
||||
// All backends with emits_rename_for_dirs=true deliver at least a rename
|
||||
// event for the source path. INotify delivers a paired rename callback;
|
||||
// KQueue/KQueueDir deliver change(.renamed, .dir) for the old path only;
|
||||
// FSEvents/Windows deliver change(.renamed, .dir) for both paths.
|
||||
const has_rename = th.hasRename(src_path, dst_path) or
|
||||
th.hasChange(src_path, .renamed, .dir);
|
||||
try std.testing.expect(has_rename);
|
||||
}
|
||||
|
||||
fn testUnwatchedDir(comptime Watcher: type, allocator: std.mem.Allocator) !void {
|
||||
const TH = MakeTestHandler(Watcher);
|
||||
|
||||
|
|
@ -644,6 +685,12 @@ test "renaming a file is reported correctly per-platform" {
|
|||
}
|
||||
}
|
||||
|
||||
test "renaming a directory emits a rename event" {
|
||||
inline for (comptime std.enums.values(nw.Variant)) |variant| {
|
||||
try testRenameDir(nw.Create(variant), std.testing.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
test "an unwatched directory produces no events" {
|
||||
inline for (comptime std.enums.values(nw.Variant)) |variant| {
|
||||
try testUnwatchedDir(nw.Create(variant), std.testing.allocator);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue