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 open(alloc: Alloc, dir: std.fs.Dir) !PackFile { var self = PackFile{ .alloc = alloc }; var packDir = try dir.openDir("objects/pack", .{ .iterate = true }); defer packDir.close(); var packIt = packDir.iterate(); while (try packIt.next()) |f| { if (std.mem.endsWith(u8, f.name, ".idx")) { const idxFilename = f.name; var pckFilename = try std.BoundedArray(u8, std.fs.max_path_bytes).init(0); try std.fmt.format( pckFilename.writer(), "{s}.pack", .{idxFilename[0 .. idxFilename.len - 4]}, ); const idxFile = try packDir.openFile(idxFilename, .{}); const pckFile = try packDir.openFile(pckFilename.constSlice(), .{}); defer idxFile.close(); defer pckFile.close(); const idxReader = idxFile.reader().any(); const pckReader = pckFile.reader().any(); try self.parse(idxReader, pckReader); } } return self; } pub fn parse(self: *PackFile, idxReader: std.io.AnyReader, pckReader: std.io.AnyReader) !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, dir: std.fs.Dir, packfile: PackFile, pub fn open(alloc: Alloc, path: []const u8) !Repo { const dir = try std.fs.cwd().openDir(path, .{}); const packfile = try PackFile.open(alloc, dir); return .{ .alloc = alloc, .dir = dir, .packfile = packfile, }; } pub fn close(self: *Repo) void { self.dir.close(); } pub fn getHead(self: *Repo) !Id { // read file HEAD const head = try self.dir.readFileAlloc(self.alloc, "HEAD", 1024); defer self.alloc.free(head); // read file pointed at by HEAD const headPath = head[5 .. head.len - 1]; var idBuffer: [40]u8 = undefined; const idStr = try self.dir.readFile(headPath, &idBuffer); // parse id from file return try std.fmt.parseUnsigned(u160, idStr, 16); } // pub fn getObject(self: *Repo, id: Id) Object {} }; test "print HEAD" { var repo = try Repo.open(std.testing.allocator, "../microwindows/.git"); defer repo.close(); const head = try repo.getHead(); std.debug.print("HEAD: {}\n", .{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}); // }