Skip to content

Commit 92b3099

Browse files
committed
package.fetch: use git.iterator in unpack
1 parent e5dceed commit 92b3099

File tree

2 files changed

+77
-72
lines changed

2 files changed

+77
-72
lines changed

src/Package/Fetch/git.zig

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,7 +1479,7 @@ test "packfile indexing and checkout" {
14791479
return mem.lessThan(u8, a, b);
14801480
}
14811481
}.lessThan);
1482-
try testing.expectEqualDeep(repo.expected_files, actual_files.items);
1482+
try testing.expectEqualDeep(TestRepo.expected_files, actual_files.items);
14831483

14841484
const expected_file_contents =
14851485
\\revision 1
@@ -1502,12 +1502,13 @@ test "packfile indexing and checkout" {
15021502
try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
15031503
}
15041504

1505-
const TestRepo = struct {
1505+
pub const TestRepo = struct {
15061506
git_dir: testing.TmpDir,
15071507
pack_file: std.fs.File,
15081508
index_file: std.fs.File,
15091509
commit_id: Oid,
1510-
expected_files: []const []const u8 = &.{
1510+
1511+
pub const expected_files: []const []const u8 = &.{
15111512
"dir/file",
15121513
"dir/subdir/file",
15131514
"dir/subdir/file2",
@@ -1523,11 +1524,11 @@ const TestRepo = struct {
15231524
"file7",
15241525
"file8",
15251526
"file9",
1526-
},
1527+
};
15271528

1528-
fn open() !TestRepo {
1529-
const testrepo_pack = @embedFile("git/testdata/testrepo.pack");
1529+
const testrepo_pack = @embedFile("git/testdata/testrepo.pack");
15301530

1531+
pub fn open() !TestRepo {
15311532
var git_dir = testing.tmpDir(.{});
15321533
errdefer git_dir.cleanup();
15331534

@@ -1550,7 +1551,15 @@ const TestRepo = struct {
15501551
};
15511552
}
15521553

1553-
fn close(tr: *TestRepo) void {
1554+
pub fn stream() std.io.FixedBufferStream([]const u8) {
1555+
return .{ .buffer = testrepo_pack, .pos = 0 };
1556+
}
1557+
1558+
pub fn commitID() !Oid {
1559+
return try parseOid("dd582c0720819ab7130b103635bd7271b9fd4feb");
1560+
}
1561+
1562+
pub fn close(tr: *TestRepo) void {
15541563
tr.index_file.close();
15551564
tr.pack_file.close();
15561565
tr.git_dir.cleanup();
@@ -1583,7 +1592,7 @@ test "packfile iterator" {
15831592
return mem.lessThan(u8, a, b);
15841593
}
15851594
}.lessThan);
1586-
try testing.expectEqualDeep(repo.expected_files, actual_files.items);
1595+
try testing.expectEqualDeep(TestRepo.expected_files, actual_files.items);
15871596
}
15881597

15891598
/// Checks out a commit of a packfile. Intended for experimenting with and

src/Package/Unpack.zig

Lines changed: 60 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,18 @@ pub const Errors = struct {
5454
return self.list.items.len;
5555
}
5656

57-
fn createFile(self: *Errors, sub_path: []const u8, err: anyerror) !void {
57+
fn createFile(self: *Errors, subdir_path: []const u8, file_path: []const u8, err: anyerror) !void {
5858
try self.list.append(self.allocator, .{ .unable_to_create_file = .{
5959
.code = err,
60-
.file_name = try self.allocator.dupe(u8, sub_path),
60+
.file_name = try std.fs.path.join(testing.allocator, &.{ subdir_path, file_path }),
6161
} });
6262
}
6363

64-
fn symLink(self: *Errors, target_path: []const u8, sym_link_path: []const u8, err: anyerror) !void {
64+
fn symLink(self: *Errors, subdir_path: []const u8, target_path: []const u8, sym_link_path: []const u8, err: anyerror) !void {
6565
try self.list.append(self.allocator, .{ .unable_to_create_sym_link = .{
6666
.code = err,
6767
.target_path = try self.allocator.dupe(u8, target_path),
68-
.sym_link_path = try self.allocator.dupe(u8, sym_link_path),
68+
.sym_link_path = try std.fs.path.join(testing.allocator, &.{ subdir_path, sym_link_path }),
6969
} });
7070
}
7171

@@ -116,7 +116,7 @@ pub fn tarball(self: *Self, reader: anytype) !void {
116116
if (entry.size == 0 and entry.name.len == 0) continue;
117117
const file_name = stripComponents(entry.name, strip_components);
118118
if (file_name.len == 0) return error.BadFileName;
119-
if (try self.createFile(file_name)) |file| {
119+
if (try self.createFile("", file_name)) |file| {
120120
defer file.close();
121121
try entry.writeAll(file);
122122
}
@@ -125,29 +125,14 @@ pub fn tarball(self: *Self, reader: anytype) !void {
125125
const file_name = stripComponents(entry.name, strip_components);
126126
if (file_name.len == 0) return error.BadFileName;
127127
const link_name = entry.link_name;
128-
try self.symLink(link_name, file_name);
128+
try self.symLink("", link_name, file_name);
129129
},
130130
}
131131
} else break;
132132
}
133133
}
134134

135135
pub fn gitPack(self: *Self, commit_oid: git.Oid, reader: anytype) !void {
136-
// Same interface as std.fs.Dir.createFile, symLink
137-
const inf = struct {
138-
parent: *Self,
139-
140-
pub fn makePath(_: @This(), _: []const u8) !void {}
141-
142-
pub fn createFile(t: @This(), sub_path: []const u8, _: fs.File.CreateFlags) !fs.File {
143-
return (try t.parent.createFile(sub_path)) orelse error.Skip;
144-
}
145-
146-
pub fn symLink(t: @This(), target_path: []const u8, sym_link_path: []const u8, _: fs.Dir.SymLinkFlags) !void {
147-
try t.parent.symLink(target_path, sym_link_path);
148-
}
149-
}{ .parent = self };
150-
151136
var pack_dir = try self.root.makeOpenPath(".git", .{});
152137
defer pack_dir.close();
153138
var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
@@ -168,7 +153,22 @@ pub fn gitPack(self: *Self, commit_oid: git.Oid, reader: anytype) !void {
168153
{
169154
var repository = try git.Repository.init(self.allocator, pack_file, index_file);
170155
defer repository.deinit();
171-
try repository.checkout(inf, commit_oid);
156+
var iter = try repository.iterator(commit_oid);
157+
defer iter.deinit();
158+
while (try iter.next()) |entry| {
159+
switch (entry.type) {
160+
.file => {
161+
if (try self.createFile(entry.path, entry.name)) |file| {
162+
defer file.close();
163+
try file.writeAll(entry.data);
164+
}
165+
},
166+
.symlink => {
167+
try self.symLink(entry.path, entry.data, entry.name);
168+
},
169+
else => {}, // skip empty directory
170+
}
171+
}
172172
}
173173

174174
try self.root.deleteTree(".git");
@@ -186,7 +186,7 @@ pub fn directory(self: *Self, source: fs.Dir) !void {
186186
.sym_link => {
187187
var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
188188
const link_name = try source.readLink(entry.path, &buf);
189-
try self.symLink(link_name, entry.path);
189+
try self.symLink("", link_name, entry.path);
190190
},
191191
else => return error.IllegalFileTypeInPackage,
192192
}
@@ -201,6 +201,12 @@ pub fn filterErrors(self: *Self, filter: Filter) !void {
201201
try self.errors.filterWith(filter);
202202
}
203203

204+
fn makePath(self: *Self, sub_path: []const u8) !fs.Dir {
205+
if (sub_path.len == 0) return self.root;
206+
try self.root.makePath(sub_path);
207+
return try self.root.openDir(sub_path, .{});
208+
}
209+
204210
fn copyFile(source_dir: fs.Dir, source_path: []const u8, dest_dir: fs.Dir, dest_path: []const u8) !void {
205211
source_dir.copyFile(source_path, dest_dir, dest_path, .{}) catch |err| switch (err) {
206212
error.FileNotFound => {
@@ -213,32 +219,44 @@ fn copyFile(source_dir: fs.Dir, source_path: []const u8, dest_dir: fs.Dir, dest_
213219

214220
/// Returns fs.File on success, null on failure.
215221
/// Errors are collected in errors list.
216-
fn createFile(self: *Self, sub_path: []const u8) !?fs.File {
217-
return createFilePath(self.root, sub_path) catch |err| {
218-
try self.errors.createFile(sub_path, err);
222+
fn createFile(self: *Self, subdir_path: []const u8, file_path: []const u8) !?fs.File {
223+
return createFilePath(self.root, subdir_path, file_path) catch |err| {
224+
try self.errors.createFile(subdir_path, file_path, err);
219225
return null;
220226
};
221227
}
222228

223-
fn symLink(self: *Self, target_path: []const u8, sym_link_path: []const u8) !void {
224-
symLinkPath(self.root, target_path, sym_link_path) catch |err| {
225-
try self.errors.symLink(target_path, sym_link_path, err);
229+
fn symLink(self: *Self, subdir_path: []const u8, target_path: []const u8, sym_link_path: []const u8) !void {
230+
symLinkPath(self.root, subdir_path, target_path, sym_link_path) catch |err| {
231+
try self.errors.symLink(subdir_path, target_path, sym_link_path, err);
226232
};
227233
}
228234

229-
fn createFilePath(dir: fs.Dir, sub_path: []const u8) !fs.File {
230-
return dir.createFile(sub_path, .{ .exclusive = true }) catch |err| switch (err) {
235+
fn createFilePath(root: fs.Dir, subdir_path: []const u8, file_path: []const u8) !fs.File {
236+
var dir = root;
237+
if (subdir_path.len > 0) {
238+
try dir.makePath(subdir_path);
239+
dir = try dir.openDir(subdir_path, .{});
240+
}
241+
242+
return dir.createFile(file_path, .{ .exclusive = true }) catch |err| switch (err) {
231243
error.FileNotFound => {
232-
if (std.fs.path.dirname(sub_path)) |dirname| try dir.makePath(dirname);
233-
return try dir.createFile(sub_path, .{ .exclusive = true });
244+
if (std.fs.path.dirname(file_path)) |dirname| try dir.makePath(dirname);
245+
return try dir.createFile(file_path, .{ .exclusive = true });
234246
},
235247
else => |e| return e,
236248
};
237249
}
238250

239-
fn symLinkPath(dir: fs.Dir, target_path: []const u8, sym_link_path: []const u8) !void {
251+
fn symLinkPath(root: fs.Dir, subdir_path: []const u8, target_path: []const u8, sym_link_path: []const u8) !void {
240252
// TODO: if this would create a symlink to outside
241253
// the destination directory, fail with an error instead.
254+
var dir = root;
255+
if (subdir_path.len > 0) {
256+
try dir.makePath(subdir_path);
257+
dir = try dir.openDir(subdir_path, .{});
258+
}
259+
242260
dir.symLink(target_path, sym_link_path, .{}) catch |err| switch (err) {
243261
error.FileNotFound => {
244262
if (fs.path.dirname(sym_link_path)) |dirname| try dir.makePath(dirname);
@@ -275,40 +293,21 @@ test "tar stripComponents" {
275293
}
276294

277295
test gitPack {
278-
const paths: []const []const u8 = &.{
279-
"dir/file",
280-
"dir/subdir/file",
281-
"dir/subdir/file2",
282-
"dir2/file",
283-
"dir3/file",
284-
"dir3/file2",
285-
"file",
286-
"file2",
287-
"file3",
288-
"file4",
289-
"file5",
290-
"file6",
291-
"file7",
292-
"file8",
293-
"file9",
294-
};
295-
296-
// load git pack with expected files
297-
const data = @embedFile("Fetch/git/testdata/testrepo.pack");
298-
var fbs = std.io.fixedBufferStream(data);
299-
300296
var tmp = testing.tmpDir(.{ .iterate = true });
301297
defer tmp.cleanup();
302298

303-
// unpack git pack
299+
const repo = git.TestRepo;
300+
var stream = repo.stream();
301+
const reader = stream.reader();
302+
303+
// Unpack git repo at commitID from reader
304304
{
305305
var unpack = Unpack.init(testing.allocator, tmp.dir);
306306
defer unpack.deinit();
307-
const commit_id = try git.parseOid("dd582c0720819ab7130b103635bd7271b9fd4feb");
308-
try unpack.gitPack(commit_id, fbs.reader());
307+
try unpack.gitPack(try repo.commitID(), reader);
309308
}
310309

311-
try expectDirFiles(tmp.dir, paths);
310+
try expectDirFiles(tmp.dir, repo.expected_files);
312311
}
313312

314313
const TarHeader = std.tar.output.Header;
@@ -354,7 +353,7 @@ test directory {
354353
defer source.cleanup();
355354

356355
for (paths) |path| {
357-
const f = try createFilePath(source.dir, path);
356+
const f = try createFilePath(source.dir, "", path);
358357
f.close();
359358
}
360359

@@ -453,6 +452,3 @@ fn expectDirFiles(dir: fs.Dir, expected_files: []const []const u8) !void {
453452
}.lessThan);
454453
try testing.expectEqualDeep(expected_files, actual_files.items);
455454
}
456-
457-
// var buf: [256]u8 = undefined;
458-
// std.debug.print("tmp dir: {s}\n", .{try tmp.dir.realpath(".", &buf)});

0 commit comments

Comments
 (0)