| ... | ... | @@ -29,7 +29,7 @@ pub const Diagnostics = struct { |
| 29 | 29 | allocator: std.mem.Allocator, |
| 30 | 30 | errors: std.ArrayListUnmanaged(Error) = .{}, |
| 31 | 31 | |
| 32 | | root_entries: usize = 0, |
| 32 | entries: usize = 0, |
| 33 | 33 | root_dir: []const u8 = "", |
| 34 | 34 | |
| 35 | 35 | pub const Error = union(enum) { |
| ... | ... | @@ -48,41 +48,40 @@ pub const Diagnostics = struct { |
| 48 | 48 | }, |
| 49 | 49 | }; |
| 50 | 50 | |
| 51 | | fn findRoot(d: *Diagnostics, path: []const u8, kind: FileKind) !void { |
| 52 | | if (rootDir(path)) |root_dir| { |
| 53 | | d.root_entries += 1; |
| 54 | | if (kind == .directory and d.root_entries == 1) { |
| 55 | | d.root_dir = try d.allocator.dupe(u8, root_dir); |
| 56 | | return; |
| 57 | | } |
| 58 | | d.allocator.free(d.root_dir); |
| 59 | | d.root_dir = ""; |
| 51 | fn findRoot(d: *Diagnostics, path: []const u8) !void { |
| 52 | if (path.len == 0) return; |
| 53 | |
| 54 | d.entries += 1; |
| 55 | const root_dir = rootDir(path); |
| 56 | if (d.entries == 1) { |
| 57 | d.root_dir = try d.allocator.dupe(u8, root_dir); |
| 58 | return; |
| 60 | 59 | } |
| 60 | if (d.root_dir.len == 0 or std.mem.eql(u8, root_dir, d.root_dir)) |
| 61 | return; |
| 62 | d.allocator.free(d.root_dir); |
| 63 | d.root_dir = ""; |
| 61 | 64 | } |
| 62 | 65 | |
| 63 | | // If path is package root returns root_dir name, otherwise null. |
| 64 | | fn rootDir(path: []const u8) ?[]const u8 { |
| 65 | | if (path.len == 0) return null; |
| 66 | | |
| 66 | // Returns root dir of the path, assumes non empty path. |
| 67 | fn rootDir(path: []const u8) []const u8 { |
| 67 | 68 | const start_index: usize = if (path[0] == '/') 1 else 0; |
| 68 | 69 | const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len; |
| 69 | 70 | const buf = path[start_index..end_index]; |
| 70 | | return if (std.mem.indexOfScalarPos(u8, buf, 0, '/') == null) |
| 71 | | buf |
| 72 | | else |
| 73 | | null; |
| 71 | if (std.mem.indexOfScalarPos(u8, buf, 0, '/')) |idx| { |
| 72 | return buf[0..idx]; |
| 73 | } |
| 74 | return buf; |
| 74 | 75 | } |
| 75 | 76 | |
| 76 | 77 | test rootDir { |
| 77 | 78 | const expectEqualStrings = testing.expectEqualStrings; |
| 78 | | const expect = testing.expect; |
| 79 | | |
| 80 | | try expectEqualStrings("a", rootDir("a").?); |
| 81 | | try expectEqualStrings("b", rootDir("b").?); |
| 82 | | try expectEqualStrings("c", rootDir("/c").?); |
| 83 | | try expectEqualStrings("d", rootDir("/d/").?); |
| 84 | | try expect(rootDir("a/b") == null); |
| 85 | | try expect(rootDir("") == null); |
| 79 | try expectEqualStrings("a", rootDir("a")); |
| 80 | try expectEqualStrings("b", rootDir("b")); |
| 81 | try expectEqualStrings("c", rootDir("/c")); |
| 82 | try expectEqualStrings("d", rootDir("/d/")); |
| 83 | try expectEqualStrings("a", rootDir("a/b")); |
| 84 | try expectEqualStrings("a", rootDir("a/b/c")); |
| 86 | 85 | } |
| 87 | 86 | |
| 88 | 87 | pub fn deinit(d: *Diagnostics) void { |
| ... | ... | @@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) |
| 625 | 624 | while (try iter.next()) |file| { |
| 626 | 625 | const file_name = stripComponents(file.name, options.strip_components); |
| 627 | 626 | if (options.diagnostics) |d| { |
| 628 | | try d.findRoot(file_name, file.kind); |
| 627 | try d.findRoot(file_name); |
| 629 | 628 | } |
| 630 | 629 | |
| 631 | 630 | switch (file.kind) { |
| ... | ... | @@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" { |
| 1056 | 1055 | |
| 1057 | 1056 | // there is no root_dir |
| 1058 | 1057 | try testing.expectEqual(0, diagnostics.root_dir.len); |
| 1059 | | try testing.expectEqual(3, diagnostics.root_entries); |
| 1058 | try testing.expectEqual(5, diagnostics.entries); |
| 1060 | 1059 | } |
| 1061 | 1060 | |
| 1062 | 1061 | // with strip_components = 0 |
| ... | ... | @@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" { |
| 1078 | 1077 | |
| 1079 | 1078 | // root_dir found |
| 1080 | 1079 | try testing.expectEqualStrings("example", diagnostics.root_dir); |
| 1081 | | try testing.expectEqual(1, diagnostics.root_entries); |
| 1080 | try testing.expectEqual(6, diagnostics.entries); |
| 1082 | 1081 | } |
| 1083 | 1082 | } |
| 1084 | 1083 | |
| 1084 | test "findRoot without explicit root dir" { |
| 1085 | const data = @embedFile("tar/testdata/19820.tar"); |
| 1086 | var fbs = std.io.fixedBufferStream(data); |
| 1087 | const reader = fbs.reader(); |
| 1088 | |
| 1089 | var tmp = testing.tmpDir(.{}); |
| 1090 | defer tmp.cleanup(); |
| 1091 | |
| 1092 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1093 | defer diagnostics.deinit(); |
| 1094 | try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics }); |
| 1095 | |
| 1096 | try testing.expectEqualStrings("root", diagnostics.root_dir); |
| 1097 | } |
| 1098 | |
| 1085 | 1099 | fn normalizePath(bytes: []u8) []u8 { |
| 1086 | 1100 | const canonical_sep = std.fs.path.sep_posix; |
| 1087 | 1101 | if (std.fs.path.sep == canonical_sep) return bytes; |