summaryrefslogtreecommitdiff
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
parent608b3456b218ea0f7c8d37412b3a541680e6638e (diff)
downloadgall-66188bf99eac268e7f651a54dcbf164660ef8bd2.tar.gz
Basic dodgy version of a git2 binding
-rw-r--r--Makefile17
-rw-r--r--lib/gall/ll/git2.c268
2 files changed, 283 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 49336d9..0afd01b 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,16 @@ INST_BASE := $(PREFIX)
INST_ROOT := $(DESTDIR)$(INST_BASE)/share/lua/$(LUA_VER)
C_INST_ROOT := $(DESTDIR)$(INST_BASE)/lib/lua/$(LUA_VER)
+INCS := -I/usr/include/lua$(LUA_VER) -Ilibgit2/build/gall-install/include
+OPT := -O0 -g
+PIC := -fPIC
+WARN := -Wall -Werror
+DEFS := -D'LUA_INTERP_NAME="$(LUA_INTERP_NAME)"' \
+ -D'LUA_INTERP_PATH="$(LUA_INTERP_PATH)"'
+CFLAGS := $(INCS) $(OPT) $(WARN) $(DEFS) $(PIC) $(CFLAGS)
+LIBGIT2_LDEPS ?= -lssl -lrt
+LFLAGS := -O1 -g -Llibgit2/build/gall-install/lib -lgit2 $(LIBGIT2_LDEPS) $(LFLAGS)
+
MOD_FILES := $(patsubst %,%.lua,$(subst .,/,$(MODULES)))
install: cmodule
@@ -30,11 +40,14 @@ cmodule: try-cmodule
try-cmodule:
-@$(MAKE) --no-print-directory do-cmodule
-do-cmodule: libgit2/build/gall-install-stamp
+do-cmodule: lib/gall/ll/git2.so
+
+lib/gall/ll/git2.so: libgit2/build/gall-install-stamp lib/gall/ll/git2.c
+ $(CC) $(CFLAGS) lib/gall/ll/git2.c -o $@ -shared $(LFLAGS)
libgit2/build/gall-install-stamp:
mkdir -p libgit2/build
- cd libgit2/build && cmake -DBUILD_SHARED_LIBS:BOOLEAN=OFF -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/libgit2/build/gall-install ..
+ cd libgit2/build && cmake -DBUILD_SHARED_LIBS:BOOLEAN=OFF -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/libgit2/build/gall-install -DCMAKE_C_FLAGS=-fPIC ..
cd libgit2/build && $(MAKE)
echo "DISABLED BECAUSE LIBGIT2 AUTHORS ARE MAD: cd libgit2/build && $(MAKE) test"
cd libgit2/build && ./libgit2_clar -xonline
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;
+}