@@ -1143,61 +1143,23 @@ fn unpackResource(
1143
1143
}
1144
1144
}
1145
1145
1146
+ const Unpack = @import ("Unpack.zig" );
1147
+
1146
1148
fn unpackTarball (f : * Fetch , out_dir : fs.Dir , reader : anytype ) RunError ! void {
1147
1149
const eb = & f .error_bundle ;
1148
1150
const gpa = f .arena .child_allocator ;
1149
1151
1150
- var diagnostics : std.tar.Diagnostics = .{ .allocator = gpa };
1151
- defer diagnostics .deinit ();
1152
-
1153
- std .tar .pipeToFileSystem (out_dir , reader , .{
1154
- .diagnostics = & diagnostics ,
1155
- .strip_components = 1 ,
1156
- // TODO: we would like to set this to executable_bit_only, but two
1157
- // things need to happen before that:
1158
- // 1. the tar implementation needs to support it
1159
- // 2. the hashing algorithm here needs to support detecting the is_executable
1160
- // bit on Windows from the ACLs (see the isExecutable function).
1161
- .mode_mode = .ignore ,
1162
- .exclude_empty_directories = true ,
1163
- }) catch | err | return f .fail (f .location_tok , try eb .printString (
1164
- "unable to unpack tarball to temporary directory: {s}" ,
1165
- .{@errorName (err )},
1166
- ));
1167
-
1168
- if (diagnostics .errors .items .len > 0 ) {
1169
- const notes_len : u32 = @intCast (diagnostics .errors .items .len );
1170
- try eb .addRootErrorMessage (.{
1171
- .msg = try eb .addString ("unable to unpack tarball" ),
1172
- .src_loc = try f .srcLoc (f .location_tok ),
1173
- .notes_len = notes_len ,
1174
- });
1175
- const notes_start = try eb .reserveNotes (notes_len );
1176
- for (diagnostics .errors .items , notes_start .. ) | item , note_i | {
1177
- switch (item ) {
1178
- .unable_to_create_sym_link = > | info | {
1179
- eb .extra .items [note_i ] = @intFromEnum (try eb .addErrorMessage (.{
1180
- .msg = try eb .printString ("unable to create symlink from '{s}' to '{s}': {s}" , .{
1181
- info .file_name , info .link_name , @errorName (info .code ),
1182
- }),
1183
- }));
1184
- },
1185
- .unable_to_create_file = > | info | {
1186
- eb .extra .items [note_i ] = @intFromEnum (try eb .addErrorMessage (.{
1187
- .msg = try eb .printString ("unable to create file '{s}': {s}" , .{
1188
- info .file_name , @errorName (info .code ),
1189
- }),
1190
- }));
1191
- },
1192
- .unsupported_file_type = > | info | {
1193
- eb .extra .items [note_i ] = @intFromEnum (try eb .addErrorMessage (.{
1194
- .msg = try eb .printString ("file '{s}' has unsupported type '{c}'" , .{
1195
- info .file_name , @intFromEnum (info .file_type ),
1196
- }),
1197
- }));
1198
- },
1199
- }
1200
- }
1152
+ var unpack = Unpack { .allocator = gpa , .root = out_dir };
1153
+ defer unpack .deinit ();
1154
+ unpack .tarball (reader ) catch | err | return f .fail (
1155
+ f .location_tok ,
1156
+ try eb .printString (
1157
+ "unable to unpack tarball to temporary directory: {s}" ,
1158
+ .{@errorName (err )},
1159
+ ),
1160
+ );
1161
+ if (unpack .hasErrors ()) {
1162
+ try unpack .bundleErrors (eb , try f .srcLoc (f .location_tok ));
1201
1163
return error .FetchFailed ;
1202
1164
}
1203
1165
}
@@ -1207,104 +1169,26 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource) anyerror!void
1207
1169
const gpa = f .arena .child_allocator ;
1208
1170
const want_oid = resource .git .want_oid ;
1209
1171
const reader = resource .git .fetch_stream .reader ();
1210
- // The .git directory is used to store the packfile and associated index, but
1211
- // we do not attempt to replicate the exact structure of a real .git
1212
- // directory, since that isn't relevant for fetching a package.
1213
- {
1214
- var pack_dir = try out_dir .makeOpenPath (".git" , .{});
1215
- defer pack_dir .close ();
1216
- var pack_file = try pack_dir .createFile ("pkg.pack" , .{ .read = true });
1217
- defer pack_file .close ();
1218
- var fifo = std .fifo .LinearFifo (u8 , .{ .Static = 4096 }).init ();
1219
- try fifo .pump (reader , pack_file .writer ());
1220
- try pack_file .sync ();
1221
-
1222
- var index_file = try pack_dir .createFile ("pkg.idx" , .{ .read = true });
1223
- defer index_file .close ();
1224
- {
1225
- var index_prog_node = f .prog_node .start ("Index pack" , 0 );
1226
- defer index_prog_node .end ();
1227
- index_prog_node .activate ();
1228
- var index_buffered_writer = std .io .bufferedWriter (index_file .writer ());
1229
- try git .indexPack (gpa , pack_file , index_buffered_writer .writer ());
1230
- try index_buffered_writer .flush ();
1231
- try index_file .sync ();
1232
- }
1233
1172
1234
- {
1235
- var checkout_prog_node = f .prog_node .start ("Checkout" , 0 );
1236
- defer checkout_prog_node .end ();
1237
- checkout_prog_node .activate ();
1238
- var repository = try git .Repository .init (gpa , pack_file , index_file );
1239
- defer repository .deinit ();
1240
- var diagnostics : git.Diagnostics = .{ .allocator = gpa };
1241
- defer diagnostics .deinit ();
1242
- try repository .checkout (out_dir , want_oid , & diagnostics );
1243
-
1244
- if (diagnostics .errors .items .len > 0 ) {
1245
- const notes_len : u32 = @intCast (diagnostics .errors .items .len );
1246
- try eb .addRootErrorMessage (.{
1247
- .msg = try eb .addString ("unable to unpack packfile" ),
1248
- .src_loc = try f .srcLoc (f .location_tok ),
1249
- .notes_len = notes_len ,
1250
- });
1251
- const notes_start = try eb .reserveNotes (notes_len );
1252
- for (diagnostics .errors .items , notes_start .. ) | item , note_i | {
1253
- switch (item ) {
1254
- .unable_to_create_sym_link = > | info | {
1255
- eb .extra .items [note_i ] = @intFromEnum (try eb .addErrorMessage (.{
1256
- .msg = try eb .printString ("unable to create symlink from '{s}' to '{s}': {s}" , .{
1257
- info .file_name , info .link_name , @errorName (info .code ),
1258
- }),
1259
- }));
1260
- },
1261
- }
1262
- }
1263
- return error .InvalidGitPack ;
1264
- }
1265
- }
1173
+ var unpack = Unpack { .allocator = gpa , .root = out_dir };
1174
+ defer unpack .deinit ();
1175
+ try unpack .gitPack (want_oid , reader );
1176
+ if (unpack .hasErrors ()) {
1177
+ try unpack .bundleErrors (eb , try f .srcLoc (f .location_tok ));
1178
+ return error .FetchFailed ;
1266
1179
}
1267
-
1268
- try out_dir .deleteTree (".git" );
1269
1180
}
1270
1181
1271
1182
fn recursiveDirectoryCopy (f : * Fetch , dir : fs.Dir , tmp_dir : fs.Dir ) anyerror ! void {
1183
+ const eb = & f .error_bundle ;
1272
1184
const gpa = f .arena .child_allocator ;
1273
- // Recursive directory copy.
1274
- var it = try dir .walk (gpa );
1275
- defer it .deinit ();
1276
- while (try it .next ()) | entry | {
1277
- switch (entry .kind ) {
1278
- .directory = > {}, // omit empty directories
1279
- .file = > {
1280
- dir .copyFile (
1281
- entry .path ,
1282
- tmp_dir ,
1283
- entry .path ,
1284
- .{},
1285
- ) catch | err | switch (err ) {
1286
- error .FileNotFound = > {
1287
- if (fs .path .dirname (entry .path )) | dirname | try tmp_dir .makePath (dirname );
1288
- try dir .copyFile (entry .path , tmp_dir , entry .path , .{});
1289
- },
1290
- else = > | e | return e ,
1291
- };
1292
- },
1293
- .sym_link = > {
1294
- var buf : [fs .MAX_PATH_BYTES ]u8 = undefined ;
1295
- const link_name = try dir .readLink (entry .path , & buf );
1296
- // TODO: if this would create a symlink to outside
1297
- // the destination directory, fail with an error instead.
1298
- tmp_dir .symLink (link_name , entry .path , .{}) catch | err | switch (err ) {
1299
- error .FileNotFound = > {
1300
- if (fs .path .dirname (entry .path )) | dirname | try tmp_dir .makePath (dirname );
1301
- try tmp_dir .symLink (link_name , entry .path , .{});
1302
- },
1303
- else = > | e | return e ,
1304
- };
1305
- },
1306
- else = > return error .IllegalFileTypeInPackage ,
1307
- }
1185
+
1186
+ var unpack = Unpack { .allocator = gpa , .root = tmp_dir };
1187
+ defer unpack .deinit ();
1188
+ try unpack .directory (dir );
1189
+ if (unpack .hasErrors ()) {
1190
+ try unpack .bundleErrors (eb , try f .srcLoc (f .location_tok ));
1191
+ return error .FetchFailed ;
1308
1192
}
1309
1193
}
1310
1194
0 commit comments