2022-02-26 17:17:22 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
first commit: basic libgit2 wrapper
diff --git a/git.lua b/git.lua new file mode 100644 index 0000000..9b4b38a --- /dev/null +++ b/git.lua @@ -0,0 +1,154 @@ +local ffi = require "ffi" + +ffi.cdef[[ +typedef int64_t git_time_t; +typedef struct git_repository git_repository; +typedef struct git_object git_object; +typedef struct git_commit git_commit; +typedef struct git_tree git_tree; +typedef struct git_tree_entry git_tree_entry; +typedef struct git_diff git_diff; +typedef struct git_blob git_blob; +typedef struct git_tag git_tag; +typedef struct git_revwalk git_revwalk; +typedef enum { + GIT_OBJECT_ANY = -2, /**< Object can be any of the following */ + GIT_OBJECT_INVALID = -1, /**< Object is invalid. */ + GIT_OBJECT_COMMIT = 1, /**< A commit object. */ + GIT_OBJECT_TREE = 2, /**< A tree (directory listing) object. */ + GIT_OBJECT_BLOB = 3, /**< A file revision object. */ + GIT_OBJECT_TAG = 4, /**< An annotated tag object. */ + GIT_OBJECT_OFS_DELTA = 6, /**< A delta, base is given by an offset. */ + GIT_OBJECT_REF_DELTA = 7 /**< A delta, base is given by object id. */ +} git_object_t; +typedef struct git_oid { + /** raw binary formatted id */ + unsigned char id[20]; +} git_oid; +typedef struct git_strarray { + char **strings; + size_t count; +} git_strarray; +typedef struct git_time { + git_time_t time; /**< time in seconds from epoch */ + int offset; /**< timezone offset, in minutes */ + char sign; /**< indicator for questionable '-0000' offsets in signature */ +} git_time; +typedef struct git_signature { + char *name; /**< full name of the author */ + char *email; /**< email of the author */ + git_time when; /**< time when the action happened */ +} git_signature; +typedef struct git_diff_options git_diff_options; + +int git_libgit2_init(); +int git_libgit2_shutdown(); +int git_libgit2_version(int *major, int *minor, int *rev); + +const git_oid * git_object_id(const git_object *obj); +void git_object_free(git_object *object); + +int git_repository_open_ext(git_repository **out, const char *path, unsigned int flags, const char *ceiling_dirs); +int git_repository_open_bare(git_repository **out, const char *bare_path); + +int git_oid_fromstr(git_oid *out, const char *str); +char * git_oid_tostr(char *out, size_t n, const git_oid *id); + +int git_reference_list(git_strarray *array, git_repository *repo); +void git_strarray_free(git_strarray *array); + +int git_tag_list(git_strarray *tag_names, git_repository *repo); + +int git_revparse_single(git_object **out, git_repository *repo, const char *spec); + +int git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id); +int git_commit_parent(git_commit **out, const git_commit *commit, unsigned int n); +const char * git_commit_message(const git_commit *commit); +const char * git_commit_summary(git_commit *commit); +git_time_t git_commit_time(const git_commit *commit); +const git_signature * git_commit_author(const git_commit *commit); + +int git_revwalk_new(git_revwalk **out, git_repository *repo); +int git_revwalk_push_range(git_revwalk *walk, const char *range); +int git_revwalk_next(git_oid *out, git_revwalk *walk); + +int git_commit_tree(git_tree **tree_out, const git_commit *commit); +size_t git_tree_entrycount(const git_tree *tree); +const git_tree_entry * git_tree_entry_byindex(const git_tree *tree, size_t idx); +git_object_t git_tree_entry_type(const git_tree_entry *entry); + +int git_diff_tree_to_tree(git_diff **diff, git_repository *repo, git_tree *old_tree, git_tree *new_tree, const git_diff_options *opts); +]] +local C = ffi.load("git2") + +local function strarr_to_table(strarr) + local tab = {} + for i = 1, tonumber(strarr[0].count) do + local str = ffi.string(strarr[0].strings[i-1]) + table.insert(tab, str) + end + return tab +end + +local Commit = {} +Commit.__index = Commit + +local function get_commit(commit) + return setmetatable({commit=commit}, Commit) +end + +function Commit:message() + return ffi.string(C.git_commit_message(self.commit)) +end + +function Commit:summary() + return ffi.string(C.git_commit_summary(self.commit)) +end + +function Commit:parent(n) + n = n or 1 + local pcommit = ffi.new("git_commit *[1]") + C.git_commit_parent(pcommit, self.commit, n-1) + return get_commit(pcommit[0]) +end + +local Repo = {} +Repo.__index = Repo + +function Repo:refs() + local strarr = ffi.new("git_strarray[1]") + C.git_reference_list(strarr, self.repo) + local refs = strarr_to_table(strarr) + C.git_strarray_free(strarr); + return refs +end + +function Repo:tags() + local strarr = ffi.new("git_strarray[1]") + C.git_tag_list(strarr, self.repo) + local tags = strarr_to_table(strarr) + C.git_strarray_free(strarr); + return tags +end + +function Repo:commit(rev) + local pobj = ffi.new("git_object *[1]") + C.git_revparse_single(pobj, self.repo, rev) + local obj = pobj[0] + local oid = C.git_object_id(obj) + local pcommit = ffi.new("git_commit *[1]") + C.git_commit_lookup(pcommit, self.repo, oid) + local commit = pcommit[0] + C.git_object_free(obj) + return get_commit(commit) +end + +local function open(path) + local self = setmetatable({}, Repo) + local prepo = ffi.new("git_repository *[1]") + assert(C.git_repository_open_bare(prepo, path) == 0) + self.repo = prepo[0] + return self +end + +return {init=C.git_libgit2_init, shutdown=C.git_libgit2_shutdown, open=open}