| ... | @@ -9,6 +9,7 @@ pub const Id = *const [40]u8; | ... | @@ -9,6 +9,7 @@ pub const Id = *const [40]u8; |
| 9 | pub const TreeId = struct { id: Id }; | 9 | pub const TreeId = struct { id: Id }; |
| 10 | pub const CommitId = struct { id: Id }; | 10 | pub const CommitId = struct { id: Id }; |
| 11 | pub const BlobId = struct { id: Id }; | 11 | pub const BlobId = struct { id: Id }; |
| | 12 | pub const TagId = struct { id: Id }; |
| 12 | | 13 | |
| 13 | pub fn version(alloc: std.mem.Allocator) !string { | 14 | pub fn version(alloc: std.mem.Allocator) !string { |
| 14 | const result = try std.ChildProcess.exec(.{ | 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,6 +102,20 @@ pub fn isType(alloc: std.mem.Allocator, dir: std.fs.Dir, maybeobj: Id, typ: Tree |
| 101 | return std.meta.stringToEnum(Tree.Object.Id.Tag, output).? == typ; | 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 | // TODO make this inspect .git/objects manually | 119 | // TODO make this inspect .git/objects manually |
| 105 | // TODO make this return a Reader when we implement it ourselves | 120 | // TODO make this return a Reader when we implement it ourselves |
| 106 | // 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 | 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,6 +262,7 @@ pub const Tree = struct { |
| 247 | blob: BlobId, | 262 | blob: BlobId, |
| 248 | tree: TreeId, | 263 | tree: TreeId, |
| 249 | commit: CommitId, | 264 | commit: CommitId, |
| | 265 | tag: TagId, |
| 250 | | 266 | |
| 251 | pub const Tag = std.meta.Tag(@This()); | 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,15 +594,66 @@ pub fn getBranches(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref { |
| 578 | errdefer list.deinit(); | 594 | errdefer list.deinit(); |
| 579 | while (iter.next()) |line| { | 595 | while (iter.next()) |line| { |
| 580 | var jter = std.mem.split(u8, line, " "); | 596 | var jter = std.mem.split(u8, line, " "); |
| 581 | try list.append(.{ | 597 | try list.append(Ref{ |
| 582 | .commit = ensureObjId(CommitId, jter.next().?), | 598 | .commit = ensureObjId(CommitId, jter.next().?), |
| 583 | .label = extras.trimPrefixEnsure(jter.rest(), "refs/heads/").?, | 599 | .label = extras.trimPrefixEnsure(jter.rest(), "refs/heads/").?, |
| | 600 | .tag = null, |
| 584 | }); | 601 | }); |
| 585 | } | 602 | } |
| 586 | return list.toOwnedSlice(); | 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 | pub const Ref = struct { | 655 | pub const Ref = struct { |
| 590 | label: string, | 656 | label: string, |
| 591 | commit: CommitId, | 657 | commit: CommitId, |
| | 658 | tag: ?TagId, |
| 592 | }; | 659 | }; |