| ... | @@ -29,7 +29,7 @@ pub const Diagnostics = struct { | ... | @@ -29,7 +29,7 @@ pub const Diagnostics = struct { |
| 29 | allocator: std.mem.Allocator, | 29 | allocator: std.mem.Allocator, |
| 30 | errors: std.ArrayListUnmanaged(Error) = .{}, | 30 | errors: std.ArrayListUnmanaged(Error) = .{}, |
| 31 | | 31 | |
| 32 | root_entries: usize = 0, | 32 | entries: usize = 0, |
| 33 | root_dir: []const u8 = "", | 33 | root_dir: []const u8 = "", |
| 34 | | 34 | |
| 35 | pub const Error = union(enum) { | 35 | pub const Error = union(enum) { |
| ... | @@ -48,41 +48,40 @@ pub const Diagnostics = struct { | ... | @@ -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 { | 51 | fn findRoot(d: *Diagnostics, path: []const u8) !void { |
| 52 | if (rootDir(path)) |root_dir| { | 52 | if (path.len == 0) return; |
| 53 | d.root_entries += 1; | 53 | |
| 54 | if (kind == .directory and d.root_entries == 1) { | 54 | d.entries += 1; |
| 55 | d.root_dir = try d.allocator.dupe(u8, root_dir); | 55 | const root_dir = rootDir(path); |
| 56 | return; | 56 | if (d.entries == 1) { |
| 57 | } | 57 | d.root_dir = try d.allocator.dupe(u8, root_dir); |
| 58 | d.allocator.free(d.root_dir); | 58 | return; |
| 59 | d.root_dir = ""; | | |
| 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. | 66 | // Returns root dir of the path, assumes non empty path. |
| 64 | fn rootDir(path: []const u8) ?[]const u8 { | 67 | fn rootDir(path: []const u8) []const u8 { |
| 65 | if (path.len == 0) return null; | | |
| 66 | | | |
| 67 | const start_index: usize = if (path[0] == '/') 1 else 0; | 68 | const start_index: usize = if (path[0] == '/') 1 else 0; |
| 68 | const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len; | 69 | const end_index: usize = if (path[path.len - 1] == '/') path.len - 1 else path.len; |
| 69 | const buf = path[start_index..end_index]; | 70 | const buf = path[start_index..end_index]; |
| 70 | return if (std.mem.indexOfScalarPos(u8, buf, 0, '/') == null) | 71 | if (std.mem.indexOfScalarPos(u8, buf, 0, '/')) |idx| { |
| 71 | buf | 72 | return buf[0..idx]; |
| 72 | else | 73 | } |
| 73 | null; | 74 | return buf; |
| 74 | } | 75 | } |
| 75 | | 76 | |
| 76 | test rootDir { | 77 | test rootDir { |
| 77 | const expectEqualStrings = testing.expectEqualStrings; | 78 | const expectEqualStrings = testing.expectEqualStrings; |
| 78 | const expect = testing.expect; | 79 | try expectEqualStrings("a", rootDir("a")); |
| 79 | | 80 | try expectEqualStrings("b", rootDir("b")); |
| 80 | try expectEqualStrings("a", rootDir("a").?); | 81 | try expectEqualStrings("c", rootDir("/c")); |
| 81 | try expectEqualStrings("b", rootDir("b").?); | 82 | try expectEqualStrings("d", rootDir("/d/")); |
| 82 | try expectEqualStrings("c", rootDir("/c").?); | 83 | try expectEqualStrings("a", rootDir("a/b")); |
| 83 | try expectEqualStrings("d", rootDir("/d/").?); | 84 | try expectEqualStrings("a", rootDir("a/b/c")); |
| 84 | try expect(rootDir("a/b") == null); | | |
| 85 | try expect(rootDir("") == null); | | |
| 86 | } | 85 | } |
| 87 | | 86 | |
| 88 | pub fn deinit(d: *Diagnostics) void { | 87 | pub fn deinit(d: *Diagnostics) void { |
| ... | @@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) | ... | @@ -625,7 +624,7 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) |
| 625 | while (try iter.next()) |file| { | 624 | while (try iter.next()) |file| { |
| 626 | const file_name = stripComponents(file.name, options.strip_components); | 625 | const file_name = stripComponents(file.name, options.strip_components); |
| 627 | if (options.diagnostics) |d| { | 626 | if (options.diagnostics) |d| { |
| 628 | try d.findRoot(file_name, file.kind); | 627 | try d.findRoot(file_name); |
| 629 | } | 628 | } |
| 630 | | 629 | |
| 631 | switch (file.kind) { | 630 | switch (file.kind) { |
| ... | @@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" { | ... | @@ -1056,7 +1055,7 @@ test "pipeToFileSystem root_dir" { |
| 1056 | | 1055 | |
| 1057 | // there is no root_dir | 1056 | // there is no root_dir |
| 1058 | try testing.expectEqual(0, diagnostics.root_dir.len); | 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 | // with strip_components = 0 | 1061 | // with strip_components = 0 |
| ... | @@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" { | ... | @@ -1078,10 +1077,25 @@ test "pipeToFileSystem root_dir" { |
| 1078 | | 1077 | |
| 1079 | // root_dir found | 1078 | // root_dir found |
| 1080 | try testing.expectEqualStrings("example", diagnostics.root_dir); | 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 | fn normalizePath(bytes: []u8) []u8 { | 1099 | fn normalizePath(bytes: []u8) []u8 { |
| 1086 | const canonical_sep = std.fs.path.sep_posix; | 1100 | const canonical_sep = std.fs.path.sep_posix; |
| 1087 | if (std.fs.path.sep == canonical_sep) return bytes; | 1101 | if (std.fs.path.sep == canonical_sep) return bytes; |