mirror of
https://github.com/ziglang/zig.git
synced 2026-01-02 19:43:29 +00:00
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:
parent
f476463cd2
commit
c1285a1bbe
@ -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,
|
||||
}
|
||||
|
||||
183
lib/std/fs.zig
183
lib/std/fs.zig
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user