authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2025-08-24 21:08:47 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2025-12-17 18:31:47 -08:00
log73aeaf86db7d1ee7ab39f053ccc846f3954ecd3a
tree0810b1a82d911f8bd7d73e16ffd733cc89b8e4d4
parente3fb67f40f18132e1553024aaa8efaa306f2cb13

switch to nfs over std.fs


4 files changed, 48 insertions(+), 30 deletions(-)

git.zig+23-19
......@@ -4,6 +4,7 @@ const top = @This();
44const time = @import("time");
55const extras = @import("extras");
66const tracer = @import("tracer");
7const nfs = @import("nfs");
78
89// 40 is length of sha1 hash
910pub const Id = *const [40]u8;
......@@ -55,7 +56,7 @@ pub fn version(alloc: std.mem.Allocator) !string {
5556/// Returns the result of running `git rev-parse HEAD`
5657/// dir must already be pointing at the .git folder
5758// TODO this doesnt handle when there are 0 commits
58pub fn getHEAD(alloc: std.mem.Allocator, dir: std.fs.Dir) !?CommitId {
59pub fn getHEAD(alloc: std.mem.Allocator, dir: nfs.Dir) !?CommitId {
5960 const t = tracer.trace(@src(), "", .{});
6061 defer t.end();
6162
......@@ -63,7 +64,10 @@ pub fn getHEAD(alloc: std.mem.Allocator, dir: std.fs.Dir) !?CommitId {
6364
6465 if (std.mem.startsWith(u8, h, "ref:")) {
6566 blk: {
66 const reffile = dir.readFileAlloc(alloc, h[5..], 1024) catch |err| switch (err) {
67 var buf: [std.fs.max_path_bytes]u8 = undefined;
68 @memcpy((&buf).ptr, h[5..]);
69 buf[h[5..].len] = 0;
70 const reffile = dir.readFileAlloc(alloc, buf[0..h[5..].len :0], 1024) catch |err| switch (err) {
6771 error.FileNotFound => break :blk,
6872 else => |e| return e,
6973 };
......@@ -101,13 +105,13 @@ fn ensureObjId(comptime T: type, input: string) T {
101105// TODO make this return a Reader when we implement it ourselves
102106// https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
103107// https://git-scm.com/book/en/v2/Git-Internals-Packfiles
104pub fn getObject(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !string {
108pub fn getObject(alloc: std.mem.Allocator, dir: nfs.Dir, obj: Id) !string {
105109 const t = tracer.trace(@src(), " {s}", .{obj});
106110 defer t.end();
107111
108112 const result = try std.process.Child.run(.{
109113 .allocator = alloc,
110 .cwd_dir = dir,
114 .cwd_dir = dir.to_std(),
111115 .argv = &.{ "git", "cat-file", "-p", obj },
112116 .max_output_bytes = 1024 * 1024 * 1024,
113117 });
......@@ -118,13 +122,13 @@ pub fn getObject(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !string {
118122// TODO make this inspect .git/objects manually
119123// https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
120124// https://git-scm.com/book/en/v2/Git-Internals-Packfiles
121pub fn getObjectSize(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !u64 {
125pub fn getObjectSize(alloc: std.mem.Allocator, dir: nfs.Dir, obj: Id) !u64 {
122126 const t = tracer.trace(@src(), " {s}", .{obj});
123127 defer t.end();
124128
125129 const result = try std.process.Child.run(.{
126130 .allocator = alloc,
127 .cwd_dir = dir,
131 .cwd_dir = dir.to_std(),
128132 .argv = &.{ "git", "cat-file", "-s", obj },
129133 });
130134 extras.assertLog(result.term == .Exited and result.term.Exited == 0, "{s}", .{result.stderr});
......@@ -134,13 +138,13 @@ pub fn getObjectSize(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !u64 {
134138// TODO make this inspect .git manually
135139// https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
136140// https://git-scm.com/book/en/v2/Git-Internals-Packfiles
137pub fn isType(alloc: std.mem.Allocator, dir: std.fs.Dir, maybeobj: Id, typ: Tree.Object.Id.Tag) !bool {
141pub fn isType(alloc: std.mem.Allocator, dir: nfs.Dir, maybeobj: Id, typ: Tree.Object.Id.Tag) !bool {
138142 const t = tracer.trace(@src(), " {s} = {s} ?", .{ maybeobj, @tagName(typ) });
139143 defer t.end();
140144
141145 const result = try std.process.Child.run(.{
142146 .allocator = alloc,
143 .cwd_dir = dir,
147 .cwd_dir = dir.to_std(),
144148 .argv = &.{ "git", "cat-file", "-t", maybeobj },
145149 });
146150 std.debug.assert(result.term == .Exited and result.term.Exited == 0);
......@@ -151,13 +155,13 @@ pub fn isType(alloc: std.mem.Allocator, dir: std.fs.Dir, maybeobj: Id, typ: Tree
151155// TODO make this inspect .git manually
152156// https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
153157// https://git-scm.com/book/en/v2/Git-Internals-Packfiles
154pub fn getType(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !Tree.Object.Id.Tag {
158pub fn getType(alloc: std.mem.Allocator, dir: nfs.Dir, obj: Id) !Tree.Object.Id.Tag {
155159 const t = tracer.trace(@src(), " {s}", .{obj});
156160 defer t.end();
157161
158162 const result = try std.process.Child.run(.{
159163 .allocator = alloc,
160 .cwd_dir = dir,
164 .cwd_dir = dir.to_std(),
161165 .argv = &.{ "git", "cat-file", "-t", obj },
162166 });
163167 std.debug.assert(result.term == .Exited and result.term.Exited == 0);
......@@ -169,13 +173,13 @@ pub fn getType(alloc: std.mem.Allocator, dir: std.fs.Dir, obj: Id) !Tree.Object.
169173// TODO make a version of this that accepts an array of sub_paths and searches all of them at once, so as to not lose spot in history when searching for many old paths
170174// https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
171175// https://git-scm.com/book/en/v2/Git-Internals-Packfiles
172pub fn revList(alloc: std.mem.Allocator, dir: std.fs.Dir, comptime count: u31, from: CommitId, sub_path: string) !string {
176pub fn revList(alloc: std.mem.Allocator, dir: nfs.Dir, comptime count: u31, from: CommitId, sub_path: string) !string {
173177 const t = tracer.trace(@src(), "({d}) {s} -- {s}", .{ count, from.id, sub_path });
174178 defer t.end();
175179
176180 const result = try std.process.Child.run(.{
177181 .allocator = alloc,
178 .cwd_dir = dir,
182 .cwd_dir = dir.to_std(),
179183 .argv = &.{
180184 "git",
181185 "rev-list",
......@@ -412,14 +416,14 @@ pub const Tree = struct {
412416
413417// TODO make this inspect .git manually
414418// TODO make this return a Reader when we implement it ourselves
415pub fn getTreeDiff(alloc: std.mem.Allocator, dir: std.fs.Dir, commitid: CommitId, parentid: ?CommitId) !string {
419pub fn getTreeDiff(alloc: std.mem.Allocator, dir: nfs.Dir, commitid: CommitId, parentid: ?CommitId) !string {
416420 const t = tracer.trace(@src(), "", .{});
417421 defer t.end();
418422
419423 if (parentid == null) {
420424 const result = try std.process.Child.run(.{
421425 .allocator = alloc,
422 .cwd_dir = dir,
426 .cwd_dir = dir.to_std(),
423427 // 4b825dc642cb6eb9a060e54bf8d69288fbee4904 is a hardcode for the empty tree in git sha1
424428 // result of `printf | git hash-object -t tree --stdin`
425429 .argv = &.{ "git", "diff-tree", "-p", "--raw", "4b825dc642cb6eb9a060e54bf8d69288fbee4904", commitid.id },
......@@ -430,7 +434,7 @@ pub fn getTreeDiff(alloc: std.mem.Allocator, dir: std.fs.Dir, commitid: CommitId
430434 }
431435 const result = try std.process.Child.run(.{
432436 .allocator = alloc,
433 .cwd_dir = dir,
437 .cwd_dir = dir.to_std(),
434438 .argv = &.{ "git", "diff-tree", "-p", "--raw", parentid.?.id, commitid.id },
435439 .max_output_bytes = 1024 * 1024 * 1024,
436440 });
......@@ -681,13 +685,13 @@ pub const TreeDiff = struct {
681685 };
682686};
683687
684pub fn getBranches(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref {
688pub fn getBranches(alloc: std.mem.Allocator, dir: nfs.Dir) ![]const Ref {
685689 const t = tracer.trace(@src(), "", .{});
686690 defer t.end();
687691
688692 const result = try std.process.Child.run(.{
689693 .allocator = alloc,
690 .cwd_dir = dir,
694 .cwd_dir = dir.to_std(),
691695 .argv = &.{ "git", "show-ref", "--heads" },
692696 .max_output_bytes = 1024 * 1024 * 1024,
693697 });
......@@ -707,7 +711,7 @@ pub fn getBranches(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref {
707711 return list.toOwnedSlice();
708712}
709713
710pub fn getTags(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref {
714pub fn getTags(alloc: std.mem.Allocator, dir: nfs.Dir) ![]const Ref {
711715 const t = tracer.trace(@src(), "", .{});
712716 defer t.end();
713717
......@@ -717,7 +721,7 @@ pub fn getTags(alloc: std.mem.Allocator, dir: std.fs.Dir) ![]const Ref {
717721 // 7dfd3948a9095f0253bfba60fed52895ffbf84bb refs/tags/15.3.2
718722 const result = try std.process.Child.run(.{
719723 .allocator = alloc,
720 .cwd_dir = dir,
724 .cwd_dir = dir.to_std(),
721725 .argv = &.{ "git", "show-ref", "--tags", "--dereference" },
722726 .max_output_bytes = 1024 * 1024 * 1024,
723727 });
licenses.txt+11
......@@ -1,7 +1,18 @@
11MIT:
22= https://spdx.org/licenses/MIT
33- This
4- git https://github.com/nektro/zig-errno
45- git https://github.com/nektro/zig-expect
56- git https://github.com/nektro/zig-extras
7- git https://github.com/nektro/zig-libc
8- git https://github.com/nektro/zig-sys-libc
69- git https://github.com/nektro/zig-time
710- git https://github.com/nektro/zig-tracer
11
12MPL-2.0:
13= https://spdx.org/licenses/MPL-2.0
14- git https://github.com/nektro/zig-nfs
15- git https://github.com/nektro/zig-nio
16
17Unspecified:
18- system_lib c
test.zig+12-11
......@@ -2,6 +2,7 @@ const std = @import("std");
22const git = @import("git");
33const extras = @import("extras");
44const expect = @import("expect").expect;
5const nfs = @import("nfs");
56
67test {
78 _ = &git.version;
......@@ -14,7 +15,7 @@ test {
1415 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
1516 defer arena.deinit();
1617 const alloc = arena.allocator();
17 var git_dir = try std.fs.cwd().openDir(".git", .{});
18 const git_dir = try nfs.cwd().openDir(".git", .{});
1819 defer git_dir.close();
1920 const branch_refs = try git.getBranches(alloc, git_dir);
2021 const branch_names = try extras.mapBy(alloc, branch_refs, .label);
......@@ -25,7 +26,7 @@ test {
2526 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
2627 defer arena.deinit();
2728 const alloc = arena.allocator();
28 var git_dir = try std.fs.cwd().openDir(".git", .{});
29 const git_dir = try nfs.cwd().openDir(".git", .{});
2930 defer git_dir.close();
3031 try expect(try git.getObject(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e")).toEqualString(
3132 \\tree 5403fecad0fde9120535321f222a061abc2849d9
......@@ -42,7 +43,7 @@ test {
4243 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
4344 defer arena.deinit();
4445 const alloc = arena.allocator();
45 var git_dir = try std.fs.cwd().openDir(".git", .{});
46 const git_dir = try nfs.cwd().openDir(".git", .{});
4647 defer git_dir.close();
4748 try expect(try git.getObjectSize(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e")).toEqual(229);
4849 try expect(try git.getObjectSize(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e")).toEqual(45 + 47 + 55 + 58 + 0 + 18 + 6);
......@@ -52,7 +53,7 @@ test {
5253 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
5354 defer arena.deinit();
5455 const alloc = arena.allocator();
55 var git_dir = try std.fs.cwd().openDir(".git", .{});
56 const git_dir = try nfs.cwd().openDir(".git", .{});
5657 defer git_dir.close();
5758 try expect(try git.isType(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e", .blob)).toEqual(false);
5859 try expect(try git.isType(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e", .tree)).toEqual(false);
......@@ -64,7 +65,7 @@ test {
6465 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
6566 defer arena.deinit();
6667 const alloc = arena.allocator();
67 var git_dir = try std.fs.cwd().openDir(".git", .{});
68 const git_dir = try nfs.cwd().openDir(".git", .{});
6869 defer git_dir.close();
6970 try expect(try git.getType(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e")).toEqual(.commit);
7071}
......@@ -73,7 +74,7 @@ test {
7374 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
7475 defer arena.deinit();
7576 const alloc = arena.allocator();
76 var git_dir = try std.fs.cwd().openDir(".git", .{});
77 const git_dir = try nfs.cwd().openDir(".git", .{});
7778 defer git_dir.close();
7879 const c = try git.parseCommit(alloc, try git.getObject(alloc, git_dir, "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e"));
7980 try expect(c.tree.id).toEqualString("5403fecad0fde9120535321f222a061abc2849d9");
......@@ -95,7 +96,7 @@ test {
9596 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
9697 defer arena.deinit();
9798 const alloc = arena.allocator();
98 var git_dir = try std.fs.cwd().openDir(".git", .{});
99 const git_dir = try nfs.cwd().openDir(".git", .{});
99100 defer git_dir.close();
100101 try expect(try git.getObject(alloc, git_dir, "5403fecad0fde9120535321f222a061abc2849d9")).toEqualString(
101102 // zig fmt: off
......@@ -113,7 +114,7 @@ test {
113114 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
114115 defer arena.deinit();
115116 const alloc = arena.allocator();
116 var git_dir = try std.fs.cwd().openDir(".git", .{});
117 const git_dir = try nfs.cwd().openDir(".git", .{});
117118 defer git_dir.close();
118119 const t = try git.parseTree(alloc, try git.getObject(alloc, git_dir, "5403fecad0fde9120535321f222a061abc2849d9"));
119120 // TODO: test fields when we upgrade to 0.14 and have decl literals
......@@ -137,7 +138,7 @@ test {
137138 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
138139 defer arena.deinit();
139140 const alloc = arena.allocator();
140 var git_dir = try std.fs.cwd().openDir(".git", .{});
141 const git_dir = try nfs.cwd().openDir(".git", .{});
141142 defer git_dir.close();
142143 try expect(try git.getTreeDiff(alloc, git_dir, .{ .id = "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e" }, .{ .id = "c39f57f6bb01664a7146ddbfc3debe76ec135f44" })).toEqualString(
143144 // zig fmt: off
......@@ -171,7 +172,7 @@ test {
171172 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
172173 defer arena.deinit();
173174 const alloc = arena.allocator();
174 var git_dir = try std.fs.cwd().openDir(".git", .{});
175 const git_dir = try nfs.cwd().openDir(".git", .{});
175176 defer git_dir.close();
176177 const t = try git.parseTreeDiffMeta(try git.getTreeDiff(alloc, git_dir, .{ .id = "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e" }, .{ .id = "c39f57f6bb01664a7146ddbfc3debe76ec135f44" }));
177178 try expect(t.files_changed).toEqual(1);
......@@ -183,7 +184,7 @@ test {
183184 var arena = std.heap.ArenaAllocator.init(std.testing.allocator);
184185 defer arena.deinit();
185186 const alloc = arena.allocator();
186 var git_dir = try std.fs.cwd().openDir(".git", .{});
187 const git_dir = try nfs.cwd().openDir(".git", .{});
187188 defer git_dir.close();
188189 const t = try git.parseTreeDiff(alloc, try git.getTreeDiff(alloc, git_dir, .{ .id = "a542da41f1f0c59fdd0e1527cf5ff9de3f6a0c8e" }, .{ .id = "c39f57f6bb01664a7146ddbfc3debe76ec135f44" }));
189190 _ = t; // TODO: test fields when we upgrade to 0.14 and have decl literals
zig.mod+2
......@@ -7,6 +7,8 @@ dependencies:
77 - src: git https://github.com/nektro/zig-time
88 - src: git https://github.com/nektro/zig-extras
99 - src: git https://github.com/nektro/zig-tracer
10 - src: git https://github.com/nektro/zig-nfs
1011root_dependencies:
1112 - src: git https://github.com/nektro/zig-extras
1213 - src: git https://github.com/nektro/zig-expect
14 - src: git https://github.com/nektro/zig-nfs