| ... | ... | @@ -124,19 +124,6 @@ pub fn ensureObjId(comptime T: type, input: string) T { |
| 124 | 124 | return .{ .id = input[0..40] }; |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | | // TODO make this inspect .git/objects manually |
| 128 | | // 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 |
| 129 | | // https://git-scm.com/book/en/v2/Git-Internals-Git-Objects |
| 130 | | // https://git-scm.com/book/en/v2/Git-Internals-Packfiles |
| 131 | | pub fn revListAll(alloc: std.mem.Allocator, dir: nfs.Dir, from: CommitId, sub_path: string) !string { |
| 132 | | const t = tracer.trace(@src(), " {s} -- {s}", .{ from.id, sub_path }); |
| 133 | | defer t.end(); |
| 134 | | |
| 135 | | const result = try root.child_process.run(alloc, dir, .ignore, .pipe, .pipe, 1024 * 1024 * 10, &.{ "git", "rev-list", from.id, "--", sub_path }); |
| 136 | | std.debug.assert(result.term == .exited and result.term.exited == 0); |
| 137 | | return std.mem.trimEnd(u8, result.stdout, "\n"); |
| 138 | | } |
| 139 | | |
| 140 | 127 | pub fn parseCommit(alloc: std.mem.Allocator, commitfile: string, mailmap: *const std.hash_map.StringHashMapUnmanaged([]const u8), mailmap_names: *const std.hash_map.StringHashMapUnmanaged([]const u8)) !Commit { |
| 141 | 128 | const t = tracer.trace(@src(), "", .{}); |
| 142 | 129 | defer t.end(); |
| ... | ... | @@ -1657,6 +1644,55 @@ pub const Repository = struct { |
| 1657 | 1644 | }; |
| 1658 | 1645 | return diffFileIterator(r, writable, parentid, commitid, S); |
| 1659 | 1646 | } |
| 1647 | |
| 1648 | pub fn revListAll(r: *Repository, alloc: std.mem.Allocator, from: CommitId, sub_path: string) ![]const u8 { |
| 1649 | const t = tracer.trace(@src(), " {s} -- {s}", .{ from.id, sub_path }); |
| 1650 | defer t.end(); |
| 1651 | |
| 1652 | var list: std.ArrayList(u8) = .empty; |
| 1653 | errdefer list.deinit(alloc); |
| 1654 | |
| 1655 | const base = try r.getCommitA(from.id, .no_cache); |
| 1656 | const base_tree = try r.getTreeA(base.tree.id, .no_cache); |
| 1657 | const base_id, const base_id_parent = (try idFor(r, base_tree, sub_path)).?; |
| 1658 | |
| 1659 | var prev_prev_commit: ?*Commit = null; |
| 1660 | var prev_commit = base; |
| 1661 | var prev_tree = base_id_parent; |
| 1662 | var prev_id = try r.gpa.dupe(u8, base_id); |
| 1663 | defer r.gpa.free(prev_id); |
| 1664 | |
| 1665 | while (true) { |
| 1666 | if (prev_commit.parents.len == 0) { |
| 1667 | try list.appendSlice(alloc, prev_prev_commit.?.parents[0].id ++ "\n"); |
| 1668 | break; |
| 1669 | } |
| 1670 | const next_commit = try r.getCommitA(prev_commit.parents[0].id, .no_cache); |
| 1671 | const next_commit_tree = try r.getTreeA(next_commit.tree.id, .no_cache); |
| 1672 | const next_id, const next_tree = try idFor(r, next_commit_tree, sub_path) orelse { |
| 1673 | try list.appendSlice(alloc, prev_prev_commit.?.parents[0].id ++ "\n"); |
| 1674 | break; |
| 1675 | }; |
| 1676 | if (std.mem.eql(u8, next_id, prev_id)) { |
| 1677 | if (prev_prev_commit) |p| p.destroy(r); |
| 1678 | prev_prev_commit = prev_commit; |
| 1679 | prev_commit = next_commit; |
| 1680 | prev_tree = next_tree; |
| 1681 | continue; |
| 1682 | } |
| 1683 | try list.appendSlice(alloc, prev_prev_commit.?.parents[0].id ++ "\n"); |
| 1684 | if (prev_prev_commit) |p| p.destroy(r); |
| 1685 | prev_prev_commit = prev_commit; |
| 1686 | prev_commit = next_commit; |
| 1687 | prev_tree = next_tree; |
| 1688 | |
| 1689 | r.gpa.free(prev_id); |
| 1690 | prev_id = try r.gpa.dupe(u8, next_id); |
| 1691 | continue; |
| 1692 | } |
| 1693 | |
| 1694 | return list.toOwnedSlice(alloc); |
| 1695 | } |
| 1660 | 1696 | }; |
| 1661 | 1697 | |
| 1662 | 1698 | const z = @cImport({ |
| ... | ... | @@ -2112,3 +2148,28 @@ const PathListNode = struct { |
| 2112 | 2148 | try writable.writevAll(&.{ "/", node.data }); |
| 2113 | 2149 | } |
| 2114 | 2150 | }; |
| 2151 | |
| 2152 | /// Consumes 'tree' and returns a new owned 'Tree' in the tuple. |
| 2153 | pub fn idFor(r: *Repository, tree: *Tree, sub_path: []const u8) !?struct { Id, *Tree } { |
| 2154 | const s_idx = std.mem.indexOfScalar(u8, sub_path, '/'); |
| 2155 | const seg = sub_path[0 .. s_idx orelse sub_path.len]; |
| 2156 | const obj = tree.get(seg) orelse { |
| 2157 | tree.destroy(r); |
| 2158 | return null; |
| 2159 | }; |
| 2160 | switch (obj.id) { |
| 2161 | .tree => |id| { |
| 2162 | defer tree.destroy(r); |
| 2163 | if (s_idx == null) return null; |
| 2164 | const new_tree = try r.getTreeA(id.id, .no_cache); |
| 2165 | return idFor(r, new_tree, sub_path[s_idx.? + 1 ..]); |
| 2166 | }, |
| 2167 | else => |id| { |
| 2168 | if (s_idx != null) { |
| 2169 | tree.destroy(r); |
| 2170 | return null; |
| 2171 | } |
| 2172 | return .{ id.erase(), tree }; |
| 2173 | }, |
| 2174 | } |
| 2175 | } |