about summary refs log tree commit diff
path: root/src/fs.zig
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2025-07-25 19:20:52 +0200
committerRobert Günzler <r@gnzler.io>2025-07-25 19:31:19 +0200
commit69ea02e682fa63910cc8316e8b55a3aa60643e83 (patch)
tree431781a1c94c0cd44205b74da8f96bcf63620bbb /src/fs.zig
parentc36b9cb651dccec5defc0826b3c43e864fd00ddf (diff)
downloadsite-69ea02e682fa63910cc8316e8b55a3aa60643e83.tar.gz
refactor gen binary
- make indexer also pick up markdown files
- prepare for hosting more markdown functionality

Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'src/fs.zig')
-rw-r--r--src/fs.zig116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/fs.zig b/src/fs.zig
new file mode 100644
index 0000000..c009afd
--- /dev/null
+++ b/src/fs.zig
@@ -0,0 +1,116 @@
+const std = @import("std");
+const c = @cImport({
+    @cInclude("time.h");
+});
+
+pub const FileSwapper = struct {
+    allocator: std.mem.Allocator,
+    target_path: []const u8,
+    tmp_path: []const u8,
+    tmp: std.fs.File,
+
+    pub fn createAt(alloc: std.mem.Allocator, path: []const u8) !FileSwapper {
+        const target_dir = std.fs.path.dirname(path) orelse ".";
+        const target_name = std.fs.path.basename(path);
+
+        const tmp_name = try std.fmt.allocPrint(
+            alloc,
+            ".{s}",
+            .{target_name},
+        );
+        defer alloc.free(tmp_name);
+
+        const tmp_path = try std.fs.path.join(
+            alloc,
+            &.{ target_dir, tmp_name },
+        );
+
+        const f = try std.fs.cwd().createFile(tmp_path, .{});
+
+        return .{
+            .allocator = alloc,
+            .target_path = path,
+            .tmp_path = tmp_path,
+            .tmp = f,
+        };
+    }
+
+    pub fn writer(self: FileSwapper) std.fs.File.Writer {
+        return self.tmp.writer();
+    }
+
+    pub fn close(self: FileSwapper) void {
+        defer self.allocator.free(self.tmp_path);
+        defer self.tmp.close();
+
+        // flush writes
+        self.tmp.sync() catch
+            @panic("sync tmp file");
+
+        // swap file into final location
+        std.fs.rename(
+            std.fs.cwd(),
+            self.tmp_path,
+            std.fs.cwd(),
+            self.target_path,
+        ) catch
+            @panic("rename tmp file");
+    }
+};
+
+pub fn replace_extension(alloc: std.mem.Allocator, p: []const u8, new: []const u8) ![]const u8 {
+    const dirname = std.fs.path.dirname(p) orelse ".";
+    const basename = try strip_extension(p);
+    return try join_path_and_filename(
+        alloc,
+        &.{dirname},
+        &.{ basename, ".", new },
+    );
+}
+
+// also trims off base paths
+pub fn strip_extension(path: []const u8) ![]const u8 {
+    const ext = std.fs.path.extension(path);
+    const ext_idx = std.mem.indexOfPosLinear(u8, path, 0, ext);
+    std.debug.assert(ext_idx != null);
+    return path[0..ext_idx.?];
+}
+
+pub fn join_path_and_filename(alloc: std.mem.Allocator, paths: []const []const u8, filename_parts: []const []const u8) ![]const u8 {
+    const filename = try std.mem.concat(alloc, u8, filename_parts);
+    defer alloc.free(filename);
+
+    var p = try std.ArrayList([]const u8).initCapacity(alloc, paths.len + 1);
+    defer p.deinit();
+
+    p.appendSliceAssumeCapacity(paths);
+    p.appendAssumeCapacity(filename);
+
+    const paths2 = try p.toOwnedSlice();
+    defer alloc.free(paths2);
+
+    std.debug.assert(paths.len + 1 == paths2.len);
+    return try std.fs.path.join(alloc, paths2);
+}
+
+pub fn get_mtime(alloc: std.mem.Allocator, path: []const u8) ![]const u8 {
+    const attr = try alloc.create(std.os.linux.Stat);
+    defer alloc.destroy(attr);
+
+    const pathZ = try alloc.dupeZ(u8, path);
+    defer alloc.free(pathZ);
+
+    // use stat to get mtime
+    _ = std.os.linux.stat(pathZ, attr);
+
+    // use libc strftime to format time string
+    const mtime = attr.mtime();
+    const mtime_str = try alloc.alloc(u8, 512);
+    const n = c.strftime(
+        mtime_str.ptr,
+        mtime_str.len,
+        "%F",
+        c.localtime(&mtime.sec),
+    );
+    return try alloc.realloc(mtime_str, n);
+}