return result;
}
+fn parseObject(alloc: std.mem.Allocator, objectType: u3, objectData: []const u8) !git.Object {
+ if (objectType == 3) {
+ return .{
+ .data = objectData,
+ .blob = .{
+ .data = objectData[0..@min(objectData.len, 1000)],
+ },
+ };
+ } else if (objectType == 2) {
+ var treeEntries = git.Tree.init(alloc);
+
+ var counter: u64 = 0;
+ while (counter < objectData.len) {
+ const modeLen = std.mem.indexOfScalar(u8, objectData[counter..objectData.len], ' ') orelse break;
+ const mode = objectData[counter .. counter + modeLen];
+ counter += modeLen + 1;
+
+ var nameLen: u64 = 0;
+ while (counter + nameLen < objectData.len and objectData[counter + nameLen] != 0) {
+ nameLen += 1;
+ }
+ const name = objectData[counter .. counter + nameLen];
+ counter += nameLen + 1;
+
+ if (counter + 20 <= objectData.len) {
+ const hash: u160 = std.mem.readVarInt(u160, objectData[counter .. counter + 20], .big);
+ counter += 20;
+
+ treeEntries.append(.{
+ .mode = alloc.dupe(u8, mode),
+ .name = alloc.dupe(u8, name),
+ .hash = hash,
+ });
+ }
+ }
+ return .{
+ .tree = treeEntries,
+ };
+ } else {
+ std.debug.print("type: {}\n{s}\n", .{ objectType, objectData });
+ }
+}
+
const PackFile = struct {
alloc: std.mem.Allocator,
version: i32,
return null;
}
- pub fn getObject(self: @This(), index: u64) !GitObject {
+ pub fn getObject(self: @This(), alloc: std.mem.Allocator, index: u64) !git.Object {
var objectType: u3 = @truncate(self.packBuffer[index] >> 4);
const objectSize = getSize(self.packBuffer[index..self.packBuffer.len], true);
const baseIndex = index - offsetSize.offset;
- const baseObject = try self.getObject(baseIndex);
+ const baseObject = try self.getObject(alloc, baseIndex);
defer self.alloc.free(baseObject.data);
+
const deltaData = try decompress(
self.alloc,
self.packBuffer[index + objectSize.bytelen + offsetSize.bytelen .. self.packBuffer.len],
);
}
- // const objectStart = objectSize.bytelen;
- // objectData = self.packBuffer[objectStart .. objectStart + objectSize];
-
- return .{
- .type = objectType,
- .data = objectData,
- };
+ return try parseObject(alloc, objectType, objectData);
}
};
-pub fn main() !void {
- const packPath = "../microwindows/.git/objects/pack/pack-a2e25318e6fc668e1264fdaa11fb7223d5627143.pack";
- const idxPath = "../microwindows/.git/objects/pack/pack-a2e25318e6fc668e1264fdaa11fb7223d5627143.idx";
+const git = struct {
+ const Blob = struct {
+ data: []u8,
+ };
+ const TreeEntry = struct {
+ mode: []u8,
+ name: []u8,
+ hash: u160,
+ };
+ const Tree = std.ArrayList(TreeEntry);
+ const Commit = struct {
+ author: []u8,
+ message: []u8,
+ parent: u160,
+ Tree: u160,
+ };
+ const Object = struct {
+ usingnamespace union(enum) {
+ blob: Blob,
+ tree: Tree,
+ commit: Commit,
+ };
+ data: []const u8,
+ };
+ const Repo = struct {
+ pub fn init(alloc: std.mem.Allocator, path: []const u8) !@This() {
+ const gitDir = try std.fs.cwd().openDir(path, .{});
+
+ var objects = std.AutoHashMap(u160, Object).init(alloc);
+
+ var iter = gitDir.iterate();
+ while (try iter.next()) |dirEntry| {
+ if (std.mem.endsWith(u8, dirEntry.name, ".idx")) {
+ var packPathBuffer: [128]u8 = undefined;
+ const idxPath = try gitDir.realpathAlloc(alloc, dirEntry.name);
+ const packPath = try std.fmt.bufPrint(
+ &packPathBuffer,
+ "{s}.pack",
+ .{idxPath[0 .. idxPath.len - 4]},
+ );
+
+ const packBuffer = try std.fs.cwd().readFileAlloc(alloc, packPath, 1024 * 1024 * 1024 * 1024);
+ const idxBuffer = try std.fs.cwd().readFileAlloc(alloc, idxPath, 1024 * 1024 * 1024 * 1024);
+ defer alloc.free(packBuffer);
+ defer alloc.free(idxBuffer);
+
+ const pf = try PackFile.init(alloc, packBuffer, idxBuffer);
+ defer pf.deinit();
+
+ for (0..pf.objectNames.items.len) |i| {
+ try objects.put(
+ pf.objectNames.items[i],
+ try pf.getObject(alloc, pf.objectOffsets.items[i]),
+ );
+ }
+ }
+ }
+ return .{
+ .alloc = alloc,
+ .objects = objects,
+ };
+ }
- const packBytes = 35920363;
- const idxBytes = 392036;
+ pub fn deinit(self: *@This()) void {
+ self.objects.deinit();
+ }
+ alloc: std.mem.Allocator,
+ objects: std.AutoHashMap(u160, Object),
+ };
+};
+
+pub fn main() !void {
+ // allocator
var allocator = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = allocator.allocator();
defer {
std.debug.print("{}\n", .{res});
}
- const packBuffer = try std.fs.cwd().readFileAlloc(alloc, packPath, packBytes);
- const idxBuffer = try std.fs.cwd().readFileAlloc(alloc, idxPath, idxBytes);
- defer alloc.free(packBuffer);
- defer alloc.free(idxBuffer);
-
- const print = std.debug.print;
-
- const pf = try PackFile.init(alloc, packBuffer, idxBuffer);
- defer pf.deinit();
-
- print("{} objects\n", .{pf.objectNames.items.len});
+ // open repo
+ var repo = try git.Repo.init(alloc, "../microwindows/.git/");
+ // input
const r = std.io.getStdIn().reader();
var inputBuffer = std.mem.zeroes([1024]u8);
+ // print HEAD
+ // const head = repo.getHead();
+ // const headObject = head.getObject();
+ // std.debug.print("HEAD: {x:0>40}\n", .{headObject.id});
+
+ // main loop
while (true) {
+ // read line
const input = r.readUntilDelimiter(&inputBuffer, '\n') catch continue;
+ // parse object id
const id = std.fmt.parseInt(u160, input, 16) catch continue;
- if (pf.findObjectOffset(id)) |offset| {
- const o = try pf.getObject(offset);
-
- if (o.type == 3) {
- std.debug.print("object data: {s}\n\n", .{o.data[0..@min(o.data.len, 1000)]});
- } else if (o.type == 2) {
- var counter: u64 = 0;
- while (counter < o.data.len) {
- const modeLen = std.mem.indexOfScalar(u8, o.data[counter..o.data.len], ' ') orelse break;
- const mode = o.data[counter .. counter + modeLen];
- counter += modeLen + 1;
-
- var nameLen: u64 = 0;
- while (counter + nameLen < o.data.len and o.data[counter + nameLen] != 0) {
- nameLen += 1;
- }
- const name = o.data[counter .. counter + nameLen];
- counter += nameLen + 1;
-
- if (counter + 20 <= o.data.len) {
- const hash: u160 = std.mem.readVarInt(u160, o.data[counter .. counter + 20], .big);
- counter += 20;
-
- std.debug.print("{s} {s} {x:0>40}\n", .{ mode, name, hash });
+ // print object
+ if (repo.objects.get(id)) |o| {
+ switch (o) {
+ .Blob => |blob| {
+ std.debug.print("blob: {s}\n\n", .{blob.data});
+ },
+ .Tree => |tree| {
+ for (tree.entries) |entry| {
+ std.debug.print("{s} {s} {x:0>40}\n", .{ entry.mode, entry.name, entry.hash });
}
- }
- print("\n", .{});
- } else {
- std.debug.print("type: {}\n{s}\n", .{ o.type, o.data });
+ std.debug.print("\n", .{});
+ },
+ .Commit => |commit| {
+ std.debug.print("commit: {}", .{commit});
+ },
}
}
}
-
- // for (0..pf.objectNames.items.len) |i| {
- // print("object {x:0>40}:\n", .{pf.objectNames.items[i]});
- // const o = try pf.getObject(pf.objectOffsets.items[i]);
- // defer alloc.free(o.data);
-
- // if (o.type == 3) {
- // std.debug.print("object data: {s}\n\n", .{o.data[0..@min(o.data.len, 1000)]});
- // } else if (o.type == 2) {
- // var counter: u64 = 0;
- // while (counter < o.data.len) {
- // const modeLen = std.mem.indexOfScalar(u8, o.data[counter..o.data.len], ' ') orelse break;
- // const mode = o.data[counter .. counter + modeLen];
- // counter += modeLen + 1;
-
- // var nameLen: u64 = 0;
- // while (counter + nameLen < o.data.len and o.data[counter + nameLen] != 0) {
- // nameLen += 1;
- // }
- // const name = o.data[counter .. counter + nameLen];
- // counter += nameLen + 1;
-
- // if (counter + 20 <= o.data.len) {
- // const hash: u160 = std.mem.readVarInt(u160, o.data[counter .. counter + 20], .big);
- // counter += 20;
-
- // std.debug.print("{s} {s} {x:0>40}\n", .{ mode, name, hash });
- // }
- // }
- // print("\n", .{});
- // } else {
- // std.debug.print("type: {}\n", .{o.type});
- // }
-
- // if (o.type == 4) {
- // std.debug.print("type: {}\ndata: {s}\n\n", .{ o.type, o.data });
- // }
- // }
}