Writes out a version 2 index for the given packfile, as documented in pack-format.
pub fn indexPack(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
index_writer: *Io.File.Writer,
) !void
pub fn indexPack(
allocator: Allocator,
format: Oid.Format,
pack: *Io.File.Reader,
index_writer: *Io.File.Writer,
) !void {
try pack.seekTo(0);
var index_entries: std.AutoHashMapUnmanaged(Oid, IndexEntry) = .empty;
defer index_entries.deinit(allocator);
var pending_deltas: std.ArrayList(IndexEntry) = .empty;
defer pending_deltas.deinit(allocator);
const pack_checksum = try indexPackFirstPass(allocator, format, pack, &index_entries, &pending_deltas);
var cache: ObjectCache = .{};
defer cache.deinit(allocator);
var remaining_deltas = pending_deltas.items.len;
while (remaining_deltas > 0) {
var i: usize = remaining_deltas;
while (i > 0) {
i -= 1;
const delta = pending_deltas.items[i];
if (try indexPackHashDelta(allocator, format, pack, delta, index_entries, &cache)) |oid| {
try index_entries.put(allocator, oid, delta);
_ = pending_deltas.swapRemove(i);
}
}
if (pending_deltas.items.len == remaining_deltas) return error.IncompletePack;
remaining_deltas = pending_deltas.items.len;
}
var oids: std.ArrayList(Oid) = .empty;
defer oids.deinit(allocator);
try oids.ensureTotalCapacityPrecise(allocator, index_entries.count());
var index_entries_iter = index_entries.iterator();
while (index_entries_iter.next()) |entry| {
oids.appendAssumeCapacity(entry.key_ptr.*);
}
mem.sortUnstable(Oid, oids.items, {}, struct {
fn lessThan(_: void, o1: Oid, o2: Oid) bool {
return mem.lessThan(u8, o1.slice(), o2.slice());
}
}.lessThan);
var fan_out_table: [256]u32 = undefined;
var count: u32 = 0;
var fan_out_index: u8 = 0;
for (oids.items) |oid| {
const key = oid.slice()[0];
if (key > fan_out_index) {
@memset(fan_out_table[fan_out_index..key], count);
fan_out_index = key;
}
count += 1;
}
@memset(fan_out_table[fan_out_index..], count);
var index_hashed_writer = Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{});
const writer = &index_hashed_writer.writer;
try writer.writeAll(IndexHeader.signature);
try writer.writeInt(u32, IndexHeader.supported_version, .big);
for (fan_out_table) |fan_out_entry| {
try writer.writeInt(u32, fan_out_entry, .big);
}
for (oids.items) |oid| {
try writer.writeAll(oid.slice());
}
for (oids.items) |oid| {
try writer.writeInt(u32, index_entries.get(oid).?.crc32, .big);
}
var big_offsets: std.ArrayList(u64) = .empty;
defer big_offsets.deinit(allocator);
for (oids.items) |oid| {
const offset = index_entries.get(oid).?.offset;
if (offset <= std.math.maxInt(u31)) {
try writer.writeInt(u32, @intCast(offset), .big);
} else {
const index = big_offsets.items.len;
try big_offsets.append(allocator, offset);
try writer.writeInt(u32, @as(u32, @intCast(index)) | (1 << 31), .big);
}
}
for (big_offsets.items) |offset| {
try writer.writeInt(u64, offset, .big);
}
try writer.writeAll(pack_checksum.slice());
const index_checksum = index_hashed_writer.hasher.finalResult();
try index_writer.interface.writeAll(index_checksum.slice());
try index_writer.end();
}