authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-03-14 14:56:33 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-03-14 14:56:33 -07:00
logd36ce19ba6141444cab7be4f73686b947696bade
tree49620d642a7da59b7e366688d83a15d9d203bdf2
parentb5407960b0d512153e39e00af3a5a063977be944
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

start Repository struct


1 files changed, 86 insertions(+), 0 deletions(-)

git.zig+86
...@@ -965,3 +965,89 @@ pub const BlameIterator = struct {...@@ -965,3 +965,89 @@ pub const BlameIterator = struct {
965 line: string,965 line: string,
966 };966 };
967};967};
968
969pub const Repository = struct {
970 gitdir: nfs.Dir,
971 gpa: std.mem.Allocator,
972 raw_object_contents: std.StringArrayHashMapUnmanaged([]const u8) = .empty,
973 commits: std.StringArrayHashMapUnmanaged(Commit),
974
975 pub fn init(gitdir: nfs.Dir, gpa: std.mem.Allocator) Repository {
976 return .{
977 .gitdir = gitdir,
978 .gpa = gpa,
979 .commits = .empty,
980 };
981 }
982
983 pub fn deinit(r: *Repository) void {
984 for (r.raw_object_contents.values()) |v| r.gpa.free(v);
985 r.raw_object_contents.deinit(r.gpa);
986 r.commits.deinit(r.gpa);
987 }
988
989 fn getObject(r: *Repository, obj: Id) !?[]const u8 {
990 if (r.raw_object_contents.get(obj)) |content| {
991 return content;
992 }
993 if (obj.len == 40) blk: { //sha1 object
994 var sub_path: [49:0]u8 = "objects/00/00000000000000000000000000000000000000".*;
995 @memcpy(sub_path[8..][0..2], obj[0..2]);
996 @memcpy(sub_path[11..], obj[2..]);
997 const objfile = r.gitdir.openFile(&sub_path, .{}) catch |err| switch (err) {
998 error.ENOENT => break :blk,
999 else => |e| return e,
1000 };
1001 defer objfile.close();
1002 var bufr = nio.BufferedReader(4096, nfs.File).init(objfile);
1003 var list: std.ArrayList(u8) = .init(r.gpa);
1004 errdefer list.deinit();
1005 try list.ensureUnusedCapacity(512);
1006 try std.compress.flate.inflate.decompress(.zlib, bufr.anyReadable(), list.writer());
1007 const content = try list.toOwnedSlice();
1008 try r.raw_object_contents.put(r.gpa, obj, content);
1009 return content;
1010 }
1011 return null;
1012 }
1013
1014 fn getGitObject(r: *Repository, obj: Id, arena: std.mem.Allocator) !?GitObject {
1015 if (try r.getObject(obj)) |data| {
1016 const header = data[0..std.mem.indexOfScalar(u8, data, 0).?];
1017 const _type = header[0..std.mem.indexOfScalar(u8, header, ' ').?];
1018 const content_len = try extras.parseDigits(u64, header[_type.len + 1 ..], 10);
1019 std.debug.assert(data[header.len + 1 ..].len == content_len);
1020 return .{
1021 .type = std.meta.stringToEnum(RefType, _type).?,
1022 .content = try arena.dupe(u8, data[header.len + 1 ..]),
1023 };
1024 }
1025 return null;
1026 }
1027
1028 const RefType = enum {
1029 blob,
1030 tree,
1031 commit,
1032 tag,
1033 };
1034
1035 const GitObject = struct {
1036 type: RefType,
1037 content: []const u8,
1038 };
1039
1040 pub fn getCommit(r: *Repository, arena: std.mem.Allocator, id: CommitId) !?struct { CommitId, Commit } {
1041 if (r.commits.getPtr(id.id)) |val| {
1042 return .{ id, val.* };
1043 }
1044 if (try r.getGitObject(id.id, arena)) |obj| {
1045 if (obj.type == .commit) {
1046 const commit = try parseCommit(arena, obj.content);
1047 try r.commits.put(r.gpa, id.id, commit);
1048 return .{ id, commit };
1049 }
1050 }
1051 return null;
1052 }
1053};