Add depth function to Walker.Entry

This enables depth-related use cases without any dependency on the Walker's internal stack which doesn't always pertain to the actual depth of the current entry (i.e. recursing into a directory immediately affects the stack).
This commit is contained in:
Ryan Liptak 2025-10-03 14:25:12 -07:00
parent 98dd8856ef
commit 894a991714
3 changed files with 28 additions and 20 deletions

View File

@ -732,16 +732,14 @@ pub const SelectiveWalker = struct {
}); });
} }
pub fn depth(self: *SelectiveWalker) usize {
return self.stack.items.len;
}
pub fn deinit(self: *SelectiveWalker) void { pub fn deinit(self: *SelectiveWalker) void {
self.name_buffer.deinit(self.allocator); self.name_buffer.deinit(self.allocator);
self.stack.deinit(self.allocator); self.stack.deinit(self.allocator);
} }
/// Leaves the current directory, continuing walking one level up. /// Leaves the current directory, continuing walking one level up.
/// If the current entry is a directory entry, then the "current directory"
/// will pertain to that entry if `enter` is called before `leave`.
pub fn leave(self: *SelectiveWalker) void { pub fn leave(self: *SelectiveWalker) void {
var item = self.stack.pop().?; var item = self.stack.pop().?;
if (self.stack.items.len != 0) { if (self.stack.items.len != 0) {
@ -789,6 +787,13 @@ pub const Walker = struct {
basename: [:0]const u8, basename: [:0]const u8,
path: [:0]const u8, path: [:0]const u8,
kind: Dir.Entry.Kind, kind: Dir.Entry.Kind,
/// Returns the depth of the entry relative to the initial directory.
/// Returns 1 for a direct child of the initial directory, 2 for an entry
/// within a direct child of the initial directory, etc.
pub fn depth(self: Walker.Entry) usize {
return mem.countScalar(u8, self.path, fs.path.sep) + 1;
}
}; };
const StackItem = struct { const StackItem = struct {

View File

@ -1765,14 +1765,14 @@ test "walker" {
// iteration order of walker is undefined, so need lookup maps to check against // iteration order of walker is undefined, so need lookup maps to check against
const expected_paths = std.StaticStringMap(void).initComptime(.{ const expected_paths = std.StaticStringMap(usize).initComptime(.{
.{"dir1"}, .{ "dir1", 1 },
.{"dir2"}, .{ "dir2", 1 },
.{"dir3"}, .{ "dir3", 1 },
.{"dir4"}, .{ "dir4", 1 },
.{"dir3" ++ fs.path.sep_str ++ "sub1"}, .{ "dir3" ++ fs.path.sep_str ++ "sub1", 2 },
.{"dir3" ++ fs.path.sep_str ++ "sub2"}, .{ "dir3" ++ fs.path.sep_str ++ "sub2", 2 },
.{"dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1"}, .{ "dir3" ++ fs.path.sep_str ++ "sub2" ++ fs.path.sep_str ++ "subsub1", 3 },
}); });
const expected_basenames = std.StaticStringMap(void).initComptime(.{ const expected_basenames = std.StaticStringMap(void).initComptime(.{
@ -1802,6 +1802,10 @@ test "walker" {
std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)}); std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
return err; return err;
}; };
testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
return err;
};
// make sure that the entry.dir is the containing dir // make sure that the entry.dir is the containing dir
var entry_dir = try entry.dir.openDir(entry.basename, .{}); var entry_dir = try entry.dir.openDir(entry.basename, .{});
defer entry_dir.close(); defer entry_dir.close();
@ -1851,6 +1855,10 @@ test "selective walker, skip entries that start with ." {
var num_walked: usize = 0; var num_walked: usize = 0;
while (try walker.next()) |entry| { while (try walker.next()) |entry| {
if (entry.basename[0] == '.') continue; if (entry.basename[0] == '.') continue;
if (entry.kind == .directory) {
try walker.enter(entry);
}
testing.expect(expected_basenames.has(entry.basename)) catch |err| { testing.expect(expected_basenames.has(entry.basename)) catch |err| {
std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)}); std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
return err; return err;
@ -1859,16 +1867,11 @@ test "selective walker, skip entries that start with ." {
std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)}); std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
return err; return err;
}; };
testing.expectEqual(expected_paths.get(entry.path).?, entry.depth()) catch |err| {
testing.expectEqual(expected_paths.get(entry.path).?, walker.depth()) catch |err| { std.debug.print("path reported unexpected depth: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
std.debug.print("path reported unexpected depth: {f}, {d}, expected {d}\n", .{ std.ascii.hexEscape(entry.path, .lower), walker.depth(), expected_paths.get(entry.path).? });
return err; return err;
}; };
if (entry.kind == .directory) {
try walker.enter(entry);
}
// make sure that the entry.dir is the containing dir // make sure that the entry.dir is the containing dir
var entry_dir = try entry.dir.openDir(entry.basename, .{}); var entry_dir = try entry.dir.openDir(entry.basename, .{});
defer entry_dir.close(); defer entry_dir.close();

View File

@ -117,7 +117,7 @@ pub fn main() !void {
while (try walker.next()) |entry| { while (try walker.next()) |entry| {
switch (entry.kind) { switch (entry.kind) {
.directory => { .directory => {
switch (walker.depth()) { switch (entry.depth()) {
1 => if (def_dirs.has(entry.basename)) { 1 => if (def_dirs.has(entry.basename)) {
try walker.enter(entry); try walker.enter(entry);
continue; continue;