Move fs.Walker to fs.Dir.Walker

fs.Walker has been replaced with fs.Dir.Walker. Paths of entries
returned are relative to the Dir.
This commit is contained in:
Ominitay 2021-04-17 18:33:43 +01:00 committed by Veikka Tuominen
parent f476463cd2
commit c1285a1bbe
3 changed files with 100 additions and 100 deletions

View File

@ -3015,7 +3015,8 @@ pub const InstallDirStep = struct {
const self = @fieldParentPtr(InstallDirStep, "step", step);
const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);
var it = try fs.walkPath(self.builder.allocator, full_src_dir);
const src_dir = try std.fs.cwd().openDir(full_src_dir, .{ .iterate = true });
var it = try src_dir.walk(self.builder.allocator);
next_entry: while (try it.next()) |entry| {
for (self.options.exclude_extensions) |ext| {
if (mem.endsWith(u8, entry.path, ext)) {
@ -3023,9 +3024,12 @@ pub const InstallDirStep = struct {
}
}
const rel_path = entry.path[full_src_dir.len + 1 ..];
const full_path = try fs.path.join(self.builder.allocator, &[_][]const u8{
full_src_dir, entry.path,
});
const dest_path = try fs.path.join(self.builder.allocator, &[_][]const u8{
dest_prefix, rel_path,
dest_prefix, entry.path,
});
switch (entry.kind) {
@ -3038,7 +3042,7 @@ pub const InstallDirStep = struct {
}
}
try self.builder.updateFile(entry.path, dest_path);
try self.builder.updateFile(full_path, dest_path);
},
else => continue,
}

View File

