authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-04-11 19:27:40+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-11 15:44:40-07:00
log9cfac4718d2a536fdd096320cc68664ae1ee2c68
treef3c664be277b24d8b02ca1429806067067ce1037
parent0ac15b9726d03819f0e8837ae0490e1b9890a799

fetch: combine unpack error validation in a single function

Follow up of: #19500 [discussion](https://github.com/ziglang/zig/pull/19500#discussion_r1558238138)

1 files changed, 46 insertions(+), 49 deletions(-)

src/Package/Fetch.zig+46-49
......@@ -1802,45 +1802,25 @@ const UnpackResult = struct {
18021802 }
18031803
18041804 fn validate(self: *UnpackResult, f: *Fetch, filter: Filter) !void {
1805 self.filterErrors(filter);
1806 if (self.hasErrors()) {
1807 const eb = &f.error_bundle;
1808 try self.bundleErrors(eb, try f.srcLoc(f.location_tok));
1809 return error.FetchFailed;
1810 }
1811 }
1805 if (self.errors_count == 0) return;
18121806
1813 // Filter errors by manifest inclusion rules.
1814 fn filterErrors(self: *UnpackResult, filter: Filter) void {
1815 var i = self.errors_count;
1816 while (i > 0) {
1817 i -= 1;
1818 if (self.errors[i].excluded(filter)) {
1819 self.errors_count -= 1;
1820 const tmp = self.errors[i];
1821 self.errors[i] = self.errors[self.errors_count];
1822 self.errors[self.errors_count] = tmp;
1823 }
1807 var unfiltered_errors: u32 = 0;
1808 for (self.errors) |item| {
1809 if (item.excluded(filter)) continue;
1810 unfiltered_errors += 1;
18241811 }
1825 }
1826
1827 // Emmit errors to an `ErrorBundle`.
1828 fn bundleErrors(
1829 self: *UnpackResult,
1830 eb: *ErrorBundle.Wip,
1831 src_loc: ErrorBundle.SourceLocationIndex,
1832 ) !void {
1833 if (self.errors_count == 0 and self.root_error_message.len == 0)
1834 return;
1812 if (unfiltered_errors == 0) return;
18351813
1836 const notes_len: u32 = @intCast(self.errors_count);
1814 // Emmit errors to an `ErrorBundle`.
1815 const eb = &f.error_bundle;
18371816 try eb.addRootErrorMessage(.{
18381817 .msg = try eb.addString(self.root_error_message),
1839 .src_loc = src_loc,
1840 .notes_len = notes_len,
1818 .src_loc = try f.srcLoc(f.location_tok),
1819 .notes_len = unfiltered_errors,
18411820 });
1842 const notes_start = try eb.reserveNotes(notes_len);
1843 for (self.errors, notes_start..) |item, note_i| {
1821 var note_i: u32 = try eb.reserveNotes(unfiltered_errors);
1822 for (self.errors) |item| {
1823 if (item.excluded(filter)) continue;
18441824 switch (item) {
18451825 .unable_to_create_sym_link => |info| {
18461826 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
......@@ -1864,37 +1844,54 @@ const UnpackResult = struct {
18641844 }));
18651845 },
18661846 }
1847 note_i += 1;
18671848 }
1849
1850 return error.FetchFailed;
18681851 }
18691852
1870 test filterErrors {
1871 var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator);
1853 test validate {
1854 const gpa = std.testing.allocator;
1855 var arena_instance = std.heap.ArenaAllocator.init(gpa);
18721856 defer arena_instance.deinit();
18731857 const arena = arena_instance.allocator();
18741858
1875 // init
1859 // fill UnpackResult with errors
18761860 var res: UnpackResult = .{};
1877 try res.allocErrors(arena, 4, "error");
1861 try res.allocErrors(arena, 4, "unable to unpack");
18781862 try std.testing.expectEqual(0, res.errors_count);
1879
1880 // create errors
18811863 res.unableToCreateFile("dir1/file1", error.File1);
1882 res.unableToCreateSymLink("dir2/file2", "", error.File2);
1864 res.unableToCreateSymLink("dir2/file2", "filename", error.SymlinkError);
18831865 res.unableToCreateFile("dir1/file3", error.File3);
18841866 res.unsupportedFileType("dir2/file4", 'x');
18851867 try std.testing.expectEqual(4, res.errors_count);
18861868
1887 // filter errors
1869 // create filter, includes dir2, excludes dir1
18881870 var filter: Filter = .{};
18891871 try filter.include_paths.put(arena, "dir2", {});
1890 res.filterErrors(filter);
1891
1892 try std.testing.expectEqual(2, res.errors_count);
1893 try std.testing.expect(res.errors[0] == Error.unsupported_file_type);
1894 try std.testing.expect(res.errors[1] == Error.unable_to_create_sym_link);
1895 // filtered: moved to the list end
1896 try std.testing.expect(res.errors[2] == Error.unable_to_create_file);
1897 try std.testing.expect(res.errors[3] == Error.unable_to_create_file);
1872
1873 // init Fetch
1874 var fetch: Fetch = undefined;
1875 fetch.parent_manifest_ast = null;
1876 fetch.location_tok = 0;
1877 try fetch.error_bundle.init(gpa);
1878 defer fetch.error_bundle.deinit();
1879
1880 // validate errors with filter
1881 try std.testing.expectError(error.FetchFailed, res.validate(&fetch, filter));
1882
1883 // output errors to string
1884 var errors = try fetch.error_bundle.toOwnedBundle("");
1885 defer errors.deinit(gpa);
1886 var out = std.ArrayList(u8).init(gpa);
1887 defer out.deinit();
1888 try errors.renderToWriter(.{ .ttyconf = .no_color }, out.writer());
1889 try std.testing.expectEqualStrings(
1890 \\error: unable to unpack
1891 \\ note: unable to create symlink from 'dir2/file2' to 'filename': SymlinkError
1892 \\ note: file 'dir2/file4' has unsupported type 'x'
1893 \\
1894 , out.items);
18981895 }
18991896};
19001897