Commit c1285a1bbe
lib/std/fs/test.zig
@@ -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);
}
}
lib/std/build.zig
@@ -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,
}
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,