| ... | ... | @@ -1318,6 +1318,66 @@ pub const Repository = struct { |
| 1318 | 1318 | try map.put(arena, label, oid[0..40]); |
| 1319 | 1319 | } |
| 1320 | 1320 | } |
| 1321 | |
| 1322 | pub fn getTreeCommits(r: *Repository, arena: std.mem.Allocator, base_oid: CommitId, dir_path: []const u8) ![]const CommitId { |
| 1323 | const t = tracer.trace(@src(), "", .{}); |
| 1324 | defer t.end(); |
| 1325 | |
| 1326 | const base_idx = try r.getCommitA(arena, base_oid.id); |
| 1327 | const base = base_idx.reify(r); |
| 1328 | const base_tree = try traverseTo(r, arena, base.tree, dir_path); |
| 1329 | const total = base_tree.children.len; |
| 1330 | |
| 1331 | var found: usize = 0; |
| 1332 | var result: std.StringArrayHashMapUnmanaged(CommitId) = .empty; |
| 1333 | defer result.deinit(r.gpa); |
| 1334 | for (base_tree.children) |item| try result.put(r.gpa, item.name, undefined); |
| 1335 | |
| 1336 | var set: std.bit_set.DynamicBitSetUnmanaged = try .initEmpty(r.gpa, total); |
| 1337 | defer set.deinit(r.gpa); |
| 1338 | |
| 1339 | var searched: usize = 0; |
| 1340 | var commit_id_prev = base_oid; |
| 1341 | var commit_id = base_oid; |
| 1342 | var commit_idx = base_idx; |
| 1343 | var commit = base; |
| 1344 | while (true) { |
| 1345 | if (commit.parents.len == 0) break; |
| 1346 | commit_id, commit_idx = (try r.getCommit(arena, commit.parents[0])).?; |
| 1347 | searched += 1; |
| 1348 | defer commit_id_prev = commit_id; |
| 1349 | commit = commit_idx.reify(r); |
| 1350 | const tree = try traverseTo(r, arena, commit.tree, dir_path); |
| 1351 | for (result.keys(), 0..) |k, i| { |
| 1352 | if (set.isSet(i)) continue; |
| 1353 | const original = base_tree.get(k).?; |
| 1354 | const new = tree.get(k); |
| 1355 | if (new == null) { |
| 1356 | found += 1; |
| 1357 | result.putAssumeCapacity(k, commit_id_prev); |
| 1358 | set.set(i); |
| 1359 | // std.log.debug("found [{d}/{d}] object after searching {d} commits", .{ found, total, searched }); |
| 1360 | continue; |
| 1361 | } |
| 1362 | if (!std.mem.eql(u8, new.?.id.erase(), original.id.erase())) { |
| 1363 | found += 1; |
| 1364 | result.putAssumeCapacity(k, commit_id_prev); |
| 1365 | set.set(i); |
| 1366 | // std.log.debug("found [{d}/{d}] object after searching {d} commits", .{ found, total, searched }); |
| 1367 | continue; |
| 1368 | } |
| 1369 | } |
| 1370 | if (set.count() == total) { |
| 1371 | break; |
| 1372 | } |
| 1373 | } |
| 1374 | for (0..total, result.values()) |i, *v| { |
| 1375 | if (!set.isSet(i)) { |
| 1376 | v.* = base_oid; |
| 1377 | } |
| 1378 | } |
| 1379 | return try arena.dupe(CommitId, result.values()); |
| 1380 | } |
| 1321 | 1381 | }; |
| 1322 | 1382 | |
| 1323 | 1383 | const z = @cImport({ |
| ... | ... | @@ -1372,3 +1432,14 @@ const ZlibCode = enum(c_int) { |
| 1372 | 1432 | Z_BUF_ERROR = -5, |
| 1373 | 1433 | Z_VERSION_ERROR = -6, |
| 1374 | 1434 | }; |
| 1435 | |
| 1436 | fn traverseTo(r: *Repository, arena: std.mem.Allocator, treestart_id: TreeId, dir_path: []const u8) !Tree { |
| 1437 | var tree = try r.getTreeA(arena, treestart_id.id); |
| 1438 | if (dir_path.len == 0) return tree; |
| 1439 | var iter = std.mem.splitScalar(u8, dir_path, '/'); |
| 1440 | while (iter.next()) |segment| { |
| 1441 | const o = tree.get(segment).?; |
| 1442 | tree = try r.getTreeA(arena, o.id.tree.id); |
| 1443 | } |
| 1444 | return tree; |
| 1445 | } |