summaryrefslogtreecommitdiff
path: root/lib/gall/ll/git2.c
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2014-08-23 19:13:02 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2014-08-23 19:13:02 +0100
commit66188bf99eac268e7f651a54dcbf164660ef8bd2 (patch)
tree3813eb907b889c37df7c9675a1b75f3eb50f8321 /lib/gall/ll/git2.c
parent608b3456b218ea0f7c8d37412b3a541680e6638e (diff)
downloadgall-66188bf99eac268e7f651a54dcbf164660ef8bd2.tar.gz
Basic dodgy version of a git2 binding
Diffstat (limited to 'lib/gall/ll/git2.c')
-rw-r--r--lib/gall/ll/git2.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/lib/gall/ll/git2.c b/lib/gall/ll/git2.c
new file mode 100644
index 0000000..4eecb91
--- /dev/null
+++ b/lib/gall/ll/git2.c
@@ -0,0 +1,268 @@
+/* git2.c
+ *
+ * Simple binding to the parts of libgit2 in use by Gall.
+ *
+ * Copyright 2014 Daniel Silverstone <dsilvers@digital-scurf.org>
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+#include "git2.h"
+
+typedef struct {
+ git_repository *repo;
+ git_odb *odb;
+} repo_et_al_t;
+
+static inline git_repository *to_repo(lua_State *L, int idx)
+{
+ repo_et_al_t *real = lua_touserdata(L, idx);
+ if (real == NULL)
+ return NULL;
+ return real->repo;
+}
+
+static inline git_odb *to_odb(lua_State *L, int idx)
+{
+ repo_et_al_t *real = lua_touserdata(L, idx);
+ if (real == NULL)
+ return NULL;
+ return real->odb;
+}
+
+/* Push the most recent error from libgit2 */
+static int push_git2_error(lua_State *L)
+{
+ const git_error *err = giterr_last();
+ lua_pushnil(L);
+ lua_pushstring(L, err->message);
+ return 2;
+}
+
+
+
+static int L_gc_repo(lua_State *L)
+{
+ repo_et_al_t *real = lua_touserdata(L, 1);
+ if (real->odb != NULL)
+ git_odb_free(real->odb);
+ if (real->repo != NULL)
+ git_repository_free(real->repo);
+ real->repo = NULL;
+ real->odb = NULL;
+ return 0;
+}
+
+/* Trivial Repository binding, GC will free the repo */
+static int L_open_repo(lua_State *L)
+{
+ const char *repopath = luaL_checkstring(L, 1);
+ int ret;
+ repo_et_al_t *real = lua_newuserdata(L, sizeof(*real));
+ real->repo = NULL; real->odb = NULL;
+
+ ret = git_repository_open(&real->repo, repopath);
+ if (ret != 0) {
+ return push_git2_error(L);
+ }
+
+ ret = git_repository_odb(&real->odb, real->repo);
+ if (ret != 0) {
+ push_git2_error(L);
+ git_repository_free(real->repo);
+ return 2;
+ }
+
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int L_lookup_symbolic_ref(lua_State *L)
+{
+ git_repository *repo = to_repo(L, 1);
+ const char *refname = luaL_checkstring(L, 2);
+ git_reference *ref = NULL;
+ if (git_reference_lookup(&ref, repo, refname) != 0) {
+ return push_git2_error(L);
+ }
+ if (git_reference_type(ref) != GIT_REF_SYMBOLIC) {
+ git_reference_free(ref);
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s is not symbolic", refname);
+ return 2;
+ }
+ lua_pushstring(L, git_reference_symbolic_target(ref));
+ git_reference_free(ref);
+ return 1;
+}
+
+static int format_oid(lua_State *L, git_oid *oid)
+{
+ char oidstr[40];
+ git_oid_fmt(oidstr, oid);
+ lua_pushlstring(L, oidstr, 40);
+ return 1;
+}
+
+static int L_lookup_sha_from_ref(lua_State *L)
+{
+ git_repository *repo = to_repo(L, 1);
+ const char *refname = luaL_checkstring(L, 2);
+ git_oid ref;
+ if (git_reference_name_to_id(&ref, repo, refname) != 0) {
+ return push_git2_error(L);
+ }
+ return format_oid(L, &ref);
+}
+
+static int parse_oid(lua_State *L, int spos, git_oid *oid)
+{
+ const char *oid_s = luaL_checkstring(L, spos);
+ int ret = git_oid_fromstr(oid, oid_s);
+ if (ret != 0)
+ return push_git2_error(L);
+ return 0;
+}
+
+static int L_merge_base(lua_State *L)
+{
+ git_repository *repo = to_repo(L, 1);
+ git_oid left, right, out;
+ int ret;
+ if (parse_oid(L, 2, &left) != 0)
+ return 2;
+ if (parse_oid(L, 3, &right) != 0)
+ return 2;
+ ret = git_merge_base(&out, repo, &left, &right);
+ if (ret == 0)
+ return format_oid(L, &out);
+ if (ret == GIT_ENOTFOUND) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "ENOTFOUND");
+ return 2;
+ }
+ return push_git2_error(L);
+}
+
+static int L_gc_odb_object(lua_State *L)
+{
+ git_odb_object **obj = lua_touserdata(L, 1);
+ if (*obj != NULL)
+ git_odb_object_free(*obj);
+ *obj = NULL;
+ return 0;
+}
+
+static int L_get_object(lua_State *L)
+{
+ git_odb *odb = to_odb(L, 1);
+ git_odb_object **obj = lua_newuserdata(L, sizeof(*obj));
+ git_oid oid;
+ if (parse_oid(L, 2, &oid) != 0)
+ return 2;
+ if (git_odb_read(obj, odb, &oid) != 0)
+ return push_git2_error(L);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int L_get_object_size(lua_State *L)
+{
+ git_odb_object **obj = lua_touserdata(L, 1);
+ lua_pushnumber(L, git_odb_object_size(*obj));
+ return 1;
+}
+
+static void push_object_type_str(lua_State *L, git_otype ty)
+{
+ switch(ty) {
+ case GIT_OBJ_ANY:
+ lua_pushliteral(L, "any");
+ break;
+ case GIT_OBJ_BAD:
+ lua_pushliteral(L, "bad");
+ break;
+ case GIT_OBJ__EXT1:
+ lua_pushliteral(L, "reserved");
+ break;
+ case GIT_OBJ_COMMIT:
+ lua_pushliteral(L, "commit");
+ break;
+ case GIT_OBJ_TREE:
+ lua_pushliteral(L, "tree");
+ break;
+ case GIT_OBJ_BLOB:
+ lua_pushliteral(L, "blob");
+ break;
+ case GIT_OBJ_TAG:
+ lua_pushliteral(L, "tag");
+ break;
+ case GIT_OBJ__EXT2:
+ lua_pushliteral(L, "reserved");
+ break;
+ case GIT_OBJ_OFS_DELTA:
+ lua_pushliteral(L, "delta");
+ break;
+ case GIT_OBJ_REF_DELTA:
+ lua_pushliteral(L, "refdelta");
+ break;
+ default:
+ lua_pushliteral(L, "unknown");
+ break;
+ }
+}
+
+static int L_get_object_type(lua_State *L)
+{
+ git_odb_object **obj = lua_touserdata(L, 1);
+ push_object_type_str(L, git_odb_object_type(*obj));
+ return 1;
+}
+
+static int L_get_object_raw(lua_State *L)
+{
+ git_odb_object **obj = lua_touserdata(L, 1);
+ lua_pushlstring(L, git_odb_object_data(*obj),
+ git_odb_object_size(*obj));
+ return 1;
+}
+
+int luaopen_git2(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushliteral(L, "LIBGIT2_VERSION");
+ lua_pushliteral(L, LIBGIT2_VERSION);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "open_repo");
+ lua_newtable(L);
+ lua_pushliteral(L, "__gc");
+ lua_pushcclosure(L, L_gc_repo, 0);
+ lua_settable(L, -3);
+ lua_pushcclosure(L, L_open_repo, 1);
+ lua_settable(L, -3);
+
+ lua_pushliteral(L, "get_object");
+ lua_newtable(L);
+ lua_pushliteral(L, "__gc");
+ lua_pushcclosure(L, L_gc_odb_object, 0);
+ lua_settable(L, -3);
+ lua_pushcclosure(L, L_get_object, 1);
+ lua_settable(L, -3);
+
+#define BASIC_FUNC(FN) \
+ do { \
+ lua_pushliteral(L, #FN); \
+ lua_pushcclosure(L, L_##FN, 0); \
+ lua_settable(L, -3); \
+ } while (0)
+ BASIC_FUNC(lookup_symbolic_ref);
+ BASIC_FUNC(lookup_sha_from_ref);
+ BASIC_FUNC(merge_base);
+ BASIC_FUNC(get_object_size);
+ BASIC_FUNC(get_object_type);
+ BASIC_FUNC(get_object_raw);
+ return 1;
+}