| ... | ... | @@ -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 | 773 | pub const Ref = struct { |
| 832 | 774 | oid: Id, |
| 833 | 775 | label: string, |
| ... | ... | @@ -1248,4 +1190,56 @@ pub const Repository = struct { |
| 1248 | 1190 | } |
| 1249 | 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 | }; |