authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-08-14 11:08:10+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-08-14 11:08:10+03:00
loge9bf8014bd29360353a9bfdff4aa9d5a45bc59f6
tree5bf91e0cb5e2489c297a5ccf1c8efcfe5d73e966
parentfcf2ce0ffee549ac882879364cd7e743ac10be20
parentf6bb56f8c7bd173982d48925d952afb0fd1cd6e5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9559 from squeek502/walker-basename

fs.Dir.Walker: Fix basename missing its first character for direct children of the initial directory

3 files changed, 44 insertions(+), 24 deletions(-)

lib/std/comptime_string_map.zig+5-3
...@@ -13,21 +13,21 @@ const mem = std.mem;...@@ -13,21 +13,21 @@ const mem = std.mem;
13/// `kvs` expects a list literal containing list literals or an array/slice of structs13/// `kvs` expects a list literal containing list literals or an array/slice of structs
14/// where `.@"0"` is the `[]const u8` key and `.@"1"` is the associated value of type `V`.14/// where `.@"0"` is the `[]const u8` key and `.@"1"` is the associated value of type `V`.
15/// TODO: https://github.com/ziglang/zig/issues/433515/// TODO: https://github.com/ziglang/zig/issues/4335
16pub fn ComptimeStringMap(comptime V: type, comptime kvs: anytype) type {16pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type {
17 const precomputed = comptime blk: {17 const precomputed = comptime blk: {
18 @setEvalBranchQuota(2000);18 @setEvalBranchQuota(2000);
19 const KV = struct {19 const KV = struct {
20 key: []const u8,20 key: []const u8,
21 value: V,21 value: V,
22 };22 };
23 var sorted_kvs: [kvs.len]KV = undefined;23 var sorted_kvs: [kvs_list.len]KV = undefined;
24 const lenAsc = (struct {24 const lenAsc = (struct {
25 fn lenAsc(context: void, a: KV, b: KV) bool {25 fn lenAsc(context: void, a: KV, b: KV) bool {
26 _ = context;26 _ = context;
27 return a.key.len < b.key.len;27 return a.key.len < b.key.len;
28 }28 }
29 }).lenAsc;29 }).lenAsc;
30 for (kvs) |kv, i| {30 for (kvs_list) |kv, i| {
31 if (V != void) {31 if (V != void) {
32 sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" };32 sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" };
33 } else {33 } else {
...@@ -56,6 +56,8 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs: anytype) type {...@@ -56,6 +56,8 @@ pub fn ComptimeStringMap(comptime V: type, comptime kvs: anytype) type {
56 };56 };
5757
58 return struct {58 return struct {
59 pub const kvs = precomputed.sorted_kvs;
60
59 pub fn has(str: []const u8) bool {61 pub fn has(str: []const u8) bool {
60 return get(str) != null;62 return get(str) != null;
61 }63 }
lib/std/fs.zig+3-2
...@@ -766,11 +766,12 @@ pub const Dir = struct {...@@ -766,11 +766,12 @@ pub const Dir = struct {
766 while (self.stack.items.len != 0) {766 while (self.stack.items.len != 0) {
767 // `top` becomes invalid after appending to `self.stack`767 // `top` becomes invalid after appending to `self.stack`
768 var top = &self.stack.items[self.stack.items.len - 1];768 var top = &self.stack.items[self.stack.items.len - 1];
769 const dirname_len = top.dirname_len;769 var dirname_len = top.dirname_len;
770 if (try top.iter.next()) |base| {770 if (try top.iter.next()) |base| {
771 self.name_buffer.shrinkRetainingCapacity(dirname_len);771 self.name_buffer.shrinkRetainingCapacity(dirname_len);
772 if (self.name_buffer.items.len != 0) {772 if (self.name_buffer.items.len != 0) {
773 try self.name_buffer.append(path.sep);773 try self.name_buffer.append(path.sep);
774 dirname_len += 1;
774 }775 }
775 try self.name_buffer.appendSlice(base.name);776 try self.name_buffer.appendSlice(base.name);
776 if (base.kind == .Directory) {777 if (base.kind == .Directory) {
...@@ -789,7 +790,7 @@ pub const Dir = struct {...@@ -789,7 +790,7 @@ pub const Dir = struct {
789 }790 }
790 return WalkerEntry{791 return WalkerEntry{
791 .dir = top.iter.dir,792 .dir = top.iter.dir,
792 .basename = self.name_buffer.items[dirname_len + 1 ..],793 .basename = self.name_buffer.items[dirname_len..],
793 .path = self.name_buffer.items,794 .path = self.name_buffer.items,
794 .kind = base.kind,795 .kind = base.kind,
795 };796 };
lib/std/fs/test.zig+36-19
...@@ -916,14 +916,30 @@ test "walker" {...@@ -916,14 +916,30 @@ test "walker" {
916 var tmp = tmpDir(.{});916 var tmp = tmpDir(.{});
917 defer tmp.cleanup();917 defer tmp.cleanup();
918918
919 const nb_dirs = 8;919 // iteration order of walker is undefined, so need lookup maps to check against
920920
921 var i: usize = 0;921 const expected_paths = std.ComptimeStringMap(void, .{
922 var sub_dir = tmp.dir;922 .{"dir1"},
923 while (i < nb_dirs) : (i += 1) {923 .{"dir2"},
924 const dir_name = try std.fmt.allocPrint(allocator, "{}", .{i});924 .{"dir3"},
925 try sub_dir.makeDir(dir_name);925 .{"dir4"},
926 sub_dir = try sub_dir.openDir(dir_name, .{});926 .{"dir3" ++ std.fs.path.sep_str ++ "sub1"},
927 .{"dir3" ++ std.fs.path.sep_str ++ "sub2"},
928 .{"dir3" ++ std.fs.path.sep_str ++ "sub2" ++ std.fs.path.sep_str ++ "subsub1"},
929 });
930
931 const expected_basenames = std.ComptimeStringMap(void, .{
932 .{"dir1"},
933 .{"dir2"},
934 .{"dir3"},
935 .{"dir4"},
936 .{"sub1"},
937 .{"sub2"},
938 .{"subsub1"},
939 });
940
941 for (expected_paths.kvs) |kv| {
942 try tmp.dir.makePath(kv.key);
927 }943 }
928944
929 const tmp_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });945 const tmp_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] });
...@@ -932,18 +948,19 @@ test "walker" {...@@ -932,18 +948,19 @@ test "walker" {
932 var walker = try tmp_dir.walk(testing.allocator);948 var walker = try tmp_dir.walk(testing.allocator);
933 defer walker.deinit();949 defer walker.deinit();
934950
935 i = 0;951 var num_walked: usize = 0;
936 var expected_dir_name: []const u8 = "";952 while (try walker.next()) |entry| {
937 while (i < nb_dirs) : (i += 1) {953 testing.expect(expected_basenames.has(entry.basename)) catch |err| {
938 const name = try std.fmt.allocPrint(allocator, "{}", .{i});954 std.debug.print("found unexpected basename: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.basename)});
939 expected_dir_name = if (expected_dir_name.len == 0)955 return err;
940 name956 };
941 else957 testing.expect(expected_paths.has(entry.path)) catch |err| {
942 try fs.path.join(allocator, &[_][]const u8{ expected_dir_name, name });958 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
943959 return err;
944 var entry = (try walker.next()).?;960 };
945 try testing.expectEqualStrings(expected_dir_name, entry.path);961 num_walked += 1;
946 }962 }
963 try testing.expectEqual(expected_paths.kvs.len, num_walked);
947}964}
948965
949test ". and .. in fs.Dir functions" {966test ". and .. in fs.Dir functions" {