| ... | ... | @@ -9,6 +9,7 @@ pub const Id = *const [40]u8; |
| 9 | 9 | pub const TreeId = struct { id: Id }; |
| 10 | 10 | pub const CommitId = struct { id: Id }; |
| 11 | 11 | pub const BlobId = struct { id: Id }; |
| 12 | pub const TagId = struct { id: Id }; |
| 12 | 13 | |
| 13 | 14 | pub fn version(alloc: std.mem.Allocator) !string { |
| 14 | 15 | const result = try std.ChildProcess.exec(.{ |
| ... | ... | @@ -101,6 +102,20 @@ pub fn isType(alloc: std.mem.Allocator, dir: std.fs.Dir, maybeobj: Id, typ: Tree |
| 101 | 102 | return std.meta.stringToEnum(Tree.Object.Id.Tag, output).? == typ; |
| 102 | 103 | } |
| 103 | 104 | |
| 105 | // TODO make this inspect .git manually |
| 106 | // https://git-scm.com/book/en/v2/Git-Internals-Git-Objects |
| 107 | // https://git-scm.com/book/en/v2/Git-Internals-Packfiles |
| 108 | pub fn getType(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !Tree.Object.Id.Tag { |
| 109 | const result = try std.ChildProcess.exec(.{ |
| 110 | .allocator = alloc, |
| 111 | .cwd_dir = dir, |
| 112 | .argv = &.{ "git", "cat-file", "-t", obj }, |
| 113 | }); |
| 114 | std.debug.assert(result.term == .Exited and result.term.Exited == 0); |
| 115 | const output = std.mem.trimRight(u8, result.stdout, "\n"); |
| 116 | return std.meta.stringToEnum(Tree.Object.Id.Tag, output) orelse @panic(output); |
| 117 | } |
| 118 | |
| 104 | 119 | // TODO make this inspect .git/objects manually |
| 105 | 120 | // TODO make this return a Reader when we implement it ourselves |
| 106 | 121 | // TODO make a version of this that accepts an array of sub_paths and searches all of them at once, so as to not lose spot in history when searching for many old paths |
| ... | ... | @@ -247,6 +262,7 @@ pub const Tree = struct { |
| 247 | 262 | blob: BlobId, |
| 248 | 263 | tree: TreeId, |
| 249 | 264 | commit: CommitId, |
| 265 | tag: TagId, |
| 250 | 266 | |
| 251 | 267 | pub const Tag = std.meta.Tag(@This()); |
| 252 | 268 | |
| ... | ... | @@ -578,15 +594,66 @@ pub fn getBranches(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref { |
| 578 | 594 | errdefer list.deinit(); |
| 579 | 595 | while (iter.next()) |line| { |
| 580 | 596 | var jter = std.mem.split(u8, line, " "); |
| 581 | | try list.append(.{ |
| 597 | try list.append(Ref{ |
| 582 | 598 | .commit = ensureObjId(CommitId, jter.next().?), |
| 583 | 599 | .label = extras.trimPrefixEnsure(jter.rest(), "refs/heads/").?, |
| 600 | .tag = null, |
| 584 | 601 | }); |
| 585 | 602 | } |
| 586 | 603 | return list.toOwnedSlice(); |
| 587 | 604 | } |
| 588 | 605 | |
| 606 | pub fn getTags(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref { |
| 607 | const result = try std.ChildProcess.exec(.{ |
| 608 | .allocator = alloc, |
| 609 | .cwd_dir = dir, |
| 610 | .argv = &.{ "git", "show-ref", "--tags", "--dereference" }, |
| 611 | .max_output_bytes = 1024 * 1024 * 1024, |
| 612 | }); |
| 613 | std.debug.assert(result.term == .Exited and result.term.Exited == 0); |
| 614 | const output = std.mem.trimRight(u8, result.stdout, "\n"); |
| 615 | var iter = std.mem.split(u8, output, "\n"); |
| 616 | var list = std.ArrayList(Ref).init(alloc); |
| 617 | errdefer list.deinit(); |
| 618 | while (iter.next()) |line| { |
| 619 | var jter = std.mem.split(u8, line, " "); |
| 620 | const id = ensureObjId(CommitId, jter.next().?).id; |
| 621 | const label = extras.trimPrefixEnsure(jter.rest(), "refs/tags/").?; |
| 622 | extras.assertLog(!std.mem.endsWith(u8, label, "^{}"), label); |
| 623 | |
| 624 | switch (try getType(alloc, dir, id)) { |
| 625 | .tree => continue, |
| 626 | .blob => unreachable, |
| 627 | .commit => { |
| 628 | try list.append(Ref{ |
| 629 | .label = label, |
| 630 | .commit = ensureObjId(CommitId, id), |
| 631 | .tag = null, |
| 632 | }); |
| 633 | }, |
| 634 | .tag => { |
| 635 | const derefline = iter.next().?; |
| 636 | var kter = std.mem.split(u8, derefline, " "); |
| 637 | const id2 = ensureObjId(CommitId, kter.next().?).id; |
| 638 | const label2 = extras.trimPrefixEnsure(kter.rest(), "refs/tags/").?; |
| 639 | extras.assertLog(std.mem.endsWith(u8, label2, "^{}"), label2); |
| 640 | std.debug.assert(std.mem.eql(u8, label, extras.trimSuffixEnsure(label2, "^{}").?)); |
| 641 | // extras.assertLog(try isType(alloc, dir, id2, .commit), id2); // linux kernel has a single tag that points at a tree |
| 642 | if (!(try isType(alloc, dir, id2, .commit)).?) continue; |
| 643 | |
| 644 | try list.append(Ref{ |
| 645 | .label = label, |
| 646 | .commit = ensureObjId(CommitId, id2), |
| 647 | .tag = ensureObjId(TagId, id), |
| 648 | }); |
| 649 | }, |
| 650 | } |
| 651 | } |
| 652 | return list.toOwnedSlice(); |
| 653 | } |
| 654 | |
| 589 | 655 | pub const Ref = struct { |
| 590 | 656 | label: string, |
| 591 | 657 | commit: CommitId, |
| 658 | tag: ?TagId, |
| 592 | 659 | }; |