| ... | @@ -1802,45 +1802,25 @@ const UnpackResult = struct { | ... | @@ -1802,45 +1802,25 @@ const UnpackResult = struct { |
| 1802 | } | 1802 | } |
| 1803 | | 1803 | |
| 1804 | fn validate(self: *UnpackResult, f: *Fetch, filter: Filter) !void { | 1804 | fn validate(self: *UnpackResult, f: *Fetch, filter: Filter) !void { |
| 1805 | self.filterErrors(filter); | 1805 | if (self.errors_count == 0) return; |
| 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 | } | | |
| 1812 | | 1806 | |
| 1813 | // Filter errors by manifest inclusion rules. | 1807 | var unfiltered_errors: u32 = 0; |
| 1814 | fn filterErrors(self: *UnpackResult, filter: Filter) void { | 1808 | for (self.errors) |item| { |
| 1815 | var i = self.errors_count; | 1809 | if (item.excluded(filter)) continue; |
| 1816 | while (i > 0) { | 1810 | unfiltered_errors += 1; |
| 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 | } | | |
| 1824 | } | 1811 | } |
| 1825 | } | 1812 | if (unfiltered_errors == 0) return; |
| 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; | | |
| 1835 | | 1813 | |
| 1836 | const notes_len: u32 = @intCast(self.errors_count); | 1814 | // Emmit errors to an `ErrorBundle`. |
| | 1815 | const eb = &f.error_bundle; |
| 1837 | try eb.addRootErrorMessage(.{ | 1816 | try eb.addRootErrorMessage(.{ |
| 1838 | .msg = try eb.addString(self.root_error_message), | 1817 | .msg = try eb.addString(self.root_error_message), |
| 1839 | .src_loc = src_loc, | 1818 | .src_loc = try f.srcLoc(f.location_tok), |
| 1840 | .notes_len = notes_len, | 1819 | .notes_len = unfiltered_errors, |
| 1841 | }); | 1820 | }); |
| 1842 | const notes_start = try eb.reserveNotes(notes_len); | 1821 | var note_i: u32 = try eb.reserveNotes(unfiltered_errors); |
| 1843 | for (self.errors, notes_start..) |item, note_i| { | 1822 | for (self.errors) |item| { |
| | 1823 | if (item.excluded(filter)) continue; |
| 1844 | switch (item) { | 1824 | switch (item) { |
| 1845 | .unable_to_create_sym_link => |info| { | 1825 | .unable_to_create_sym_link => |info| { |
| 1846 | eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{ | 1826 | eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{ |
| ... | @@ -1864,37 +1844,54 @@ const UnpackResult = struct { | ... | @@ -1864,37 +1844,54 @@ const UnpackResult = struct { |
| 1864 | })); | 1844 | })); |
| 1865 | }, | 1845 | }, |
| 1866 | } | 1846 | } |
| | 1847 | note_i += 1; |
| 1867 | } | 1848 | } |
| | 1849 | |
| | 1850 | return error.FetchFailed; |
| 1868 | } | 1851 | } |
| 1869 | | 1852 | |
| 1870 | test filterErrors { | 1853 | test validate { |
| 1871 | var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator); | 1854 | const gpa = std.testing.allocator; |
| | 1855 | var arena_instance = std.heap.ArenaAllocator.init(gpa); |
| 1872 | defer arena_instance.deinit(); | 1856 | defer arena_instance.deinit(); |
| 1873 | const arena = arena_instance.allocator(); | 1857 | const arena = arena_instance.allocator(); |
| 1874 | | 1858 | |
| 1875 | // init | 1859 | // fill UnpackResult with errors |
| 1876 | var res: UnpackResult = .{}; | 1860 | var res: UnpackResult = .{}; |
| 1877 | try res.allocErrors(arena, 4, "error"); | 1861 | try res.allocErrors(arena, 4, "unable to unpack"); |
| 1878 | try std.testing.expectEqual(0, res.errors_count); | 1862 | try std.testing.expectEqual(0, res.errors_count); |
| 1879 | | | |
| 1880 | // create errors | | |
| 1881 | res.unableToCreateFile("dir1/file1", error.File1); | 1863 | res.unableToCreateFile("dir1/file1", error.File1); |
| 1882 | res.unableToCreateSymLink("dir2/file2", "", error.File2); | 1864 | res.unableToCreateSymLink("dir2/file2", "filename", error.SymlinkError); |
| 1883 | res.unableToCreateFile("dir1/file3", error.File3); | 1865 | res.unableToCreateFile("dir1/file3", error.File3); |
| 1884 | res.unsupportedFileType("dir2/file4", 'x'); | 1866 | res.unsupportedFileType("dir2/file4", 'x'); |
| 1885 | try std.testing.expectEqual(4, res.errors_count); | 1867 | try std.testing.expectEqual(4, res.errors_count); |
| 1886 | | 1868 | |
| 1887 | // filter errors | 1869 | // create filter, includes dir2, excludes dir1 |
| 1888 | var filter: Filter = .{}; | 1870 | var filter: Filter = .{}; |
| 1889 | try filter.include_paths.put(arena, "dir2", {}); | 1871 | try filter.include_paths.put(arena, "dir2", {}); |
| 1890 | res.filterErrors(filter); | 1872 | |
| 1891 | | 1873 | // init Fetch |
| 1892 | try std.testing.expectEqual(2, res.errors_count); | 1874 | var fetch: Fetch = undefined; |
| 1893 | try std.testing.expect(res.errors[0] == Error.unsupported_file_type); | 1875 | fetch.parent_manifest_ast = null; |
| 1894 | try std.testing.expect(res.errors[1] == Error.unable_to_create_sym_link); | 1876 | fetch.location_tok = 0; |
| 1895 | // filtered: moved to the list end | 1877 | try fetch.error_bundle.init(gpa); |
| 1896 | try std.testing.expect(res.errors[2] == Error.unable_to_create_file); | 1878 | defer fetch.error_bundle.deinit(); |
| 1897 | try std.testing.expect(res.errors[3] == Error.unable_to_create_file); | 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); |
| 1898 | } | 1895 | } |
| 1899 | }; | 1896 | }; |
| 1900 | | 1897 | |