From 1523d3f2d63333f95068315f5d38aea069f27514 Mon Sep 17 00:00:00 2001
From: tri <tri@thac.loan>
Date: Sat, 27 Sep 2025 21:16:20 +0700
Subject: [PATCH] get commits

---
 .rgignore    |  1 +
 src/git.zig  | 37 +++++++++++++++++++++++++++++++++++++
 src/main.zig | 30 +++++++++++++++++++-----------
 3 files changed, 57 insertions(+), 11 deletions(-)
 create mode 100644 .rgignore

diff --git a/.rgignore b/.rgignore
new file mode 100644
index 0000000..69ff739
--- /dev/null
+++ b/.rgignore
@@ -0,0 +1 @@
+/demo
diff --git a/src/git.zig b/src/git.zig
index 3f83048..2810936 100644
--- a/src/git.zig
+++ b/src/git.zig
@@ -27,3 +27,40 @@ pub fn updateServerInfo(gpa: mem.Allocator, dir: fs.Dir) !void {
 
     std.debug.assert(proc.term.Exited == 0);
 }
+
+pub const Commit = struct {
+    hash: []const u8,
+    subject: []const u8,
+    date: []const u8,
+};
+
+pub fn getCommits(arena: std.mem.Allocator, dir: fs.Dir) ![]Commit {
+    const proc = try std.process.Child.run(.{
+        .allocator = arena,
+        .cwd_dir = dir,
+        .argv = &.{
+            "git",
+            "log",
+            "-z", // NUL byte is a safer delimiter than \n
+            "--pretty=format:%H\n%ai\n%s",
+        },
+        // 512 MiB should be enough for everyone (tm)
+        .max_output_bytes = 1024 * 1024 * 512,
+    });
+
+    var commits: std.ArrayList(Commit) = try .initCapacity(arena, 128);
+
+    var commit_texts = std.mem.splitSequence(u8, proc.stdout, "\x00");
+    while (commit_texts.next()) |commit_text| {
+        if (commit_text.len == 0) {
+            continue;
+        }
+        var fields_iter = std.mem.splitSequence(u8, commit_text, "\n");
+        try commits.append(arena, Commit{
+            .hash = fields_iter.next().?,
+            .date = fields_iter.next().?,
+            .subject = fields_iter.next().?,
+        });
+    }
+    return commits.items;
+}
diff --git a/src/main.zig b/src/main.zig
index 01fac8a..8374976 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -10,6 +10,7 @@ pub fn main() !u8 {
     }
 
     var dba_impl: std.heap.DebugAllocator(.{}) = .init;
+    defer _ = dba_impl.deinit();
     const dba = dba_impl.allocator();
 
     const target_dir_path = std.os.argv[1];
@@ -18,30 +19,37 @@ pub fn main() !u8 {
     var target_dir = try fs.cwd().openDirZ(target_dir_path, .{ .iterate = true });
     defer target_dir.close();
 
+    var repo_arena_impl: std.heap.ArenaAllocator = .init(dba);
+    defer repo_arena_impl.deinit();
+    const repo_arena = repo_arena_impl.allocator();
+
     var dir_iter = target_dir.iterate();
     while (try dir_iter.next()) |entry| {
+        defer _ = repo_arena_impl.reset(.retain_capacity);
+
         if (entry.kind != .directory) {
             continue;
         }
 
-        var subdir = try target_dir.openDir(entry.name, .{});
-        defer subdir.close();
+        var repo_dir = try target_dir.openDir(entry.name, .{});
+        defer repo_dir.close();
 
-        if (!try git.isGitDir(dba, subdir)) {
+        if (!try git.isGitDir(repo_arena, repo_dir)) {
             continue;
         }
 
         // update-server-info generates the necessary files to make our static
         // dir cloneable: https://git-scm.com/docs/git-update-server-info
-        try git.updateServerInfo(dba, subdir);
+        try git.updateServerInfo(repo_arena, repo_dir);
+
+        const commits = try git.getCommits(repo_arena, repo_dir);
+        for (commits) |commit| {
+            println(
+                ">> commit: {s} / {s} / {s}",
+                .{ commit.date, commit.hash, commit.subject },
+            );
+        }
     }
 
-    // Deinit goes here.
-    // It's technically not necessary because the process is ending anyway,
-    // but it lets us know if there's been any memory leak.
-    if (dba_impl.deinit() == .leak) {
-        println(">> memory leak detected", .{});
-        return 1;
-    }
     return 0;
 }
-- 
2.47.3