@ -737,6 +737,94 @@ pub const Dir = struct {
}
}
pub const Walker = struct {
stack: std.ArrayList(StackItem),
name_buffer: std.ArrayList(u8),
pub const WalkerEntry = struct {
/// The containing directory. This can be used to operate directly on `basename`
/// rather than `path`, avoiding `error.NameTooLong` for deeply nested paths.
/// The directory remains open until `next` or `deinit` is called.
dir: Dir,
basename: []const u8,
path: []const u8,
kind: Dir.Entry.Kind,
};
const StackItem = struct {
iter: Dir.Iterator,
dirname_len: usize,
};
/// After each call to this function, and on deinit(), the memory returned
/// from this function becomes invalid. A copy must be made in order to keep
/// a reference to the path.
pub fn next(self: *Walker) !?WalkerEntry {
while (self.stack.items.len != 0) {
// `top` becomes invalid after appending to `self.stack`
var top = &self.stack.items[self.stack.items.len - 1];
const dirname_len = top.dirname_len;
if (try top.iter.next()) |base| {
self.name_buffer.shrinkRetainingCapacity(dirname_len);
if (self.name_buffer.items.len != 0) {
try self.name_buffer.append(path.sep);
}
try self.name_buffer.appendSlice(base.name);
if (base.kind == .Directory) {
var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
error.NameTooLong => unreachable, // no path sep in base.name
else => |e| return e,
};
{
errdefer new_dir.close();
try self.stack.append(StackItem{
.iter = new_dir.iterate(),
.dirname_len = self.name_buffer.items.len,
});
top = &self.stack.items[self.stack.items.len - 1];
}
}
return WalkerEntry{
.dir = top.iter.dir,
.basename = self.name_buffer.items[dirname_len + 1 ..],
.path = self.name_buffer.items,
.kind = base.kind,
};
} else {
self.stack.pop().iter.dir.close();
}
}
return null;
}
pub fn deinit(self: *Walker) void {
while (self.stack.popOrNull()) |*item| item.iter.dir.close();
self.stack.deinit();
self.name_buffer.deinit();
}
};
/// Recursively iterates over a directory.
/// Must call `Walker.deinit` when done.
/// The order of returned file system entries is undefined.
pub fn walk(self: Dir, allocator: *Allocator) !Walker {
var name_buffer = std.ArrayList(u8).init(allocator);
errdefer name_buffer.deinit();
var stack = std.ArrayList(Walker.StackItem).init(allocator);
errdefer stack.deinit();
try stack.append(Walker.StackItem{
.iter = self.iterate(),
.dirname_len = 0,
});
return Walker{
.stack = stack,
.name_buffer = name_buffer,
};
}
pub const OpenError = error{
FileNotFound,
NotDir,
@ -2259,100 +2347,7 @@ pub fn symLinkAbsoluteZ(target_path_c: [*:0]const u8, sym_link_path_c: [*:0]cons
pub const symLink = @compileError("deprecated: use Dir.symLink or symLinkAbsolute");
pub const symLinkC = @compileError("deprecated: use Dir.symLinkZ or symLinkAbsoluteZ");
pub const Walker = struct {
stack: std.ArrayList(StackItem),
name_buffer: std.ArrayList(u8),
pub const Entry = struct {
/// The containing directory. This can be used to operate directly on `basename`
/// rather than `path`, avoiding `error.NameTooLong` for deeply nested paths.
/// The directory remains open until `next` or `deinit` is called.
dir: Dir,
/// TODO make this null terminated for API convenience
basename: []const u8,
path: []const u8,
kind: Dir.Entry.Kind,
};
const StackItem = struct {
dir_it: Dir.Iterator,
dirname_len: usize,
};
/// After each call to this function, and on deinit(), the memory returned
/// from this function becomes invalid. A copy must be made in order to keep
/// a reference to the path.
pub fn next(self: *Walker) !?Entry {
while (true) {
if (self.stack.items.len == 0) return null;
// `top` becomes invalid after appending to `self.stack`.
var top = &self.stack.items[self.stack.items.len - 1];
const dirname_len = top.dirname_len;
if (try top.dir_it.next()) |base| {
self.name_buffer.shrinkRetainingCapacity(dirname_len);
try self.name_buffer.append(path.sep);
try self.name_buffer.appendSlice(base.name);
if (base.kind == .Directory) {
var new_dir = top.dir_it.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
error.NameTooLong => unreachable, // no path sep in base.name
else => |e| return e,
};
{
errdefer new_dir.close();
try self.stack.append(StackItem{
.dir_it = new_dir.iterate(),
.dirname_len = self.name_buffer.items.len,
});
top = &self.stack.items[self.stack.items.len - 1];
}
}
return Entry{
.dir = top.dir_it.dir,
.basename = self.name_buffer.items[dirname_len + 1 ..],
.path = self.name_buffer.items,
.kind = base.kind,
};
} else {
self.stack.pop().dir_it.dir.close();
}
}
}
pub fn deinit(self: *Walker) void {
while (self.stack.popOrNull()) |*item| item.dir_it.dir.close();
self.stack.deinit();
self.name_buffer.deinit();
}
};
/// Recursively iterates over a directory.
/// Must call `Walker.deinit` when done.
/// `dir_path` must not end in a path separator.
/// The order of returned file system entries is undefined.
pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
assert(!mem.endsWith(u8, dir_path, path.sep_str));
var dir = try cwd().openDir(dir_path, .{ .iterate = true });
errdefer dir.close();
var name_buffer = std.ArrayList(u8).init(allocator);
errdefer name_buffer.deinit();
try name_buffer.appendSlice(dir_path);
var walker = Walker{
.stack = std.ArrayList(Walker.StackItem).init(allocator),
.name_buffer = name_buffer,
};
try walker.stack.append(Walker.StackItem{
.dir_it = dir.iterate(),
.dirname_len = dir_path.len,
});
return walker;
}
pub const walkPath = @compileError("deprecated: use Dir.walk");
pub const OpenSelfExeError = error{
SharingViolation,

View File

@ -927,8 +927,9 @@ test "walker" {
}
const tmp_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
const tmp_dir = try fs.cwd().openDir(tmp_path, .{ .iterate = true });
var walker = try fs.walkPath(testing.allocator, tmp_path);
var walker = try tmp_dir.walk(testing.allocator);
defer walker.deinit();
i = 0;
@ -941,7 +942,7 @@ test "walker" {
try fs.path.join(allocator, &[_][]const u8{ expected_dir_name, name });
var entry = (try walker.next()).?;
try testing.expectEqualStrings(expected_dir_name, try fs.path.relative(allocator, tmp_path, entry.path));
try testing.expectEqualStrings(expected_dir_name, entry.path);
}
}