From 66188bf99eac268e7f651a54dcbf164660ef8bd2 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 23 Aug 2014 19:13:02 +0100 Subject: Basic dodgy version of a git2 binding --- Makefile | 17 +++- lib/gall/ll/git2.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 lib/gall/ll/git2.c 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 + */ + +#include +#include +#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; +} -- cgit v1.2.1