X-Git-Url: https://gitweb.ps.run/ziggit/blobdiff_plain/1eff0cba79ccb40715c7d1257f8b0743bf2b6b0b..a6e6daa88e6d294fbb7b6173b3cc37bcad28ccc8:/git.zig diff --git a/git.zig b/git.zig index 7dd1d96..0d42c2a 100644 --- a/git.zig +++ b/git.zig @@ -8,11 +8,18 @@ const MaxFileSize = 1024 * 1024; const Id = u160; const Commit = struct { + tree: Id, + parent: Id, author: []u8, + committer: []u8, message: []u8, - parent: Id, - tree: Id, }; +const TreeEntry = struct { + permissions: []u8, + name: []u8, + id: Id, +}; +const Tree = std.ArrayList(TreeEntry); const Blob = struct { data: []u8, }; @@ -26,10 +33,67 @@ const Object = struct { .data = data, }; } + pub fn parse(self: Object, alloc: Alloc) !union(enum) { c: Commit, t: Tree, b: Blob } { + switch (self.kind) { + 1 => { + const authorOffset = std.mem.indexOf(u8, self.data, "author ") orelse return error.InvalidCommitFormat; + const authorNewline = std.mem.indexOfScalarPos(u8, self.data, authorOffset, '\n') orelse return error.InvalidCommitFormat; + const committerOffset = std.mem.indexOf(u8, self.data, "committer ") orelse return error.InvalidCommitFormat; + const committerNewline = std.mem.indexOfScalarPos(u8, self.data, committerOffset, '\n') orelse return error.InvalidCommitFormat; + + return .{ + .c = Commit{ + .tree = try std.fmt.parseUnsigned(Id, self.data[5..45], 16), + .parent = try std.fmt.parseUnsigned(Id, self.data[53..93], 16), + .author = self.data[authorOffset..authorNewline], + .committer = self.data[committerOffset..committerNewline], + .message = self.data[committerNewline + 1 .. self.data.len], + }, + }; + }, + 2 => { + var t = Tree.init(alloc); + + var offset: usize = 0; + + while (offset < self.data.len - 1) { + const spaceOffset = std.mem.indexOfScalarPos(u8, self.data, offset, ' ') orelse return error.InvalidTreeFormat; + const zeroOffset = std.mem.indexOfScalarPos(u8, self.data, spaceOffset, 0) orelse return error.InvalidTreeFormat; + + try t.append(.{ + .permissions = self.data[offset..spaceOffset], + .name = self.data[spaceOffset + 1 .. zeroOffset], + .id = std.mem.readVarInt(Id, self.data[zeroOffset + 1 .. zeroOffset + 21], .big), + }); + + offset = zeroOffset + 21; + } + + return .{ .t = t }; + }, + 3 => { + return .{ + .b = Blob{ .data = self.data }, + }; + }, + 4 => { + return error.TagNotImplemented; + }, + else => return error.UnknownGitObjectType, + } + } // pub fn getCommit(self: *Object) Commit {} // pub fn getBlob(self: *Object) Blob {} }; +fn decompress(alloc: Alloc, r: Reader) ![]u8 { + var buffer = std.ArrayList(u8).init(alloc); + + try std.compress.zlib.decompress(r, buffer.writer().any()); + + return alloc.realloc(buffer.allocatedSlice(), buffer.items.len); +} + const PackFile = struct { alloc: Alloc, idxFile: std.fs.File, @@ -326,12 +390,15 @@ const Repo = struct { } pub fn getObject(self: *Repo, id: Id) !?Object { - return self.packfile.getObject(id); + if (self.packfile) |*packfile| { + return packfile.getObject(id); + } + return null; } }; test "print HEAD" { - var repo = try Repo.open(std.testing.allocator, "../microwindows/.git"); + var repo = try Repo.open(std.testing.allocator, "../imgui/.git"); defer repo.close(); const head = try repo.getHead(); @@ -340,15 +407,17 @@ test "print HEAD" { } test "parse idx" { - var repo = try Repo.open(std.testing.allocator, "../microwindows/.git"); + var repo = try Repo.open(std.testing.allocator, "../imgui/.git"); defer repo.close(); - std.debug.print("{}\n", .{repo.packfile.objectOffsets.keys().len}); - std.debug.print("{}\n", .{repo.packfile.objectOffsets.values().len}); + if (repo.packfile) |packfile| { + std.debug.print("{}\n", .{packfile.objectOffsets.keys().len}); + std.debug.print("{}\n", .{packfile.objectOffsets.values().len}); + } } test "get object" { - var repo = try Repo.open(std.testing.allocator, "../microwindows/.git"); + var repo = try Repo.open(std.testing.allocator, "../imgui/.git"); defer repo.close(); const head = try repo.getHead();