summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--Makefile26
-rw-r--r--lib/gall/ll/git2.c317
-rw-r--r--lib/gall/object.lua9
-rw-r--r--lib/gall/repository.lua61
-rw-r--r--lib/gall/tree.lua14
m---------libgit20
m---------luagit20
-rw-r--r--test/test-gall.repository.lua2
9 files changed, 369 insertions, 63 deletions
diff --git a/.gitmodules b/.gitmodules
index 8734ea9..6f8f2a5 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,9 +1,6 @@
[submodule "libgit2"]
path = libgit2
url = git://git.gitano.org.uk/libgit2.git
-[submodule "luagit2"]
- path = luagit2
- url = git://git.gitano.org.uk/luagit2.git
[submodule "extras/luacov"]
path = extras/luacov
url = git://git.gitano.org.uk/luacov.git
diff --git a/Makefile b/Makefile
index 74ed18d..e844f02 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,15 @@ 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 :=
+CFLAGS := $(INCS) $(OPT) $(WARN) $(DEFS) $(PIC) $(CFLAGS)
+LIBGIT2_LDEPS ?= -lssl -lssh2 -lrt
+LFLAGS := -O1 -g -Llibgit2/build/gall-install/lib -lgit2 $(LIBGIT2_LDEPS) $(LFLAGS)
+
MOD_FILES := $(patsubst %,%.lua,$(subst .,/,$(MODULES)))
install: cmodule
@@ -32,26 +41,21 @@ try-cmodule:
do-cmodule: lib/gall/ll/git2.so
-lib/gall/ll/git2.so: luagit2/build/git2.so
- mkdir -p lib/gall/ll
- cp $< $@
-
-luagit2/build/git2.so: libgit2/build/gall-install-stamp
- mkdir -p luagit2/build
- cd luagit2/build && PKG_CONFIG_PATH="$(shell pwd)/libgit2/build/gall-install/lib/pkgconfig:$(PKG_CONFIG_PATH)" cmake -DCMAKE_C_FLAGS:STRING="$${CMAKE_C_FLAGS} -Dluaopen_git2=luaopen_gall_ll_git2" -DCMAKE_MODULE_LINKER_FLAGS="-lssl" ..
- cd luagit2/build && $(MAKE)
+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)
- cd libgit2/build && $(MAKE) test
+ echo "DISABLED BECAUSE LIBGIT2 AUTHORS ARE MAD: cd libgit2/build && $(MAKE) test"
+ cd libgit2/build && ./libgit2_clar -xonline
cd libgit2/build && $(MAKE) install DESTDIR=""
touch $@
clean:
$(RM) luacov.report.out luacov.report.git2.out luacov.stats.out
- $(RM) -r libgit2/build luagit2/build lib/gall/ll
+ $(RM) -r libgit2/build luagit2/build lib/gall/ll/git2.so
distclean: clean
find . -name "*~" -delete
diff --git a/lib/gall/ll/git2.c b/lib/gall/ll/git2.c
new file mode 100644
index 0000000..27e2450
--- /dev/null
+++ b/lib/gall/ll/git2.c
@@ -0,0 +1,317 @@
+/* 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, const 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_set_symbolic_ref(lua_State *L)
+{
+ git_repository *repo = to_repo(L, 1);
+ git_reference *ref;
+ if (git_reference_symbolic_create(&ref, repo,
+ luaL_checkstring(L, 2),
+ luaL_checkstring(L, 3),
+ 1, NULL, NULL) != 0) {
+ return push_git2_error(L);
+ }
+ git_reference_free(ref);
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+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;
+}
+
+static int L_get_tree_table(lua_State *L)
+{
+ git_repository *repo = to_repo(L, 1);
+ git_oid oid;
+ git_tree *tree;
+ size_t ent;
+ if (parse_oid(L, 2, &oid) != 0)
+ return 2;
+ if (git_tree_lookup(&tree, repo, &oid) != 0)
+ return push_git2_error(L);
+ lua_newtable(L);
+ for (ent = 0; ent < git_tree_entrycount(tree); ++ent) {
+ const git_tree_entry *tree_ent =
+ git_tree_entry_byindex(tree, ent);
+ lua_pushnumber(L, ent+1);
+ lua_newtable(L);
+ lua_pushliteral(L, "name");
+ lua_pushstring(L, git_tree_entry_name(tree_ent));
+ lua_settable(L, -3);
+ lua_pushliteral(L, "sha");
+ format_oid(L, git_tree_entry_id(tree_ent));
+ lua_settable(L, -3);
+ lua_pushliteral(L, "perms");
+ lua_pushnumber(L, git_tree_entry_filemode_raw(tree_ent));
+ lua_settable(L, -3);
+ lua_settable(L, -3);
+ }
+
+ git_tree_free(tree);
+ return 1;
+}
+
+int luaopen_gall_ll_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(set_symbolic_ref);
+ BASIC_FUNC(merge_base);
+ BASIC_FUNC(get_object_size);
+ BASIC_FUNC(get_object_type);
+ BASIC_FUNC(get_object_raw);
+ BASIC_FUNC(get_tree_table);
+ return 1;
+}
diff --git a/lib/gall/object.lua b/lib/gall/object.lua
index bedc6f1..f59fb39 100644
--- a/lib/gall/object.lua
+++ b/lib/gall/object.lua
@@ -23,19 +23,19 @@ local function _objectindex(obj, field)
local blob = blobs[obj]
if field == "type" then
if blob then
- ok, ret = 0, blob:type()
+ ok, ret = 0, ll.git2.get_object_type(blob)
else
ok, ret = repos[obj]:gather("cat-file", "-t", obj.sha)
end
elseif field == "size" then
if blob then
- ok, ret = 0, blob:size()
+ ok, ret = 0, ll.git2.get_object_size(blob)
else
ok, ret = repos[obj]:gather("cat-file", "-s", obj.sha)
end
elseif field == "raw" then
if blob and obj.type ~= "tree" then
- ok, ret = 0, blob:data()
+ ok, ret = 0, ll.git2.get_object_raw(blob)
else
ok, ret = repos[obj]:rawgather("cat-file", (obj.type == "tag" and "tag" or "-p"), obj.sha)
end
@@ -76,8 +76,7 @@ local function _new(repo, sha)
local ret = setmetatable({sha=sha}, objectmeta)
repos[ret] = repo
if ll.git2 then
- local oid = ll.git2.OID.hex(sha)
- blobs[ret] = repo.git2.odb:read(oid)
+ blobs[ret] = ll.git2.get_object(repo.git2.repo, sha)
end
return ret
end
diff --git a/lib/gall/repository.lua b/lib/gall/repository.lua
index 70381cb..38ed398 100644
--- a/lib/gall/repository.lua
+++ b/lib/gall/repository.lua
@@ -84,14 +84,7 @@ end
if ll.git2 then
function repomethod:get_ref(ref)
- local rref = ll.git2.Reference.lookup(self.git2.repo, ref)
- if not rref then
- return nil
- end
- if rref:type() ~= ll.git2.REF_OID then
- return nil
- end
- return tostring(rref:oid())
+ return ll.git2.lookup_sha_from_ref(self.git2.repo, ref)
end
end
@@ -153,15 +146,9 @@ function repomethod:normalise(sha)
else
local fullsha
if ll.git2 then
- local refobj = ll.git2.Reference.lookup(self.git2.repo, sha)
+ local refobj = ll.git2.lookup_sha_from_ref(self.git2.repo, sha)
if refobj then
- if refobj:type() == ll.git2.REF_SYMBOLIC then
- refobj = ll.git2.Reference.lookup(self.git2.repo,
- refobj:target())
- end
- if refobj:type() == ll.git2.REF_OID then
- fullsha = tostring(refobj:oid())
- end
+ fullsha = refobj
end
end
if not fullsha then
@@ -228,16 +215,16 @@ if ll.git2 then
commitish_2 = commitish_2.content.object
end
end)
- local oid_1 = ll.git2.OID.hex(commitish_1.sha)
- local oid_2 = ll.git2.OID.hex(commitish_2.sha)
- local oid_base, err = ll.git2.merge.base(self.git2.repo, oid_1, oid_2)
+ local oid_base, err = ll.git2.merge_base(self.git2.repo,
+ commitish_1.sha,
+ commitish_2.sha)
if not oid_base then
if tostring(err) == "ENOTFOUND" then
return true
end
return nil, err
end
- return tostring(oid_base), err
+ return oid_base, err
end
end
@@ -282,17 +269,18 @@ end
if ll.git2 then
function repomethod:symbolic_ref(name, toref)
- local symref = ll.git2.Reference.lookup(self.git2.repo, name)
- if not symref then
- return nil, "No such ref: " .. tostring(toref)
- end
- if symref:type() ~= ll.git2.REF_SYMBOLIC then
- return false
- end
if toref then
- symref:set_target(toref)
+ -- Set the ref...
+ local ok, err = ll.git2.set_symbolic_ref(self.git2.repo, name, toref)
+ if not ok then
+ return nil, err
+ end
end
- return true, symref:target()
+ local symref, err = ll.git2.lookup_symbolic_ref(self.git2.repo, name)
+ if not symref then
+ return nil, "No such ref: " .. tostring(toref) .. " (" .. err .. ")"
+ end
+ return true, symref
end
end
@@ -305,6 +293,8 @@ function repomethod:config(confname, value)
end
end
+--[[
+-- TODO: Add config support to git2.c and convert this
if ll.git2 then
local old_config = repomethod.config
function repomethod:config(confname, value)
@@ -325,6 +315,7 @@ if ll.git2 then
end
end
end
+]]
local repomt = {
__index = repomethod,
@@ -350,14 +341,12 @@ local function _new(path)
local symref
if ll.git2 then
- local git2, msg = ll.git2.Repository(repopath)
+ local git2, msg = ll.git2.open_repo(repopath)
if not git2 then
return nil, "Unable to find Git repository at " .. path
end
- local odb = git2:odb()
- retrepo.git2 = { repo = git2, odb = odb }
- symref = ll.git2.Reference.lookup(git2, "HEAD")
- symref = symref:target()
+ retrepo.git2 = { repo = git2 }
+ symref = ll.git2.lookup_symbolic_ref(git2, "HEAD")
else
ok, symref = ll.symbolic_ref { "-q", "HEAD", stderr=true, repo=repopath }
if ok ~= 0 then
@@ -370,6 +359,8 @@ local function _new(path)
retrepo.work = workpath
retrepo.HEAD = symref
+--[[
+-- This seems redundant
if ll.git2 then
local git2, msg = ll.git2.Repository(retrepo.path)
if not git2 then
@@ -378,7 +369,7 @@ local function _new(path)
local odb = git2:odb()
retrepo.git2 = { repo = git2, odb = odb }
end
-
+--]]
return setmetatable(retrepo, repomt)
end
diff --git a/lib/gall/tree.lua b/lib/gall/tree.lua
index 14d75ba..a44b333 100644
--- a/lib/gall/tree.lua
+++ b/lib/gall/tree.lua
@@ -107,14 +107,12 @@ if ll.git2 then
end
if not parsed[tree] then
- local repo = repos[tree]
- local oid = ll.git2.OID.hex(objs[tree].sha)
- local treeobj = ll.git2.Tree.lookup(repo.git2.repo, oid)
- for i = 0, treeobj:entrycount() - 1 do
- local entry = treeobj:entry_byindex(i)
- local perm = string.format('0x%08X', entry:filemode())
- local sha = tostring(entry:id())
- local name = entry:name()
+ local treetab = ll.git2.get_tree_table(repos[tree].git2.repo,
+ objs[tree].sha)
+ for _, tab in ipairs(treetab) do
+ local perm = string.format('0x%08X', tab.perms)
+ local sha = tab.sha
+ local name = tab.name
local obj = repos[tree]:get(sha)
local type = obj.type
local t = {
diff --git a/libgit2 b/libgit2
-Subproject 9f20b6d32ce9e971a251dca6b4e41a574bb3511
+Subproject b4d00c1d2466de3558a7cc6983dce4eb2ee9843
diff --git a/luagit2 b/luagit2
deleted file mode 160000
-Subproject 8ad8200fd7e40095f152b4a3a44da12c8ee817d
diff --git a/test/test-gall.repository.lua b/test/test-gall.repository.lua
index 0f59993..12f2f46 100644
--- a/test/test-gall.repository.lua
+++ b/test/test-gall.repository.lua
@@ -268,7 +268,7 @@ end
function suite.symbolic_ref_not_symbolic()
local repo = test_repo()
local ok, ref = repo:symbolic_ref "refs/heads/master"
- assert(ok == false)
+ assert(not ok)
end
function suite.symbolic_ref_bad_name()