about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2025-10-17 22:51:16 +0200
committerRobert Günzler <r@gnzler.io>2025-10-18 00:01:46 +0200
commit973e5fdb82e0037ba5fc2ff74cf40d32a0e3466b (patch)
tree62ec670e836b1e69081c9889fffab4b551de6528
parent55efe8b67b850b34c1483ab3be0947d80508a893 (diff)
downloadsite-973e5fdb82e0037ba5fc2ff74cf40d32a0e3466b.tar.gz
get mtime from git
but fallback to mtime anyway

Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to '')
-rw-r--r--src/exe.zig4
-rw-r--r--src/fs.zig29
-rw-r--r--src/gen.zig4
3 files changed, 31 insertions, 6 deletions
diff --git a/src/exe.zig b/src/exe.zig
index e0cb7ef..ae5cfdd 100644
--- a/src/exe.zig
+++ b/src/exe.zig
@@ -37,8 +37,8 @@ fn pandocWorker(ctx: *Context, page: []const u8) !void {
     defer ctx.allocator().free(target_path);
 
     // get mtime of the source document
-    const mtime = try fs.getMtime(source_path);
-    const mtime_str = try fs.formatMtime(ctx.allocator(), mtime, "%s");
+    const mtime = try (fs.getGitTime(source_path) catch fs.getMtime(source_path));
+    const mtime_str = try fs.formatTimespec(ctx.allocator(), mtime, "%s");
     defer ctx.allocator().free(mtime_str);
 
     const f = try fs.FileSwapper.createAt(ctx.allocator(), target_path);
diff --git a/src/fs.zig b/src/fs.zig
index 53acc07..045db89 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -1,7 +1,9 @@
 const std = @import("std");
 const c = @cImport({
+    @cInclude("stdlib.h");
     @cInclude("time.h");
 });
+const exe = @import("exe.zig");
 
 const log = std.log.scoped(.fs);
 
@@ -141,6 +143,29 @@ pub fn joinPathAndFilename(alloc: std.mem.Allocator, paths: []const []const u8,
     return try std.fs.path.join(alloc, paths2);
 }
 
+pub fn getGitTime(path: []const u8) !std.posix.timespec {
+    var buf = std.mem.zeroes([12]u8);
+
+    var p = std.process.Child.init(
+        &.{ "git", "log", "-1", "--pretty=format:%at", "-z", "--", path },
+        std.heap.page_allocator,
+    );
+    p.stdout_behavior = .Pipe;
+    try p.spawn();
+    _ = try p.stdout.?.readAll(&buf);
+    const result = try p.wait();
+    std.debug.assert(result == .Exited and result.Exited == 0);
+
+    // parse result as ulong
+    const gitAuthorDate: c_ulong = c.strtoul(&buf, null, 10);
+
+    // calculate timespec
+    return .{
+        .sec = std.math.cast(isize, gitAuthorDate) orelse std.math.maxInt(isize),
+        .nsec = 0,
+    };
+}
+
 pub fn getMtime(path: []const u8) !std.posix.timespec {
     const fd = try std.fs.cwd().openFile(path, .{ .mode = .read_only });
     defer fd.close();
@@ -155,10 +180,10 @@ pub fn getMtime(path: []const u8) !std.posix.timespec {
 }
 
 // use libc strftime to format time string
-pub fn formatMtime(alloc: std.mem.Allocator, mtime: std.posix.timespec, fmt: [*c]const u8) ![]const u8 {
+pub fn formatTimespec(alloc: std.mem.Allocator, timespec: std.posix.timespec, fmt: [*c]const u8) ![]const u8 {
     const mtime_str = try alloc.alloc(u8, std.os.linux.PATH_MAX);
     var tm: c.struct_tm = undefined;
-    _ = c.localtime_r(&mtime.sec, &tm);
+    _ = c.localtime_r(&timespec.sec, &tm);
     const rc = c.strftime(
         mtime_str.ptr,
         mtime_str.len,
diff --git a/src/gen.zig b/src/gen.zig
index 96c31a3..3e5fa9b 100644
--- a/src/gen.zig
+++ b/src/gen.zig
@@ -111,8 +111,8 @@ fn genSite(ctx: *Context) !void {
 
 // build a single html file
 fn build(allocator: std.mem.Allocator, w: std.io.AnyWriter, page_name: []const u8, srcpath: []const u8) !void {
-    const mtime = try fs.getMtime(srcpath);
-    const mtime_str = try fs.formatMtime(allocator, mtime, "%F");
+    const mtime = try (fs.getGitTime(srcpath) catch fs.getMtime(srcpath));
+    const mtime_str = try fs.formatTimespec(allocator, mtime, "%F");
     defer allocator.free(mtime_str);
 
     // HEAD