about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRobert Günzler <r@gnzler.io>2026-09-24 18:48:35 +0200
committerRobert Günzler <r@gnzler.io>2026-10-02 10:39:48 +0200
commit64371401cb8f608e00c0c0f5460257d74e42166d (patch)
tree178220aafe12f1792a41642c569eedd6fa236832 /src
parent3e2373b2d7fb76803a58d6ebaa795fa88ca3b955 (diff)
downloadsite-64371401cb8f608e00c0c0f5460257d74e42166d.tar.gz
also wrap Io.Dir
Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'src')
-rw-r--r--src/main.zig144
1 files changed, 105 insertions, 39 deletions
diff --git a/src/main.zig b/src/main.zig
index 04d1f41..90a8cb7 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -140,17 +140,17 @@ const Cli = struct {
 
         // TODO: allow setting custom root path via flags
         const root_path = std.fs.path.dirname(source_path) orelse return error.NoDirname;
-        const root_dir = try Io.Dir.cwd().openDir(io, root_path, .{});
-        defer root_dir.close(io);
+        const root_dir = try Dir.init(io, Io.Dir.cwd(), root_path, .{});
+        defer root_dir.fd.close(io);
 
         var source = try File.init(io, root_dir, std.fs.path.basename(source_path), null);
         defer source.close(io);
 
         // open/create destination dir
-        const target_dir = try Io.Dir.cwd().createDirPathOpen(io, target_path, .{});
-        defer target_dir.close(io);
+        const target_dir = try Dir.init(io, Io.Dir.cwd(), target_path, .{});
+        defer target_dir.fd.close(io);
 
-        const b = try Builder.init(gpa, root_dir, source, target_dir);
+        const b = try Builder.init(gpa, root_dir, source, target_dir, .{});
         defer b.deinit(gpa);
         try b.build(io, gpa);
     }
