authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-03-28 21:06:26+01:00
committergravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-04-09 15:00:21+02:00
loga0790914b4e0123e36432e2c0bcbf2a517fc410a
tree19abc7616d7a948ff6913f984cb946a2ad3070f4
parentb3339f3cd5b1eeb3419ee136e378dc3e348e6a83

fetch: return UnpackResult from unpackResource

Test that we are still outputing same errors.

1 files changed, 42 insertions(+), 38 deletions(-)

src/Package/Fetch.zig+42-38
...@@ -461,13 +461,16 @@ fn runResource(...@@ -461,13 +461,16 @@ fn runResource(
461 };461 };
462 defer tmp_directory.handle.close();462 defer tmp_directory.handle.close();
463463
464 // Unpack resource into tmp_directory. A non-null return value means464 var unpack_result = try unpackResource(f, resource, uri_path, tmp_directory);
465 // that the package contents are inside a `pkg_dir` sub-directory.465 defer unpack_result.deinit();
466 const pkg_dir = try unpackResource(f, resource, uri_path, tmp_directory);466 if (unpack_result.hasErrors()) {
467 try unpack_result.bundleErrors(eb, try f.srcLoc(f.location_tok));
468 return error.FetchFailed;
469 }
467470
468 var pkg_path: Cache.Path = .{471 var pkg_path: Cache.Path = .{
469 .root_dir = tmp_directory,472 .root_dir = tmp_directory,
470 .sub_path = if (pkg_dir) |pkg_dir_name| pkg_dir_name else "",473 .sub_path = if (unpack_result.root_dir) |root_dir| root_dir else "",
471 };474 };
472475
473 // Apply btrfs workaround if needed. Reopen tmp_directory.476 // Apply btrfs workaround if needed. Reopen tmp_directory.
...@@ -500,8 +503,8 @@ fn runResource(...@@ -500,8 +503,8 @@ fn runResource(
500 // directory.503 // directory.
501 f.actual_hash = try computeHash(f, pkg_path, filter);504 f.actual_hash = try computeHash(f, pkg_path, filter);
502505
503 break :blk if (pkg_dir) |pkg_dir_name|506 break :blk if (unpack_result.root_dir) |root_dir|
504 try fs.path.join(arena, &.{ tmp_dir_sub_path, pkg_dir_name })507 try fs.path.join(arena, &.{ tmp_dir_sub_path, root_dir })
505 else508 else
506 tmp_dir_sub_path;509 tmp_dir_sub_path;
507 };510 };
...@@ -1053,7 +1056,7 @@ fn unpackResource(...@@ -1053,7 +1056,7 @@ fn unpackResource(
1053 resource: *Resource,1056 resource: *Resource,
1054 uri_path: []const u8,1057 uri_path: []const u8,
1055 tmp_directory: Cache.Directory,1058 tmp_directory: Cache.Directory,
1056) RunError!?[]const u8 {1059) RunError!UnpackResult {
1057 const eb = &f.error_bundle;1060 const eb = &f.error_bundle;
1058 const file_type = switch (resource.*) {1061 const file_type = switch (resource.*) {
1059 .file => FileType.fromPath(uri_path) orelse1062 .file => FileType.fromPath(uri_path) orelse
...@@ -1121,7 +1124,8 @@ fn unpackResource(...@@ -1121,7 +1124,8 @@ fn unpackResource(
1121 .{ uri_path, @errorName(err) },1124 .{ uri_path, @errorName(err) },
1122 ));1125 ));
1123 };1126 };
1124 return null;1127 const gpa = f.arena.child_allocator;
1128 return UnpackResult.init(gpa);
1125 },1129 },
1126 };1130 };
11271131
...@@ -1156,23 +1160,19 @@ fn unpackResource(...@@ -1156,23 +1160,19 @@ fn unpackResource(
1156 });1160 });
1157 return try unpackTarball(f, tmp_directory.handle, dcp.reader());1161 return try unpackTarball(f, tmp_directory.handle, dcp.reader());
1158 },1162 },
1159 .git_pack => {1163 .git_pack => return unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) {
1160 unpackGitPack(f, tmp_directory.handle, resource) catch |err| switch (err) {1164 error.FetchFailed => return error.FetchFailed,
1161 error.FetchFailed => return error.FetchFailed,1165 error.OutOfMemory => return error.OutOfMemory,
1162 error.OutOfMemory => return error.OutOfMemory,1166 else => |e| return f.fail(f.location_tok, try eb.printString(
1163 else => |e| return f.fail(f.location_tok, try eb.printString(1167 "unable to unpack git files: {s}",
1164 "unable to unpack git files: {s}",1168 .{@errorName(e)},
1165 .{@errorName(e)},1169 )),
1166 )),
1167 };
1168 return null;
1169 },1170 },
1170 }1171 }
1171}1172}
11721173
1173fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const u8 {1174fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
1174 const eb = &f.error_bundle;1175 const eb = &f.error_bundle;
1175 const arena = f.arena.allocator();
1176 const gpa = f.arena.child_allocator;1176 const gpa = f.arena.child_allocator;
11771177
1178 var diagnostics: std.tar.Diagnostics = .{ .allocator = gpa };1178 var diagnostics: std.tar.Diagnostics = .{ .allocator = gpa };
...@@ -1188,10 +1188,11 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const...@@ -1188,10 +1188,11 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
1188 .{@errorName(err)},1188 .{@errorName(err)},
1189 ));1189 ));
11901190
1191 var res = UnpackResult.init(gpa);
1192 if (diagnostics.root_dir) |root_dir| {
1193 res.root_dir = try gpa.dupe(u8, root_dir);
1194 }
1191 if (diagnostics.errors.items.len > 0) {1195 if (diagnostics.errors.items.len > 0) {
1192 var res = UnpackResult.init(gpa);
1193 defer res.deinit();
1194
1195 for (diagnostics.errors.items) |item| {1196 for (diagnostics.errors.items) |item| {
1196 switch (item) {1197 switch (item) {
1197 .unable_to_create_file => |i| try res.createFile(i.file_name, i.code),1198 .unable_to_create_file => |i| try res.createFile(i.file_name, i.code),
...@@ -1199,21 +1200,17 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const...@@ -1199,21 +1200,17 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!?[]const
1199 .unsupported_file_type => |i| try res.unsupportedFileType(i.file_name, @intFromEnum(i.file_type)),1200 .unsupported_file_type => |i| try res.unsupportedFileType(i.file_name, @intFromEnum(i.file_type)),
1200 }1201 }
1201 }1202 }
1202 try res.bundleErrors(eb, "unable to unpack tarball", try f.srcLoc(f.location_tok));1203 try res.rootErrorMessage("unable to unpack tarball");
1203 return error.FetchFailed;
1204 }1204 }
12051205 return res;
1206 return if (diagnostics.root_dir) |root_dir|
1207 return try arena.dupe(u8, root_dir)
1208 else
1209 null;
1210}1206}
12111207
1212fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void {1208fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!UnpackResult {
1213 const eb = &f.error_bundle;
1214 const gpa = f.arena.child_allocator;1209 const gpa = f.arena.child_allocator;
1215 const want_oid = resource.git.want_oid;1210 const want_oid = resource.git.want_oid;
1216 const reader = resource.git.fetch_stream.reader();1211 const reader = resource.git.fetch_stream.reader();
1212
1213 var res = UnpackResult.init(gpa);
1217 // The .git directory is used to store the packfile and associated index, but1214 // The .git directory is used to store the packfile and associated index, but
1218 // we do not attempt to replicate the exact structure of a real .git1215 // we do not attempt to replicate the exact structure of a real .git
1219 // directory, since that isn't relevant for fetching a package.1216 // directory, since that isn't relevant for fetching a package.
...@@ -1249,7 +1246,6 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void...@@ -1249,7 +1246,6 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void
1249 try repository.checkout(out_dir, want_oid, &diagnostics);1246 try repository.checkout(out_dir, want_oid, &diagnostics);
12501247
1251 if (diagnostics.errors.items.len > 0) {1248 if (diagnostics.errors.items.len > 0) {
1252 var res = UnpackResult.init(gpa);
1253 defer res.deinit();1249 defer res.deinit();
12541250
1255 for (diagnostics.errors.items) |item| {1251 for (diagnostics.errors.items) |item| {
...@@ -1257,14 +1253,13 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void...@@ -1257,14 +1253,13 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void
1257 .unable_to_create_sym_link => |i| try res.symLink(i.file_name, i.link_name, i.code),1253 .unable_to_create_sym_link => |i| try res.symLink(i.file_name, i.link_name, i.code),
1258 }1254 }
1259 }1255 }
1260 try res.bundleErrors(eb, "unable to unpack packfile", try f.srcLoc(f.location_tok));1256 try res.rootErrorMessage("unable to unpack packfile");
1261
1262 return error.InvalidGitPack;
1263 }1257 }
1264 }1258 }
1265 }1259 }
12661260
1267 try out_dir.deleteTree(".git");1261 try out_dir.deleteTree(".git");
1262 return res;
1268}1263}
12691264
1270fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void {1265fn recursiveDirectoryCopy(f: *Fetch, dir: fs.Dir, tmp_dir: fs.Dir) anyerror!void {
...@@ -1753,6 +1748,8 @@ test FileHeader {...@@ -1753,6 +1748,8 @@ test FileHeader {
1753const UnpackResult = struct {1748const UnpackResult = struct {
1754 allocator: std.mem.Allocator,1749 allocator: std.mem.Allocator,
1755 errors: std.ArrayListUnmanaged(Error) = .{},1750 errors: std.ArrayListUnmanaged(Error) = .{},
1751 root_error_message: []const u8 = "",
1752 root_dir: ?[]const u8 = null,
17561753
1757 const Error = union(enum) {1754 const Error = union(enum) {
1758 unable_to_create_sym_link: struct {1755 unable_to_create_sym_link: struct {
...@@ -1802,6 +1799,10 @@ const UnpackResult = struct {...@@ -1802,6 +1799,10 @@ const UnpackResult = struct {
1802 item.free(self.allocator);1799 item.free(self.allocator);
1803 }1800 }
1804 self.errors.deinit(self.allocator);1801 self.errors.deinit(self.allocator);
1802 self.allocator.free(self.root_error_message);
1803 if (self.root_dir) |root_dir| {
1804 self.allocator.free(root_dir);
1805 }
1805 self.* = undefined;1806 self.* = undefined;
1806 }1807 }
18071808
...@@ -1843,15 +1844,18 @@ const UnpackResult = struct {...@@ -1843,15 +1844,18 @@ const UnpackResult = struct {
1843 }1844 }
1844 }1845 }
18451846
1847 fn rootErrorMessage(self: *UnpackResult, msg: []const u8) !void {
1848 self.root_error_message = try self.allocator.dupe(u8, msg);
1849 }
1850
1846 fn bundleErrors(1851 fn bundleErrors(
1847 self: *UnpackResult,1852 self: *UnpackResult,
1848 eb: *ErrorBundle.Wip,1853 eb: *ErrorBundle.Wip,
1849 msg: []const u8,
1850 src_loc: ErrorBundle.SourceLocationIndex,1854 src_loc: ErrorBundle.SourceLocationIndex,
1851 ) !void {1855 ) !void {
1852 const notes_len: u32 = @intCast(self.errors.items.len);1856 const notes_len: u32 = @intCast(self.errors.items.len);
1853 try eb.addRootErrorMessage(.{1857 try eb.addRootErrorMessage(.{
1854 .msg = try eb.addString(msg),1858 .msg = try eb.addString(self.root_error_message),
1855 .src_loc = src_loc,1859 .src_loc = src_loc,
1856 .notes_len = notes_len,1860 .notes_len = notes_len,
1857 });1861 });