| ... | ... | @@ -950,6 +950,7 @@ pub const Repository = struct { |
| 950 | 950 | gpa: std.mem.Allocator, |
| 951 | 951 | raw_object_contents: std.StringArrayHashMapUnmanaged([]const u8), |
| 952 | 952 | commits: std.StringArrayHashMapUnmanaged(Commit), |
| 953 | trees: std.StringArrayHashMapUnmanaged(Tree), |
| 953 | 954 | |
| 954 | 955 | pub fn init(gitdir: nfs.Dir, gpa: std.mem.Allocator) Repository { |
| 955 | 956 | return .{ |
| ... | ... | @@ -957,6 +958,7 @@ pub const Repository = struct { |
| 957 | 958 | .gpa = gpa, |
| 958 | 959 | .raw_object_contents = .empty, |
| 959 | 960 | .commits = .empty, |
| 961 | .trees = .empty, |
| 960 | 962 | }; |
| 961 | 963 | } |
| 962 | 964 | |
| ... | ... | @@ -964,6 +966,8 @@ pub const Repository = struct { |
| 964 | 966 | for (r.raw_object_contents.values()) |v| r.gpa.free(v); |
| 965 | 967 | r.raw_object_contents.deinit(r.gpa); |
| 966 | 968 | r.commits.deinit(r.gpa); |
| 969 | for (r.trees.values()) |v| r.gpa.free(v.children); |
| 970 | r.trees.deinit(r.gpa); |
| 967 | 971 | } |
| 968 | 972 | |
| 969 | 973 | fn getObject(r: *Repository, obj: Id) !?[]const u8 { |
| ... | ... | @@ -1030,4 +1034,51 @@ pub const Repository = struct { |
| 1030 | 1034 | } |
| 1031 | 1035 | return null; |
| 1032 | 1036 | } |
| 1037 | |
| 1038 | pub fn getTree(r: *Repository, arena: std.mem.Allocator, id: TreeId) !?struct { TreeId, Tree } { |
| 1039 | if (r.trees.getPtr(id.id)) |val| { |
| 1040 | return .{ id, val.* }; |
| 1041 | } |
| 1042 | if (try r.getGitObject(id.id, arena)) |obj| { |
| 1043 | if (obj.type == .tree) { |
| 1044 | var children = std.ArrayList(Tree.Object).init(r.gpa); |
| 1045 | errdefer children.deinit(); |
| 1046 | var i: usize = 0; |
| 1047 | while (i < obj.content.len) { |
| 1048 | const mode_end = std.mem.indexOfScalar(u8, obj.content[i..], ' ').?; |
| 1049 | const mode = obj.content[i..][0..mode_end]; |
| 1050 | i += mode_end + 1; |
| 1051 | |
| 1052 | const name_end = std.mem.indexOfScalar(u8, obj.content[i..], 0).?; |
| 1053 | const name = obj.content[i..][0..name_end :0]; |
| 1054 | i += name_end + 1; |
| 1055 | |
| 1056 | const oid_raw = obj.content[i..][0..20].*; |
| 1057 | const oid_hex = (try arena.alloc(u8, 40))[0..40]; |
| 1058 | oid_hex.* = extras.to_hex(oid_raw); |
| 1059 | i += 20; |
| 1060 | |
| 1061 | var mode_buf: [6]u8 = @splat('0'); |
| 1062 | @memcpy(mode_buf[6 - mode.len ..], mode); |
| 1063 | const mode_real = try parseTreeMode(&mode_buf); |
| 1064 | |
| 1065 | try children.append(.{ |
| 1066 | .mode = mode_real, |
| 1067 | .name = name, |
| 1068 | .id = switch (mode_real.type) { |
| 1069 | .file => .{ .blob = .{ .id = oid_hex } }, |
| 1070 | .directory => .{ .tree = .{ .id = oid_hex } }, |
| 1071 | .submodule => .{ .commit = .{ .id = oid_hex } }, |
| 1072 | .symlink => .{ .blob = .{ .id = oid_hex } }, |
| 1073 | .none => unreachable, |
| 1074 | }, |
| 1075 | }); |
| 1076 | } |
| 1077 | const tree: Tree = .{ .children = try children.toOwnedSlice() }; |
| 1078 | try r.trees.put(r.gpa, id.id, tree); |
| 1079 | return .{ id, tree }; |
| 1080 | } |
| 1081 | } |
| 1082 | return null; |
| 1083 | } |
| 1033 | 1084 | }; |