@@ -174,12 +174,12 @@ const Cli = struct {
 
         log.info("gen : target={s} root={s}", .{ target_path, root_path });
 
-        const root_dir = try Io.Dir.cwd().openDir(io, root_path, .{ .iterate = true });
-        defer root_dir.close(io);
+        const root_dir = try Dir.init(io, Io.Dir.cwd(), root_path, .{ .iterate = true });
+        defer root_dir.fd.close(io);
 
         // open/create destination dir
-        const target_dir = try Io.Dir.cwd().createDirPathOpen(io, target_path, .{});
-        defer target_dir.close(io);
+        const target_dir = try Dir.init(io, Io.Dir.cwd(), target_path, .{});
+        defer target_dir.fd.close(io);
 
         var work: std.ArrayList([]const u8) = .empty;
         defer work.deinit(gpa);
@@ -187,7 +187,7 @@ const Cli = struct {
         var mdn = std.BufSet.init(gpa);
         defer mdn.deinit();
 
-        var iter = root_dir.iterate();
+        var iter = root_dir.fd.iterate();
         while (try iter.next(io)) |child| {
             if (child.kind != .file) continue;
 
@@ -240,7 +240,7 @@ const Cli = struct {
                 var source = try File.init(io, root_dir, md_name, null);
                 defer source.close(io);
 
-                const b = try Builder.init(gpa, root_dir, source, target_dir);
+                const b = try Builder.init(gpa, root_dir, source, target_dir, .{});
                 defer b.deinit(gpa);
                 try b.build(io, gpa);
             }
@@ -251,7 +251,7 @@ const Cli = struct {
             var source = try File.init(io, root_dir, path, null);
             defer source.close(io);
 
-            const b = try Builder.init(gpa, root_dir, source, target_dir);
+            const b = try Builder.init(gpa, root_dir, source, target_dir, .{});
             defer b.deinit(gpa);
             try b.build(io, gpa);
 
@@ -284,7 +284,7 @@ const Cli = struct {
     fn genBackrefs(
         io: Io,
         gpa: Allocator,
-        target_dir: Io.Dir,
+        target_dir: Dir,
         target_path: []const u8,
         work: std.ArrayList([]const u8),
         outgoingRefs: std.StringHashMapUnmanaged([][]const u8),
@@ -367,8 +367,8 @@ const Cli = struct {
     fn genIndex(
         io: Io,
         gpa: Allocator,
-        root_dir: Io.Dir,
-        target_dir: Io.Dir,
+        root_dir: Dir,
+        target_dir: Dir,
         index: std.ArrayList([]const u8),
     ) !void {
         log.info("Generating index", .{});
@@ -380,7 +380,7 @@ const Cli = struct {
             };
         defer source.close(io);
 
-        const b = try Builder.init(gpa, root_dir, source, target_dir);
+        const b = try Builder.init(gpa, root_dir, source, target_dir, .{});
         b.index = index;
         defer b.deinit(gpa);
         try b.build(io, gpa);
@@ -407,14 +407,27 @@ const Cli = struct {
     }
 };
 
+const Dir = struct {
+    path: []const u8,
+    fd: Io.Dir,
+
+    fn init(io: Io, dir: Io.Dir, path: []const u8, options: Io.Dir.OpenOptions) !Dir {
+        return .{
+            .path = path,
+            .fd = try dir.openDir(io, path, options),
+        };
+    }
+};
+
 const File = struct {
     path: []const u8,
     fd: Io.File,
+    dir: Dir,
     mmap: Io.File.MemoryMap,
     mtime: Io.Timestamp,
 
-    fn init(io: Io, dir: Io.Dir, path: []const u8, options: ?Io.Dir.OpenFileOptions) !File {
-        const fd = try dir.openFile(io, path, options orelse .{
+    fn init(io: Io, dir: Dir, path: []const u8, options: ?Io.Dir.OpenFileOptions) !File {
+        const fd = try dir.fd.openFile(io, path, options orelse .{
             .lock = .exclusive,
             .mode = .read_write,
         });
@@ -427,6 +440,7 @@ const File = struct {
         return .{
             .path = path,
             .fd = fd,
+            .dir = dir,
             .mmap = mmap,
             .mtime = stat.mtime,
         };
@@ -449,9 +463,9 @@ const File = struct {
 };
 
 const Builder = struct {
-    root_dir: Io.Dir,
+    root_dir: Dir,
     source: File,
-    target_dir: Io.Dir,
+    target_dir: Dir,
     options: Options,
 
     // track files which affect build output (paths relative to root_dir)
@@ -472,13 +486,19 @@ const Builder = struct {
     const DELIM_START: []const u8 = "{[";
     const DELIM_END: []const u8 = "]}";
 
-    fn init(gpa: Allocator, root_dir: Io.Dir, source: File, target_dir: Io.Dir) !*Builder {
+    fn init(
+        gpa: Allocator,
+        root_dir: Dir,
+        source: File,
+        target_dir: Dir,
+        options: Options,
+    ) !*Builder {
         const b = try gpa.create(Builder);
         b.* = .{
             .root_dir = root_dir,
             .source = source,
             .target_dir = target_dir,
-            .options = .{},
+            .options = options,
         };
         return b;
     }
@@ -524,7 +544,7 @@ const Builder = struct {
 
         // atomic?
         errdefer log.err("path={s}", .{target_path});
-        const target_fd = try self.target_dir.createFile(io, target_path, .{
+        const target_fd = try self.target_dir.fd.createFile(io, target_path, .{
             .lock = .exclusive,
         });
         defer target_fd.close(io);
@@ -550,7 +570,11 @@ const Builder = struct {
     }
 
     // finalize computes the digest and attaches it to the target file
-    fn finalize(self: *Builder, gpa: Allocator, target_fd: Io.File) !void {
+    fn finalize(
+        self: *Builder,
+        gpa: Allocator,
+        target_fd: Io.File,
+    ) !void {
         log.debug("{s}: finalizing", .{self.source.path});
 
         const composite_dgst = compositeDigest(self.dgsts.items);
@@ -559,7 +583,13 @@ const Builder = struct {
     }
 
     // inject interprets source and writes to w
-    fn inject(self: *Builder, io: Io, gpa: Allocator, source: File, w: *Io.Writer) !void {
+    fn inject(
+        self: *Builder,
+        io: Io,
+        gpa: Allocator,
+        source: File,
+        w: *Io.Writer,
+    ) !void {
         var iter = std.mem.splitScalar(u8, source.mmap.memory, '\n');
         while (iter.next()) |line| {
             var offset: usize = 0;
@@ -590,7 +620,14 @@ const Builder = struct {
         try self.dgsts.append(gpa, try source.digest());
     }
 
-    fn template(self: *Builder, io: Io, gpa: Allocator, ref_name: []const u8, w: *Io.Writer, track_refs: bool) anyerror!void {
+    fn template(
+        self: *Builder,
+        io: Io,
+        gpa: Allocator,
+        ref_name: []const u8,
+        w: *Io.Writer,
+        track_refs: bool,
+    ) anyerror!void {
         log.debug("{s}: templating ref={s}", .{ self.source.path, ref_name });
 
         // special case for when we're injecting the source into the baseof
@@ -657,7 +694,13 @@ const Builder = struct {
         }
     }
 
-    fn templatePortal(self: *Builder, io: Io, gpa: Allocator, ref_name: []const u8, w: *Io.Writer) !void {
+    fn templatePortal(
+        self: *Builder,
+        io: Io,
+        gpa: Allocator,
+        ref_name: []const u8,
+        w: *Io.Writer,
+    ) !void {
         log.debug("{s}: portaling ref={s}", .{ self.source.path, ref_name });
 
         const ref_path = try std.fmt.allocPrint(gpa, "{s}.htm", .{ref_name});
@@ -671,7 +714,14 @@ const Builder = struct {
         try w.writeByte('\n');
     }
 
-    fn templateRef(self: *Builder, io: Io, gpa: Allocator, ref_str: []const u8, w: *Io.Writer, track_refs: bool) !void {
+    fn templateRef(
+        self: *Builder,
+        io: Io,
+        gpa: Allocator,
+        ref_str: []const u8,
+        w: *Io.Writer,
+        track_refs: bool,
+    ) !void {
         const fragment = std.mem.indexOf(u8, ref_str, "#");
         const ref = if (fragment) |i| ref_str[0..i] else ref_str;
 
@@ -689,7 +739,7 @@ const Builder = struct {
             var found = false;
             for (possible_paths) |p|
                 found = found or (blk: {
-                    self.root_dir.access(io, p, .{}) catch break :blk false;
+                    self.root_dir.fd.access(io, p, .{}) catch break :blk false;
                     break :blk true;
                 });
             if (!found) {
@@ -715,13 +765,23 @@ const Builder = struct {
         if (track_refs) try self.refs.append(gpa, try gpa.dupe(u8, ref));
     }
 
-    fn templateLink(self: *Builder, gpa: Allocator, ref_name: []const u8, w: *std.Io.Writer) !void {
+    fn templateLink(
+        self: *Builder,
+        gpa: Allocator,
+        ref_name: []const u8,
+        w: *std.Io.Writer,
+    ) !void {
         const link = try formatLink(gpa, ref_name, self.options.offset_from_siteroot);
         defer gpa.free(link);
         try w.writeAll(link);
     }
 
-    fn templateName(_: *Builder, gpa: Allocator, ref_name: []const u8, w: *std.Io.Writer) !void {
+    fn templateName(
+        _: *Builder,
+        gpa: Allocator,
+        ref_name: []const u8,
+        w: *std.Io.Writer,
+    ) !void {
         const name = try formatName(gpa, ref_name);
         defer gpa.free(name);
         try w.writeAll(name);
@@ -737,7 +797,7 @@ const Builder = struct {
 
         if (try targetExists(io, gpa, self.target_dir, target_path, self.root_dir)) return;
         // TODO: allow customizing tilde dir
-        const target_fd = try self.target_dir.createFile(io, target_path, .{
+        const target_fd = try self.target_dir.fd.createFile(io, target_path, .{
             .lock = .exclusive,
         });
         defer target_fd.close(io);
@@ -781,7 +841,7 @@ const Builder = struct {
         const source_stem = std.fs.path.basename(self.source.path)[5..]; // trim "meta."
 
         if (try targetExists(io, gpa, self.target_dir, source_stem, self.root_dir)) return;
-        const target_fd = try self.target_dir.createFile(io, source_stem, .{
+        const target_fd = try self.target_dir.fd.createFile(io, source_stem, .{
             .lock = .exclusive,
         });
         defer target_fd.close(io);
@@ -804,7 +864,7 @@ const Builder = struct {
         defer gpa.free(target_path);
 
         if (try targetExists(io, gpa, self.root_dir, target_path, self.root_dir)) return;
-        const target_fd = try self.root_dir.createFile(io, target_path, .{
+        const target_fd = try self.root_dir.fd.createFile(io, target_path, .{
             .lock = .exclusive,
             .read = true,
             .truncate = true,
@@ -819,7 +879,7 @@ const Builder = struct {
         , .{ fd, target_path, self.source.path });
         defer gpa.free(pandoc_command);
 
-        try shell(io, pandoc_command, .{ .cwd = .{ .dir = self.root_dir } });
+        try shell(io, pandoc_command, .{ .cwd = .{ .dir = self.root_dir.fd } });
 
         // track source
         try self.parts.append(gpa, try gpa.dupe(u8, self.source.path));
@@ -842,10 +902,16 @@ fn formatLink(gpa: Allocator, name: []const u8, pathPrefix: ?[]const u8) ![]u8 {
     return try std.fs.path.join(gpa, &.{ pathPrefix orelse "/", link_name });
 }
 
-fn targetExists(io: Io, gpa: Allocator, target_dir: Io.Dir, sub_path: []const u8, root_dir: Io.Dir) !bool {
+fn targetExists(
+    io: Io,
+    gpa: Allocator,
+    target_dir: Dir,
+    sub_path: []const u8,
+    root_dir: Dir,
+) !bool {
     if (FORCE) return false;
 
-    const target_fd = target_dir.openFile(io, sub_path, .{}) catch |err|
+    const target_fd = target_dir.fd.openFile(io, sub_path, .{}) catch |err|
         switch (err) {
             error.FileNotFound => return false,
             else => return err,
@@ -1104,13 +1170,13 @@ test "e2e" {
         const Self = @This();
 
         source: File,
-        root_dir: Io.Dir,
+        root_dir: Dir,
 
         expect_path: []const u8,
         expect_dgst: Digest,
 
         fn init(path: []const u8, expect_path: []const u8, expect_dgst: Digest) !Self {
-            const root_dir = try std.Io.Dir.cwd().openDir(io, std.fs.path.dirname(path).?, .{});
+            const root_dir = try Dir.init(io, std.Io.Dir.cwd(), std.fs.path.dirname(path).?, .{});
             return .{
                 .root_dir = root_dir,
                 .source = try File.init(io, root_dir, std.fs.path.basename(path), null),