commit 26a70bb0dd29c550f1f4e6f0c8e8a69ec565615e
parent 06bbaa657da60958a0ac2629b36a72ad6beaed53
Author: Martin Ashby <martin@ashbysoft.com>
Date: Sat, 10 Aug 2024 23:19:32 +0100
Work on GitRepository structure
Diffstat:
M | src/root.zig | | | 76 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
1 file changed, 56 insertions(+), 20 deletions(-)
diff --git a/src/root.zig b/src/root.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const argparse = @import("argparse.zig");
+const IniFile = @import("inifile.zig");
pub fn doMain() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
@@ -21,41 +22,76 @@ pub fn doMain() !void {
}
}
-const GitConfig = struct {};
-
pub const GitRepository = struct {
worktree: []const u8,
gitdir: []const u8,
- conf: GitConfig,
+ conf: IniFile,
_aa: std.heap.ArenaAllocator,
- pub const InitError = error{
- OutOfMemory,
- NotAGitRepo,
- FsError,
- };
+ pub fn init(ca: std.mem.Allocator, path: []const u8, force: bool) !GitRepository {
+ var self: GitRepository = undefined;
+ self._aa = std.heap.ArenaAllocator.init(ca);
+ errdefer self.deinit();
- pub fn init(ca: std.mem.Allocator, path: []const u8, force: bool) InitError!GitRepository {
- const aa = std.heap.ArenaAllocator.init(ca);
- errdefer aa.deinit();
- const a = aa.allocator();
+ self.worktree = path;
+ const a = self._aa.allocator();
+ const cwd = std.fs.cwd();
const gitdirpath = try std.fs.path.join(a, &.{ path, ".git" });
if (!force) {
- std.fs.cwd().openDir(gitdirpath, .{}) catch |e| switch (e) {
+ var gitdir = cwd.openDir(gitdirpath, .{}) catch |e| switch (e) {
error.FileNotFound, error.NotDir => return error.NotAGitRepo,
- else => error.FsError,
+ else => return error.FsError,
};
+ defer gitdir.close();
}
-
- return .{
- ._aa = aa,
- .worktree = path,
- .gitdir = gitdirpath,
- };
+ self.gitdir = gitdirpath;
+ const gitconfigpath = try std.fs.path.join(a, &.{ gitdirpath, "config" });
+ const configcontent = try cwd.readFileAlloc(a, gitconfigpath, 10_000_000);
+ defer a.free(configcontent);
+ self.conf = try IniFile.parse(a, configcontent);
+ return self;
}
pub fn deinit(self: *GitRepository) void {
self._aa.deinit();
}
+
+ /// Compute path under repo's gitdir.
+ fn repo_path(self: GitRepository, path: []const u8) ![]const u8 {
+ return try std.fs.path.join(self._aa.allocator(), &.{ self.gitdir, path });
+ }
+
+ /// Same as repo_path, but create dirname(*path) if absent. For
+ /// example, repo_file(r, \"refs\", \"remotes\", \"origin\", \"HEAD\") will create
+ /// .git/refs/remotes/origin."""
+ fn repo_file(self: GitRepository, path: []const u8, mkdir: bool) !?[]const u8 {
+ const dirname = std.fs.path.dirname(path) orelse return error.EmptyPath;
+ if (try self.repo_dir(dirname, mkdir)) |_| {
+ return try repo_path(self, path);
+ } else {
+ return null;
+ }
+ }
+
+ /// Same as repo_path, but mkdir *path if absent if mkdir.
+ fn repo_dir(self: GitRepository, path: []const u8, mkdir: bool) !?[]const u8 {
+ const p = try self.repo_path(path);
+ if (mkdir) {
+ try std.fs.cwd().makePath(p);
+ return p;
+ } else {
+ const dir = std.fs.cwd().openDir(p, .{}) catch |e| switch (e) {
+ error.FileNotFound => return null,
+ else => return e,
+ };
+ dir.close();
+ return p;
+ }
+ }
};
+
+test "init repo" {
+ var gr = try GitRepository.init(std.testing.allocator, ".", false);
+ defer gr.deinit();
+}