fix: watch all directories within the project tree

This commit is contained in:
CJ van den Berg 2026-02-20 10:23:15 +01:00
parent 583344d413
commit 348c2055da
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
3 changed files with 40 additions and 10 deletions

View file

@ -9,11 +9,13 @@ const OutOfMemoryError = error{OutOfMemory};
pub const EntryCallBack = *const fn (parent: tp.pid_ref, root_path: []const u8, path: []const u8, mtime_high: i64, mtime_low: i64) error{Exit}!void;
pub const DoneCallBack = *const fn (parent: tp.pid_ref, root_path: []const u8) error{Exit}!void;
pub const DirCallBack = *const fn (parent: tp.pid_ref, root_path: []const u8, path: []const u8) error{Exit}!void;
pub const Options = struct {
follow_directory_symlinks: bool = false,
maximum_symlink_depth: usize = 1,
log_ignored_links: bool = false,
dir_callback: ?DirCallBack = null,
};
pub fn start(a_: std.mem.Allocator, root_path_: []const u8, entry_handler: EntryCallBack, done_handler: DoneCallBack, options: Options) (SpawnError || std.fs.Dir.OpenError)!tp.pid {
@ -78,7 +80,13 @@ pub fn start(a_: std.mem.Allocator, root_path_: []const u8, entry_handler: Entry
}
fn next(self: *tree_walker) !void {
if (try self.walker.next()) |path| {
if (try self.walker.next()) |entry| {
if (entry.kind == .dir) {
if (self.options.dir_callback) |cb|
cb(self.parent.ref(), self.root_path, entry.path) catch {};
return tp.self_pid().send(.{"next"});
}
const path = entry.path;
const stat = self.dir.statFile(path) catch {
try self.entry_handler(self.parent.ref(), self.root_path, path, 0, 0);
return tp.self_pid().send(.{"next"});
@ -123,6 +131,8 @@ const FilteredWalker = struct {
name_buffer: std.ArrayListUnmanaged(u8),
options: Options,
const Kind = enum { file, dir };
const Entry = struct { path: []const u8, kind: Kind };
const Path = []const u8;
const StackItem = struct {
@ -160,7 +170,7 @@ const FilteredWalker = struct {
self.name_buffer.deinit(self.allocator);
}
fn next(self: *FilteredWalker) OutOfMemoryError!?Path {
fn next(self: *FilteredWalker) OutOfMemoryError!?Entry {
while (self.stack.items.len != 0) {
var top = &self.stack.items[self.stack.items.len - 1];
var containing = top;
@ -182,17 +192,17 @@ const FilteredWalker = struct {
switch (base.kind) {
.directory => {
_ = try self.next_directory(&base, &top, &containing, top.symlink_depth);
continue;
return .{ .path = self.name_buffer.items, .kind = .dir };
},
.file => return self.name_buffer.items,
.file => return .{ .path = self.name_buffer.items, .kind = .file },
.sym_link => {
if (top.symlink_depth == 0) {
if (self.options.log_ignored_links)
std.log.warn("TOO MANY LINKS! ignoring symlink: {s}", .{base.name});
continue;
}
if (try self.next_sym_link(&base, &top, &containing, top.symlink_depth -| 1)) |file|
return file
if (try self.next_sym_link(&base, &top, &containing, top.symlink_depth -| 1)) |entry|
return entry
else
continue;
},
@ -229,15 +239,17 @@ const FilteredWalker = struct {
return;
}
fn next_sym_link(self: *FilteredWalker, base: *const std.fs.Dir.Entry, top: **StackItem, containing: **StackItem, symlink_depth: usize) !?[]const u8 {
fn next_sym_link(self: *FilteredWalker, base: *const std.fs.Dir.Entry, top: **StackItem, containing: **StackItem, symlink_depth: usize) !?Entry {
const st = top.*.iter.dir.statFile(base.name) catch return null;
switch (st.kind) {
.directory => {
if (self.options.follow_directory_symlinks)
_ = try self.next_directory(base, top, containing, symlink_depth);
if (self.options.follow_directory_symlinks) {
try self.next_directory(base, top, containing, symlink_depth);
return .{ .path = self.name_buffer.items, .kind = .dir };
}
return null;
},
.file => return self.name_buffer.items,
.file => return .{ .path = self.name_buffer.items, .kind = .file },
.sym_link => {
if (symlink_depth == 0) {
if (self.options.log_ignored_links)