const std = @import("std"); const Alloc = std.mem.Allocator; const Id = u160; const Commit = struct { author: std.BoundedArray(u8, 64), message: std.BoundedArray(u8, 1024), parent: Id, tree: Id, }; const Blob = struct { data: std.BoundedArray(u8, 1024), }; const Object = struct { alloc: Alloc, // pub fn getCommit(self: *Object) Commit {} // pub fn getBlob(self: *Object) Blob {} }; const PackFile = struct { alloc: Alloc, pub fn init(alloc: Alloc) PackFile { return .{ .alloc = alloc, }; } pub fn deinit(self: *PackFile) void { _ = self; } pub fn parse(self: *PackFile, idxReader: std.io.AnyReader, pckReader: anytype) !void { _ = self; var buffer: [16]u8 = undefined; _ = try idxReader.read(&buffer); std.debug.print("{s}\n", .{&buffer}); _ = try pckReader.read(&buffer); std.debug.print("{s}\n", .{&buffer}); } // pub fn init(alloc: Alloc, path: []const u8) PackFile {} // pub fn deinit(self: *PackFile) void {} // pub fn getObject(self: *PackFile, id: Id) Object {} }; const Repo = struct { alloc: Alloc, packfile: PackFile, head: Id, pub fn open(alloc: Alloc, path: []const u8) !Repo { const dir = try std.fs.cwd().openDir(path, .{}); // read file HEAD const head = try dir.readFileAlloc(alloc, "HEAD", 1024); defer alloc.free(head); // read file pointed at by HEAD const headPath = head[5 .. head.len - 1]; var idBuffer: [40]u8 = undefined; const idStr = try dir.readFile(headPath, &idBuffer); // parse id from file const id = try std.fmt.parseUnsigned(u160, idStr, 16); // open any packfiles var packfile = PackFile.init(alloc); if (dir.openDir("objects/pack", .{ .iterate = true })) |packDir| { var packIt = packDir.iterate(); while (try packIt.next()) |f| { if (std.mem.endsWith(u8, f.name, ".idx")) { const idxFilename = f.name; var pckFilenameBuffer: [64]u8 = undefined; const pckFilename = try std.fmt.bufPrint(&pckFilenameBuffer, "{s}.pack", .{idxFilename[0 .. idxFilename.len - 4]}); const idxFile = try packDir.openFile(idxFilename, .{}); const pckFile = try packDir.openFile(pckFilename, .{}); defer idxFile.close(); defer pckFile.close(); const idxReader = idxFile.reader().any(); const pckReader = pckFile.reader().any(); try packfile.parse(idxReader, pckReader); } } } else |err| { std.debug.print("{}\n", .{err}); } return .{ .alloc = alloc, .packfile = packfile, .head = id, }; } pub fn close(self: *Repo) void { self.packfile.deinit(); } // pub fn getObject(self: *Repo, id: Id) Object {} }; test "print HEAD" { var repo = try Repo.open(std.testing.allocator, "../microwindows/.git"); defer repo.close(); std.debug.print("HEAD: {}\n", .{repo.head}); } // test "list commits" { // var repo = Repo.open(std.testing.allocator, "../microwindows/.git"); // defer repo.close(); // const head = repo.getObject(repo.head); // defer head.deinit(); // var c = head.getCommit(); // for (0..3) |_| { // std.debug.print("{}\n", .{c}); // c = c.parent; // } // } // test "tree" { // var repo = Repo.open(std.testing.allocator, "../microwindows/.git"); // defer repo.close(); // const head = repo.getObject(repo.head); // defer head.deinit(); // const commit = head.getCommit(); // std.debug.print("{}\n", .{commit.tree}); // } // test "blob" { // var repo = Repo.open(std.testing.allocator, "../microwindows/.git"); // defer repo.close(); // const head = repo.getObject(repo.head); // defer head.deinit(); // const commit = head.getCommit(); // const blob = repo.getBlob(commit.files[0].id); // std.debug.print("{}\n", .{blob}); // }