authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-18 22:07:27 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2023-05-18 22:07:27 -07:00
log5df10192f349aabc63abcae624cac9de205d9df6
tree59bf864144d29956bab5a013f9c791672bb86c3f
parent02b234d0a75d4c93ddcbe62d010e4445c0e94fc9

add getTags()


1 files changed, 68 insertions(+), 1 deletions(-)

git.zig+68-1
...@@ -9,6 +9,7 @@ pub const Id = *const [40]u8;...@@ -9,6 +9,7 @@ pub const Id = *const [40]u8;
9pub const TreeId = struct { id: Id };9pub const TreeId = struct { id: Id };
10pub const CommitId = struct { id: Id };10pub const CommitId = struct { id: Id };
11pub const BlobId = struct { id: Id };11pub const BlobId = struct { id: Id };
12pub const TagId = struct { id: Id };
1213
13pub fn version(alloc: std.mem.Allocator) !string {14pub 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}
103104
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
108pub 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 manually119// TODO make this inspect .git/objects manually
105// TODO make this return a Reader when we implement it ourselves120// 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 paths121// 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,
250266
251 pub const Tag = std.meta.Tag(@This());267 pub const Tag = std.meta.Tag(@This());
252268
...@@ -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}
588605
606pub 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
589pub const Ref = struct {655pub const Ref = struct {
590 label: string,656 label: string,
591 commit: CommitId,657 commit: CommitId,
658 tag: ?TagId,
592};659};