cerrado @ zig

  1const std = @import("std");
  2const testing = std.testing;
  3const Allocator = std.mem.Allocator;
  4const galloc = @import("galloc.zig");
  5
  6const git = @cImport({
  7    @cInclude("git2.h");
  8});
  9
 10const GitError = error{
 11    RepsitoryNotInitialized,
 12    RepositoryAlreadyInitialized,
 13    Unkown,
 14
 15    //libgit specific  error
 16    GitError,
 17    GitNotfound,
 18    GitExists,
 19    GitAmbiguous,
 20    GitBufs,
 21    GitUser,
 22    GitUnbornBranch,
 23    GitUnmerged,
 24    GitNonFastForward,
 25    GitInvalidSpec,
 26    GitConflict,
 27    GitLocked,
 28    GitModified,
 29    GitAuth,
 30    GitCertificate,
 31    GitApplied,
 32    GitPeel,
 33    GitEof,
 34    GitInvalid,
 35    GitUncommitted,
 36    GitDirectory,
 37    GitMergeConflict,
 38    GitPassthrough,
 39    GitIterOver,
 40    GitRetry,
 41    GitMismatch,
 42    GitIndexDirty,
 43    GitApplyFail,
 44    GitOwner,
 45    GitTimeout,
 46    GitUnchanged,
 47    GitNotSupported,
 48    GitReadonly,
 49};
 50
 51var alloc: galloc.GitAllocator = undefined;
 52
 53fn malloc(size: usize, _: ?*anyopaque) callconv(.C) ?*anyopaque {
 54    return alloc.malloc(size);
 55}
 56
 57fn relloc(ptr: ?*anyopaque, size: usize, _: ?*anyopaque) callconv(.C) ?*anyopaque {
 58    const new_ptr = alloc.realloc(ptr, size);
 59    return new_ptr;
 60}
 61
 62fn free(ptr: ?*anyopaque) callconv(.C) void {
 63    alloc.free(ptr);
 64}
 65
 66fn err(code: c_int) GitError!void {
 67    if (code >= 0) return;
 68
 69    return switch (code) {
 70        git.GIT_ERROR => GitError.GitError,
 71        git.GIT_ENOTFOUND => GitError.GitNotfound,
 72        git.GIT_EEXISTS => GitError.GitExists,
 73        git.GIT_EAMBIGUOUS => GitError.GitAmbiguous,
 74        git.GIT_EBUFS => GitError.GitBufs,
 75        git.GIT_EUSER => GitError.GitUser,
 76        git.GIT_EUNBORNBRANCH => GitError.GitUnbornBranch,
 77        git.GIT_EUNMERGED => GitError.GitUnmerged,
 78        git.GIT_ENONFASTFORWARD => GitError.GitNonFastForward,
 79        git.GIT_EINVALIDSPEC => GitError.GitInvalidSpec,
 80        git.GIT_ECONFLICT => GitError.GitConflict,
 81        git.GIT_ELOCKED => GitError.GitLocked,
 82        git.GIT_EMODIFIED => GitError.GitModified,
 83        git.GIT_EAUTH => GitError.GitAuth,
 84        git.GIT_ECERTIFICATE => GitError.GitCertificate,
 85        git.GIT_EAPPLIED => GitError.GitApplied,
 86        git.GIT_EPEEL => GitError.GitPeel,
 87        git.GIT_EEOF => GitError.GitEof,
 88        git.GIT_EINVALID => GitError.GitInvalid,
 89        git.GIT_EUNCOMMITTED => GitError.GitUncommitted,
 90        git.GIT_EDIRECTORY => GitError.GitDirectory,
 91        git.GIT_EMERGECONFLICT => GitError.GitMergeConflict,
 92        git.GIT_PASSTHROUGH => GitError.GitPassthrough,
 93        git.GIT_ITEROVER => GitError.GitIterOver,
 94        git.GIT_RETRY => GitError.GitRetry,
 95        git.GIT_EMISMATCH => GitError.GitMismatch,
 96        git.GIT_EINDEXDIRTY => GitError.GitIndexDirty,
 97        git.GIT_EAPPLYFAIL => GitError.GitApplyFail,
 98        git.GIT_EOWNER => GitError.GitOwner,
 99        git.GIT_TIMEOUT => GitError.GitTimeout,
100        git.GIT_EUNCHANGED => GitError.GitUnchanged,
101        git.GIT_ENOTSUPPORTED => GitError.GitNotSupported,
102        git.GIT_EREADONLY => GitError.GitReadonly,
103        else => GitError.Unkown,
104    };
105}
106
107const git_allocator = extern struct {
108    gmalloc: ?*const fn (size: usize, payload: ?*anyopaque) callconv(.C) ?*anyopaque,
109    grealloc: ?*const fn (ptr: ?*anyopaque, size: usize, payload: ?*anyopaque) callconv(.C) ?*anyopaque,
110    gfree: ?*const fn (ptr: ?*anyopaque) callconv(.C) void,
111};
112
113pub fn init(a: std.mem.Allocator) GitError!void {
114    alloc = galloc.GitAllocator.init(a);
115
116    const cAlloc = git_allocator{
117        .gmalloc = malloc,
118        .grealloc = relloc,
119        .gfree = free,
120    };
121
122    var code = git.git_libgit2_opts(git.GIT_OPT_SET_ALLOCATOR, &cAlloc);
123    try err(code);
124
125    code = git.git_libgit2_init();
126    try err(code);
127}
128
129pub fn deinit() !void {
130    defer alloc.deinit();
131    try err(git.git_libgit2_shutdown());
132}
133
134pub const Commit = struct {
135    commit: *git.git_commit = undefined,
136
137    pub fn fromGitCommit(c: *git.git_commit) Commit {
138        return Commit{ .commit = c };
139    }
140};
141
142pub const Repository = struct {
143    repository: ?*git.git_repository = null,
144    reference: ?*git.git_reference = null,
145
146    fn validateInit(self: *Repository) GitError!void {
147        if (self.repository != null)
148            return GitError.RepositoryAlreadyInitialized;
149    }
150
151    fn validateNotInit(self: *Repository) GitError!void {
152        if (self.repository == null)
153            return GitError.RepsitoryNotInitialized;
154    }
155
156    fn validateRef(self: *Repository) GitError!void {
157        if (self.ref != null)
158            return GitError.RepositoryAlreadyInitialized;
159    }
160
161    pub fn open(self: *Repository, path: []const u8) GitError!void {
162        try self.validateInit();
163        try err(git.git_repository_open(@ptrCast(&self.repository), path.ptr));
164    }
165
166    pub fn init(self: *Repository, path: []const u8, bare: bool) GitError!void {
167        try self.validateInit();
168        try err(git.git_repository_init(@ptrCast(&self.repository), path.ptr, if (bare) 1 else 0));
169    }
170
171    pub fn setRef(self: *Repository, ref_name: []const u8) GitError!void {
172        try self.validateNotInit();
173
174        if (self.reference) |ref| {
175            git.git_reference_free(ref);
176            self.reference = null;
177        }
178
179        try err(git.git_reference_dwim(@ptrCast(&self.reference), self.repository, ref_name.ptr));
180    }
181
182    pub fn referenceName(self: *Repository) []const u8 {
183        if (self.reference) |ref| {
184            return std.mem.span(git.git_reference_name(ref));
185        }
186
187        return "";
188    }
189
190    pub fn deinit(self: *Repository) void {
191        if (self.reference) |ref| {
192            git.git_reference_free(ref);
193        }
194
195        if (self.repository) |repo| {
196            git.git_repository_free(repo);
197        }
198    }
199};
200
201test "init deinit" {
202    try init(testing.allocator);
203    try deinit();
204}
205
206test "open repository" {
207    try init(testing.allocator);
208    defer deinit() catch {};
209
210    var repository = Repository{};
211    defer repository.deinit();
212
213    try repository.open(".");
214}
215
216test "init repository" {
217    var tmp_dir = testing.tmpDir(.{});
218    defer tmp_dir.cleanup();
219
220    const full_path = try tmp_dir.dir.realpathAlloc(testing.allocator, ".");
221    defer testing.allocator.free(full_path);
222
223    try init(testing.allocator);
224    defer deinit() catch {};
225
226    var repository = Repository{};
227    defer repository.deinit();
228
229    try repository.init(full_path, false);
230}
231
232test "init repository bare" {
233    var tmp_dir = testing.tmpDir(.{});
234    defer tmp_dir.cleanup();
235
236    const full_path = try tmp_dir.dir.realpathAlloc(testing.allocator, ".");
237    defer testing.allocator.free(full_path);
238
239    try init(testing.allocator);
240    defer deinit() catch {};
241
242    var repository = Repository{};
243    defer repository.deinit();
244
245    try repository.init(full_path, false);
246
247    // try opening the repository to test if it is properly created.
248    var tmp = Repository{};
249    defer tmp.deinit();
250
251    try tmp.open(full_path);
252}
253
254test "set reference" {
255    try init(testing.allocator);
256    defer deinit() catch {};
257
258    var repository = Repository{};
259    defer repository.deinit();
260
261    try repository.open(".");
262
263    try repository.setRef("zig");
264    try testing.expect(std.mem.eql(u8, "refs/heads/zig", repository.referenceName()));
265
266    try repository.setRef("master");
267    try testing.expect(std.mem.eql(u8, "refs/heads/master", repository.referenceName()));
268}