| ... | @@ -770,64 +770,6 @@ pub const TreeDiff = struct { | ... | @@ -770,64 +770,6 @@ pub const TreeDiff = struct { |
| 770 | }; | 770 | }; |
| 771 | }; | 771 | }; |
| 772 | | 772 | |
| 773 | pub fn getBranches(alloc: std.mem.Allocator, dir: nfs.Dir) ![]Ref { | | |
| 774 | const t = tracer.trace(@src(), "", .{}); | | |
| 775 | defer t.end(); | | |
| 776 | | | |
| 777 | const result = try std.process.Child.run(.{ | | |
| 778 | .allocator = alloc, | | |
| 779 | .cwd_dir = dir.to_std(), | | |
| 780 | .argv = &.{ "git", "show-ref", "--heads" }, | | |
| 781 | .max_output_bytes = 1024 * 1024 * 1024, | | |
| 782 | }); | | |
| 783 | std.debug.assert(result.term == .Exited and result.term.Exited == 0); | | |
| 784 | const output = std.mem.trimRight(u8, result.stdout, "\n"); | | |
| 785 | var iter = std.mem.splitScalar(u8, output, '\n'); | | |
| 786 | var list = std.ArrayList(Ref).init(alloc); | | |
| 787 | errdefer list.deinit(); | | |
| 788 | while (iter.next()) |line| { | | |
| 789 | var jter = std.mem.splitScalar(u8, line, ' '); | | |
| 790 | try list.append(Ref{ | | |
| 791 | .oid = ensureObjId(CommitId, jter.next().?).id, | | |
| 792 | .label = extras.trimPrefixEnsure(jter.rest(), "refs/heads/").?, | | |
| 793 | }); | | |
| 794 | } | | |
| 795 | return list.toOwnedSlice(); | | |
| 796 | } | | |
| 797 | | | |
| 798 | pub fn getTags(alloc: std.mem.Allocator, dir: nfs.Dir) ![]Ref { | | |
| 799 | const t = tracer.trace(@src(), "", .{}); | | |
| 800 | defer t.end(); | | |
| 801 | | | |
| 802 | // 97bc4b5f87656a34139e1a8122866c8c5b432598 refs/tags/1.2.5 | | |
| 803 | // a450a23e318c5a8fcba5a52c8fdc2e23584650b3 refs/tags/1.2.5^{} | | |
| 804 | // 71264720050572b7bad24532ff39951f47d9296a refs/tags/15.3.1 | | |
| 805 | // 7dfd3948a9095f0253bfba60fed52895ffbf84bb refs/tags/15.3.2 | | |
| 806 | const result = try std.process.Child.run(.{ | | |
| 807 | .allocator = alloc, | | |
| 808 | .cwd_dir = dir.to_std(), | | |
| 809 | .argv = &.{ "git", "show-ref", "--tags" }, | | |
| 810 | .max_output_bytes = 1024 * 1024 * 1024, | | |
| 811 | }); | | |
| 812 | if (result.term == .Exited and result.term.Exited == 1) return &.{}; // show-ref exits 1 when there are no tags | | |
| 813 | std.debug.assert(result.term == .Exited and result.term.Exited == 0); | | |
| 814 | const output = std.mem.trimRight(u8, result.stdout, "\n"); | | |
| 815 | var iter = std.mem.splitScalar(u8, output, '\n'); | | |
| 816 | var list = std.ArrayList(Ref).init(alloc); | | |
| 817 | errdefer list.deinit(); | | |
| 818 | while (iter.next()) |line| { | | |
| 819 | var jter = std.mem.splitScalar(u8, line, ' '); | | |
| 820 | const id = ensureObjId(CommitId, jter.next().?).id; | | |
| 821 | const label = extras.trimPrefixEnsure(jter.rest(), "refs/tags/").?; | | |
| 822 | | | |
| 823 | try list.append(Ref{ | | |
| 824 | .oid = id, | | |
| 825 | .label = label, | | |
| 826 | }); | | |
| 827 | } | | |
| 828 | return list.toOwnedSlice(); | | |
| 829 | } | | |
| 830 | | | |
| 831 | pub const Ref = struct { | 773 | pub const Ref = struct { |
| 832 | oid: Id, | 774 | oid: Id, |
| 833 | label: string, | 775 | label: string, |
| ... | @@ -1248,4 +1190,56 @@ pub const Repository = struct { | ... | @@ -1248,4 +1190,56 @@ pub const Repository = struct { |
| 1248 | } | 1190 | } |
| 1249 | return null; | 1191 | return null; |
| 1250 | } | 1192 | } |
| | 1193 | |
| | 1194 | pub fn getHeads(r: *Repository, arena: std.mem.Allocator) ![]Ref { |
| | 1195 | return r.getRefs(arena, "heads"); |
| | 1196 | } |
| | 1197 | |
| | 1198 | pub fn getTags(r: *Repository, arena: std.mem.Allocator) ![]Ref { |
| | 1199 | return r.getRefs(arena, "tags"); |
| | 1200 | } |
| | 1201 | |
| | 1202 | pub fn getRefs(r: *Repository, arena: std.mem.Allocator, comptime kind: [:0]const u8) ![]Ref { |
| | 1203 | var map: std.StringArrayHashMapUnmanaged(Id) = .empty; |
| | 1204 | try r.addPackedRefs(&map, arena, kind); |
| | 1205 | try r.addDirRefs(&map, arena, kind); |
| | 1206 | var list: std.ArrayListUnmanaged(Ref) = .empty; |
| | 1207 | try list.ensureUnusedCapacity(arena, map.count()); |
| | 1208 | for (map.keys(), map.values()) |label, oid| list.appendAssumeCapacity(.{ .oid = oid, .label = label }); |
| | 1209 | return list.items; |
| | 1210 | } |
| | 1211 | |
| | 1212 | fn addPackedRefs(r: *Repository, map: *std.StringArrayHashMapUnmanaged(Id), arena: std.mem.Allocator, comptime kind: [:0]const u8) !void { |
| | 1213 | var file = try r.gitdir.openFile("packed-refs", .{}); |
| | 1214 | defer file.close(); |
| | 1215 | const content = try file.mmap(); |
| | 1216 | defer nfs.munmap(content); |
| | 1217 | var iter = std.mem.splitScalar(u8, content, '\n'); |
| | 1218 | while (iter.next()) |line| { |
| | 1219 | if (line.len == 0) break; |
| | 1220 | if (line[0] == '^') continue; |
| | 1221 | if (line[0] == '#') continue; |
| | 1222 | std.debug.assert(extras.matchesAll(u8, line[0..40], std.ascii.isHex)); |
| | 1223 | std.debug.assert(line[40] == ' '); |
| | 1224 | const rest = extras.trimPrefixEnsure(line[41..], "refs/" ++ kind ++ "/") orelse continue; |
| | 1225 | const oid = try arena.dupe(u8, line[0..40]); |
| | 1226 | const label = try arena.dupeZ(u8, rest); |
| | 1227 | try map.put(arena, label, oid[0..40]); |
| | 1228 | } |
| | 1229 | } |
| | 1230 | |
| | 1231 | fn addDirRefs(r: *Repository, map: *std.StringArrayHashMapUnmanaged(Id), arena: std.mem.Allocator, comptime kind: [:0]const u8) !void { |
| | 1232 | var dir = try r.gitdir.openDir("refs/" ++ kind, .{}); |
| | 1233 | defer dir.close(); |
| | 1234 | var walker = try dir.walk(arena); |
| | 1235 | defer walker.deinit(); |
| | 1236 | while (try walker.next()) |entry| { |
| | 1237 | if (entry.type != .REG) continue; |
| | 1238 | var file = try dir.openFile(entry.path, .{}); |
| | 1239 | defer file.close(); |
| | 1240 | const label = try arena.dupeZ(u8, entry.path); |
| | 1241 | const oid = try file.readAlloc(arena, 40); |
| | 1242 | try map.put(arena, label, oid[0..40]); |
| | 1243 | } |
| | 1244 | } |
| 1251 | }; | 1245 | }; |