commit 929cfb179ecc9f7fe6c577181b158b6b9c63caf3
parent 104c4784208a32b03cdc2bafaa61eeeb8e788f1c
Author: Martin Ashby <martin@ashbysoft.com>
Date: Sun, 11 Aug 2024 22:40:26 +0100
add repo_find function
Use std.fs.Dir instead of path in a few places where it makes more sense
to use dir directly.
Diffstat:
M | src/root.zig | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++-------- |
1 file changed, 46 insertions(+), 8 deletions(-)
diff --git a/src/root.zig b/src/root.zig
@@ -41,13 +41,15 @@ pub const GitRepository = struct {
conf: IniFile,
_aa: std.heap.ArenaAllocator,
- pub fn init(ca: std.mem.Allocator, path: []const u8) !GitRepository {
+ // Note: takes 'ownership' of dir; callers should not use it again (including closing it) after calling
+ // this function.
+ pub fn init(ca: std.mem.Allocator, dir: Dir) !GitRepository {
var self: GitRepository = undefined;
self._aa = std.heap.ArenaAllocator.init(ca);
errdefer self._aa.deinit();
const a = self._aa.allocator();
- self.worktree = try std.fs.cwd().openDir(path, .{ .iterate = true });
+ self.worktree = dir;
errdefer self.worktree.close();
self.gitdir = try self.worktree.openDir(".git", .{ .iterate = true });
errdefer self.gitdir.close();
@@ -58,25 +60,26 @@ pub const GitRepository = struct {
}
pub fn deinit(self: *GitRepository) void {
- self.gitdir.close();
- self.worktree.close();
+ safeclose(&self.gitdir);
+ safeclose(&self.worktree);
self._aa.deinit();
}
};
test "init repo" {
- var gr = try GitRepository.init(std.testing.allocator, ".", false);
+ var gr = try GitRepository.init(std.testing.allocator, std.fs.cwd());
defer gr.deinit();
}
fn repo_create(ca: std.mem.Allocator, path: []const u8) !GitRepository {
+ var worktree: Dir = undefined;
{
var aa = std.heap.ArenaAllocator.init(ca);
defer aa.deinit();
const a = aa.allocator();
const cwd = std.fs.cwd();
- var worktree = try cwd.makeOpenPath(path, .{});
- defer worktree.close();
+ worktree = try cwd.makeOpenPath(path, .{});
+ errdefer worktree.close();
var gitdir = try worktree.makeOpenPath(".git", .{});
defer gitdir.close();
try gitdir.makePath("branches");
@@ -95,5 +98,40 @@ fn repo_create(ca: std.mem.Allocator, path: []const u8) !GitRepository {
\\ bare = false
);
}
- return try GitRepository.init(ca, path);
+ return try GitRepository.init(ca, worktree);
}
+
+// takes ownership of "dir", the variable should not be used
+// by any other code after calling this function.
+fn repo_find(a: std.mem.Allocator, dir: Dir) !GitRepository {
+ const stat = dir.statFile(".git") catch |e| switch (e) {
+ error.FileNotFound => {
+ // try the parent
+ var parentdir = dir.openDir("..", .{.iterate = true}) catch |e2| switch (e2) {
+ error.FileNotFound => return error.NoGitDirFound,
+ else => return e2,
+ };
+ errdefer parentdir.close();
+ return repo_find(a, parentdir);
+ },
+ else => return e,
+ };
+ if (stat.kind == .directory) {
+ return try GitRepository.init(a, dir);
+ } else {
+ return error.NoGitDirFound;
+ }
+}
+
+fn safeclose(dir: *Dir) void {
+ if (std.fs.cwd().fd != dir.fd) {
+ dir.close();
+ }
+}
+
+test "repo_find" {
+ const srcdir = try std.fs.cwd().openDir("src/foo/bar/baz", .{.iterate = true});
+ var gr = try repo_find(std.testing.allocator, srcdir);
+ defer gr.deinit();
+}
+