diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2014-08-23 19:13:02 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2014-08-23 19:13:02 +0100 |
commit | 66188bf99eac268e7f651a54dcbf164660ef8bd2 (patch) | |
tree | 3813eb907b889c37df7c9675a1b75f3eb50f8321 /lib | |
parent | 608b3456b218ea0f7c8d37412b3a541680e6638e (diff) | |
download | gall-66188bf99eac268e7f651a54dcbf164660ef8bd2.tar.gz |
Basic dodgy version of a git2 binding
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gall/ll/git2.c | 268 |
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; +} |