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 {
self.name_buffer.deinit(self.allocator);
self.stack.deinit(self.allocator);
}
/// 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 {
var item = self.stack.pop().?;
if (self.stack.items.len != 0) {
@ -789,6 +787,13 @@ pub const Walker = struct {
basename: [:0]const u8,
path: [:0]const u8,
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 {

View file

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

View file

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