authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-04-07 01:04:38+02:00
committergravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-04-09 15:00:21+02:00
logb3339f3cd5b1eeb3419ee136e378dc3e348e6a83
tree2ba5650d462c29ac70d6996adc3c92308594944e
parent9e47857ae9340ecd77f73c3c22ae04c938d28ca7

tar: store diagnostic errors into UnpackResult

Test that UnpackResult prints same error output as diagnostic.

1 files changed, 149 insertions(+), 44 deletions(-)

src/Package/Fetch.zig+149-44
......@@ -1189,38 +1189,17 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
11891189 ));
11901190
11911191 if (diagnostics.errors.items.len > 0) {
1192 const notes_len: u32 = @intCast(diagnostics.errors.items.len);
1193 try eb.addRootErrorMessage(.{
1194 .msg = try eb.addString("unable to unpack tarball"),
1195 .src_loc = try f.srcLoc(f.location_tok),
1196 .notes_len = notes_len,
1197 });
1198 const notes_start = try eb.reserveNotes(notes_len);
1199 for (diagnostics.errors.items, notes_start..) |item, note_i| {
1192 var res = UnpackResult.init(gpa);
1193 defer res.deinit();
1194
1195 for (diagnostics.errors.items) |item| {
12001196 switch (item) {
1201 .unable_to_create_sym_link => |info| {
1202 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1203 .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
1204 info.file_name, info.link_name, @errorName(info.code),
1205 }),
1206 }));
1207 },
1208 .unable_to_create_file => |info| {
1209 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1210 .msg = try eb.printString("unable to create file '{s}': {s}", .{
1211 info.file_name, @errorName(info.code),
1212 }),
1213 }));
1214 },
1215 .unsupported_file_type => |info| {
1216 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1217 .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{
1218 info.file_name, @intFromEnum(info.file_type),
1219 }),
1220 }));
1221 },
1197 .unable_to_create_file => |i| try res.createFile(i.file_name, i.code),
1198 .unable_to_create_sym_link => |i| try res.symLink(i.file_name, i.link_name, i.code),
1199 .unsupported_file_type => |i| try res.unsupportedFileType(i.file_name, @intFromEnum(i.file_type)),
12221200 }
12231201 }
1202 try res.bundleErrors(eb, "unable to unpack tarball", try f.srcLoc(f.location_tok));
12241203 return error.FetchFailed;
12251204 }
12261205
......@@ -1270,24 +1249,16 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void
12701249 try repository.checkout(out_dir, want_oid, &diagnostics);
12711250
12721251 if (diagnostics.errors.items.len > 0) {
1273 const notes_len: u32 = @intCast(diagnostics.errors.items.len);
1274 try eb.addRootErrorMessage(.{
1275 .msg = try eb.addString("unable to unpack packfile"),
1276 .src_loc = try f.srcLoc(f.location_tok),
1277 .notes_len = notes_len,
1278 });
1279 const notes_start = try eb.reserveNotes(notes_len);
1280 for (diagnostics.errors.items, notes_start..) |item, note_i| {
1252 var res = UnpackResult.init(gpa);
1253 defer res.deinit();
1254
1255 for (diagnostics.errors.items) |item| {
12811256 switch (item) {
1282 .unable_to_create_sym_link => |info| {
1283 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1284 .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
1285 info.file_name, info.link_name, @errorName(info.code),
1286 }),
1287 }));
1288 },
1257 .unable_to_create_sym_link => |i| try res.symLink(i.file_name, i.link_name, i.code),
12891258 }
12901259 }
1260 try res.bundleErrors(eb, "unable to unpack packfile", try f.srcLoc(f.location_tok));
1261
12911262 return error.InvalidGitPack;
12921263 }
12931264 }
......@@ -1779,6 +1750,140 @@ test FileHeader {
17791750 try std.testing.expect(h.isExecutable());
17801751}
17811752
1753const UnpackResult = struct {
1754 allocator: std.mem.Allocator,
1755 errors: std.ArrayListUnmanaged(Error) = .{},
1756
1757 const Error = union(enum) {
1758 unable_to_create_sym_link: struct {
1759 code: anyerror,
1760 file_name: []const u8,
1761 link_name: []const u8,
1762 },
1763 unable_to_create_file: struct {
1764 code: anyerror,
1765 file_name: []const u8,
1766 },
1767 unsupported_file_type: struct {
1768 file_name: []const u8,
1769 file_type: u8,
1770 },
1771
1772 fn excluded(self: Error, filter: Filter) bool {
1773 switch (self) {
1774 .unable_to_create_file => |info| return !filter.includePath(info.file_name),
1775 .unable_to_create_sym_link => |info| return !filter.includePath(info.file_name),
1776 .unsupported_file_type => |info| return !filter.includePath(info.file_name),
1777 }
1778 }
1779
1780 fn free(self: Error, allocator: std.mem.Allocator) void {
1781 switch (self) {
1782 .unable_to_create_sym_link => |info| {
1783 allocator.free(info.file_name);
1784 allocator.free(info.link_name);
1785 },
1786 .unable_to_create_file => |info| {
1787 allocator.free(info.file_name);
1788 },
1789 .unsupported_file_type => |info| {
1790 allocator.free(info.file_name);
1791 },
1792 }
1793 }
1794 };
1795
1796 fn init(allocator: std.mem.Allocator) UnpackResult {
1797 return .{ .allocator = allocator };
1798 }
1799
1800 fn deinit(self: *UnpackResult) void {
1801 for (self.errors.items) |item| {
1802 item.free(self.allocator);
1803 }
1804 self.errors.deinit(self.allocator);
1805 self.* = undefined;
1806 }
1807
1808 fn hasErrors(self: *UnpackResult) bool {
1809 return self.errors.items.len > 0;
1810 }
1811
1812 fn createFile(self: *UnpackResult, file_name: []const u8, err: anyerror) !void {
1813 try self.errors.append(self.allocator, .{ .unable_to_create_file = .{
1814 .code = err,
1815 .file_name = try self.allocator.dupe(u8, file_name),
1816 } });
1817 }
1818
1819 fn symLink(self: *UnpackResult, file_name: []const u8, link_name: []const u8, err: anyerror) !void {
1820 try self.errors.append(self.allocator, .{ .unable_to_create_sym_link = .{
1821 .code = err,
1822 .file_name = try self.allocator.dupe(u8, file_name),
1823 .link_name = try self.allocator.dupe(u8, link_name),
1824 } });
1825 }
1826
1827 fn unsupportedFileType(self: *UnpackResult, file_name: []const u8, file_type: u8) !void {
1828 try self.errors.append(self.allocator, .{ .unsupported_file_type = .{
1829 .file_name = try self.allocator.dupe(u8, file_name),
1830 .file_type = file_type,
1831 } });
1832 }
1833
1834 fn filterErrors(self: *UnpackResult, filter: Filter) !void {
1835 var i = self.errors.items.len;
1836 while (i > 0) {
1837 i -= 1;
1838 const item = self.errors.items[i];
1839 if (item.excluded(filter)) {
1840 _ = self.errors.swapRemove(i);
1841 item.free(self.allocator);
1842 }
1843 }
1844 }
1845
1846 fn bundleErrors(
1847 self: *UnpackResult,
1848 eb: *ErrorBundle.Wip,
1849 msg: []const u8,
1850 src_loc: ErrorBundle.SourceLocationIndex,
1851 ) !void {
1852 const notes_len: u32 = @intCast(self.errors.items.len);
1853 try eb.addRootErrorMessage(.{
1854 .msg = try eb.addString(msg),
1855 .src_loc = src_loc,
1856 .notes_len = notes_len,
1857 });
1858 const notes_start = try eb.reserveNotes(notes_len);
1859 for (self.errors.items, notes_start..) |item, note_i| {
1860 switch (item) {
1861 .unable_to_create_sym_link => |info| {
1862 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1863 .msg = try eb.printString("unable to create symlink from '{s}' to '{s}': {s}", .{
1864 info.file_name, info.link_name, @errorName(info.code),
1865 }),
1866 }));
1867 },
1868 .unable_to_create_file => |info| {
1869 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1870 .msg = try eb.printString("unable to create file '{s}': {s}", .{
1871 info.file_name, @errorName(info.code),
1872 }),
1873 }));
1874 },
1875 .unsupported_file_type => |info| {
1876 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
1877 .msg = try eb.printString("file '{s}' has unsupported type '{c}'", .{
1878 info.file_name, info.file_type,
1879 }),
1880 }));
1881 },
1882 }
1883 }
1884 }
1885};
1886
17821887// Removing dependencies
17831888const Package = struct {
17841889 const build_zig_basename = "build.zig";