From af56a49dc72ef1c4d12f43132d0dd6243b22129b Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Fri, 11 May 2012 22:47:08 -0700 Subject: Fix support for ODB custom backends. --- git2.nobj.lua | 2 +- src/database_backend.nobj.lua | 198 ----------------------------------- src/object.nobj.lua | 6 ++ src/odb.nobj.lua | 2 - src/odb_backend.nobj.lua | 236 ++++++++++++++++++++++++++++++++++++++++++ tests/test_backend.lua | 90 ++++++++-------- 6 files changed, 291 insertions(+), 243 deletions(-) delete mode 100644 src/database_backend.nobj.lua create mode 100644 src/odb_backend.nobj.lua diff --git a/git2.nobj.lua b/git2.nobj.lua index 8ad1b29..fac7d14 100644 --- a/git2.nobj.lua +++ b/git2.nobj.lua @@ -64,7 +64,7 @@ subfiles { "src/oid.nobj.lua", "src/oid_shorten.nobj.lua", "src/odb.nobj.lua", ---"src/database_backend.nobj.lua", +"src/odb_backend.nobj.lua", "src/index.nobj.lua", "src/index_entry.nobj.lua", "src/index_entry_unmerged.nobj.lua", diff --git a/src/database_backend.nobj.lua b/src/database_backend.nobj.lua deleted file mode 100644 index 57c83c3..0000000 --- a/src/database_backend.nobj.lua +++ /dev/null @@ -1,198 +0,0 @@ --- Copyright (c) 2010 by Robert G. Jakabosky --- --- Permission is hereby granted, free of charge, to any person obtaining a copy --- of this software and associated documentation files (the "Software"), to deal --- in the Software without restriction, including without limitation the rights --- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell --- copies of the Software, and to permit persons to whom the Software is --- furnished to do so, subject to the following conditions: --- --- The above copyright notice and this permission notice shall be included in --- all copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN --- THE SOFTWARE. - -object "DatabaseBackend" { - c_source [[ -//typedef struct RawObject RawObject; -#include - -typedef struct DatabaseBackend { - git_odb_backend backend; - lua_State *L; - int read; - int read_header; - int write; - int exists; - int free; - int ref_count; -} DatabaseBackend; - -static void DatabaseBackend_ref(DatabaseBackend *backend) { - backend->ref_count++; -} - -static void DatabaseBackend_unref(DatabaseBackend *backend) { - lua_State *L = backend->L; - if((--backend->ref_count) == 0) { - luaL_unref(L, LUA_REGISTRYINDEX, backend->read); - luaL_unref(L, LUA_REGISTRYINDEX, backend->read_header); - luaL_unref(L, LUA_REGISTRYINDEX, backend->write); - luaL_unref(L, LUA_REGISTRYINDEX, backend->exists); - luaL_unref(L, LUA_REGISTRYINDEX, backend->free); - free(backend); - } -} - -static int database_backend_read_cb(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid) -{ - DatabaseBackend *lua_backend = (DatabaseBackend *)backend; - lua_State *L = lua_backend->L; - int err; - - /* get Lua callback function. */ - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->read); - - obj_type_OID_push(L, *((OID *)oid), 0); - /* call Lua function. */ - lua_call(L, 1, 2); - err = lua_tointeger(L, -1); - if(err == 0) { - RawObject *raw_obj = obj_type_RawObject_check(L,-2); - /* copy header fields. */ - obj->len = raw_obj->git.len; - obj->type = raw_obj->git.type; - /* we must malloc & copy the RawObject's data. */ - if(raw_obj->git.data) { - obj->data = malloc(obj->len); - if(obj->data == NULL) { - /* failed to allocate buffer. */ - return GIT_ENOMEM; - } - /* copy data. */ - memcpy(obj->data, raw_obj->git.data, obj->len); - } else { - obj->data = NULL; - } - } - - return err; -} - -static int database_backend_read_header_cb(git_rawobj *obj, git_odb_backend *backend, const git_oid *oid) -{ - DatabaseBackend *lua_backend = (DatabaseBackend *)backend; - lua_State *L = lua_backend->L; - int err; - - /* get Lua callback function. */ - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->read_header); - - obj_type_OID_push(L, *((OID *)oid), 0); - /* call Lua function. */ - lua_call(L, 1, 2); - err = lua_tointeger(L, -1); - if(err == 0) { - RawObject *raw_obj = obj_type_RawObject_check(L,-2); - /* copy only header fields. */ - obj->data = NULL; - obj->len = raw_obj->git.len; - obj->type = raw_obj->git.type; - } - - return err; -} - -static int database_backend_write_cb(git_oid *oid, git_odb_backend *backend, git_rawobj *obj) -{ - DatabaseBackend *lua_backend = (DatabaseBackend *)backend; - lua_State *L = lua_backend->L; - RawObject raw; - int err; - - /* get Lua callback function. */ - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->write); - - /* convert git_rawobj to RawObject */ - RawObject_from_git_rawobj(L, &raw, obj, 0); - /* push RawObject onto stack. */ - obj_type_RawObject_push(L, &raw, 0); - - /* call Lua function. */ - lua_call(L, 1, 2); - err = lua_tointeger(L, -1); - if(err == 0) { - *oid = obj_type_OID_check(L,-2); - } - - return err; -} - -static int database_backend_exists_cb(git_odb_backend *backend, const git_oid *oid) -{ - DatabaseBackend *lua_backend = (DatabaseBackend *)backend; - lua_State *L = lua_backend->L; - - /* get Lua callback function. */ - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->exists); - - obj_type_OID_push(L, *((OID *)oid), 0); - /* call Lua function. */ - lua_call(L, 1, 1); - return lua_tointeger(L, -1); -} - -static void database_backend_free_cb(git_odb_backend *backend) -{ - DatabaseBackend *lua_backend = (DatabaseBackend *)backend; - lua_State *L = lua_backend->L; - - /* get Lua callback function. */ - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->free); - - /* call Lua function. */ - lua_call(L, 0, 0); - - DatabaseBackend_unref(lua_backend); -} - -]], - constructor { - var_in{"lua_State *", "L"}, - c_source [[ - int idx; - int ref; - - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); - /* create backend object. */ - ${this} = calloc(1, sizeof(DatabaseBackend)); - ${this}->ref_count = 1; - ${this}->L = L; - /* get each callback from table. */ -#define REF_CB(_name) \ - lua_getfield(L, 1, "on_" #_name); \ - ${this}->_name = luaL_ref(L, LUA_REGISTRYINDEX); \ - ${this}->backend._name = database_backend_ ## _name ## _cb; - - REF_CB(read) - REF_CB(read_header) - REF_CB(write) - REF_CB(exists) - REF_CB(free) -#undef REF_CB -]] - }, - destructor { - c_source [[ - DatabaseBackend_unref(${this}); -]] - }, -} - diff --git a/src/object.nobj.lua b/src/object.nobj.lua index 30658bf..b8e5cb9 100644 --- a/src/object.nobj.lua +++ b/src/object.nobj.lua @@ -46,5 +46,11 @@ typedef git_object Object; method "owner" { c_method_call "Repository *" "git_object_owner" {} }, + c_function "type2string" { + c_call "const char *" "git_object_type2string" { "git_otype", "otype" }, + }, + c_function "string2type" { + c_call "git_otype" "git_object_string2type" { "const char *", "str" }, + }, } diff --git a/src/odb.nobj.lua b/src/odb.nobj.lua index 1d706b4..d68d159 100644 --- a/src/odb.nobj.lua +++ b/src/odb.nobj.lua @@ -32,7 +32,6 @@ typedef git_odb ODB; destructor "free" { c_method_call "void" "git_odb_free" {} }, - --[=[ method "add_backend" { var_in{"ODBBackend *", "backend"}, var_in{"int", "priority"}, @@ -51,7 +50,6 @@ typedef git_odb ODB; ODBBackend_ref(${backend}); ]], }, - --]=] method "read" { c_call "GitError" "git_odb_read" { "!OdbObject *", "&out>1", "ODB *", "this", "OID", "&id"}, diff --git a/src/odb_backend.nobj.lua b/src/odb_backend.nobj.lua new file mode 100644 index 0000000..4e8d9a5 --- /dev/null +++ b/src/odb_backend.nobj.lua @@ -0,0 +1,236 @@ +-- Copyright (c) 2010 by Robert G. Jakabosky +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +-- THE SOFTWARE. + +object "ODBBackend" { + c_source [[ +#include + +typedef struct ODBBackend { + git_odb_backend backend; + lua_State *L; + int read; + int read_prefix; + int read_header; + int write; + int exists; + int free; + int ref_count; +} ODBBackend; + +static void ODBBackend_ref(ODBBackend *backend) { + backend->ref_count++; +} + +static void ODBBackend_unref(ODBBackend *backend) { + lua_State *L = backend->L; + if((--backend->ref_count) == 0) { + luaL_unref(L, LUA_REGISTRYINDEX, backend->read); + luaL_unref(L, LUA_REGISTRYINDEX, backend->read_prefix); + luaL_unref(L, LUA_REGISTRYINDEX, backend->read_header); + luaL_unref(L, LUA_REGISTRYINDEX, backend->write); + luaL_unref(L, LUA_REGISTRYINDEX, backend->exists); + luaL_unref(L, LUA_REGISTRYINDEX, backend->free); + free(backend); + } +} + +static int odb_backend_read_cb(void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) +{ + ODBBackend *lua_backend = (ODBBackend *)backend; + lua_State *L = lua_backend->L; + const char *ldata; + size_t len; + int err; + + /* get Lua callback function. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->read); + + obj_type_OID_push(L, *((OID *)oid)); + /* call Lua function. */ + lua_call(L, 1, 2); + ldata = lua_tolstring(L, -2, &len); + if(ldata) { + char *data; + /* parse otype value. */ + int arg_type = lua_type(L, -1); + if(arg_type == LUA_TNUMBER) { + *type_p = lua_tointeger(L, -1); + } else if(arg_type == LUA_TSTRING) { + *type_p = git_object_string2type(lua_tostring(L, -1)); + } + *len_p = len; + /* allocate buffer for data. */ + data = malloc(len); + *data_p = data; + if(data == NULL) { + return GIT_ENOMEM; + } + /* copy data. */ + memcpy(data, ldata, len); + err = GIT_SUCCESS; + } else if(lua_isnil(L, -2)) { + *data_p = NULL; + /* backend returned an error. */ + err = lua_tointeger(L, -1); + } else { + *data_p = NULL; + /* bad return value from lua backend. */ + err = GIT_EOBJTYPE; + } + + return err; +} + +static int odb_backend_read_prefix_cb(git_oid *out_oid, void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *short_oid, unsigned int len) +{ + *data_p = NULL; + if(len >= GIT_OID_HEXSZ) { + int rc = odb_backend_read_cb(data_p, len_p, type_p, backend, short_oid); + if(rc == GIT_SUCCESS) { + git_oid_cpy(out_oid, short_oid); + } + return rc; + } + return GIT_ENOTIMPLEMENTED; +} + +static int odb_backend_read_header_cb(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid) +{ + ODBBackend *lua_backend = (ODBBackend *)backend; + lua_State *L = lua_backend->L; + int err; + int arg_type; + + /* get Lua callback function. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->read_header); + + obj_type_OID_push(L, *((OID *)oid)); + /* call Lua function. */ + lua_call(L, 1, 2); + + arg_type = lua_type(L, -2); + if(arg_type == LUA_TSTRING || arg_type == LUA_TNUMBER) { + /* parse data length. */ + *len_p = lua_tonumber(L, -2); + /* parse otype value. */ + lua_type(L, -1); + if(arg_type == LUA_TNUMBER) { + *type_p = lua_tointeger(L, -1); + } else if(arg_type == LUA_TSTRING) { + *type_p = git_object_string2type(lua_tostring(L, -1)); + } + err = GIT_SUCCESS; + } else if(arg_type == LUA_TNIL) { + /* backend returned an error. */ + err = lua_tointeger(L, -1); + } else { + /* bad return value from lua backend. */ + err = GIT_EOBJTYPE; + } + + return err; +} + +static int odb_backend_write_cb(git_oid *oid, git_odb_backend *backend, const void *data, size_t len, git_otype type) +{ + ODBBackend *lua_backend = (ODBBackend *)backend; + lua_State *L = lua_backend->L; + int err; + + /* get Lua callback function. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->write); + + /* push data onto stack. */ + lua_pushlstring(L, data, len); + /* push otype */ + lua_pushstring(L, git_object_type2string(type)); + + /* call Lua function. */ + lua_call(L, 2, 2); + if(!lua_isnil(L, -2)) { + *oid = obj_type_OID_check(L,-2); + err = GIT_SUCCESS; + } else { + err = lua_tointeger(L, -1); + } + + return err; +} + +static int odb_backend_exists_cb(git_odb_backend *backend, const git_oid *oid) +{ + ODBBackend *lua_backend = (ODBBackend *)backend; + lua_State *L = lua_backend->L; + + /* get Lua callback function. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->exists); + + obj_type_OID_push(L, *((OID *)oid)); + /* call Lua function. */ + lua_call(L, 1, 1); + return lua_tointeger(L, -1); +} + +static void odb_backend_free_cb(git_odb_backend *backend) +{ + ODBBackend *lua_backend = (ODBBackend *)backend; + lua_State *L = lua_backend->L; + + /* get Lua callback function. */ + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_backend->free); + + /* call Lua function. */ + lua_call(L, 0, 0); + + ODBBackend_unref(lua_backend); +} + +]], + constructor { + var_in{"lua_State *", "L"}, + c_source [[ + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); + /* create backend object. */ + ${this} = calloc(1, sizeof(ODBBackend)); + ${this}->ref_count = 1; + ${this}->L = L; + /* get each callback from table. */ +#define REF_CB(_name) \ + lua_getfield(L, 1, "on_" #_name); \ + ${this}->_name = luaL_ref(L, LUA_REGISTRYINDEX); \ + ${this}->backend._name = odb_backend_ ## _name ## _cb; + + REF_CB(read) + REF_CB(read_prefix) + REF_CB(read_header) + REF_CB(write) + REF_CB(exists) + REF_CB(free) +#undef REF_CB +]] + }, + destructor { + c_source [[ + ODBBackend_unref(${this}); +]] + }, +} + diff --git a/tests/test_backend.lua b/tests/test_backend.lua index 1af0c72..ba0633a 100644 --- a/tests/test_backend.lua +++ b/tests/test_backend.lua @@ -7,24 +7,23 @@ if ( build_dir ) then package.cpath = build_dir .. "?.so;" .. package.cpath end -require"git2" +local git2 = require"git2" require"utils" print(dump(git2)) -local function dump_rawobj(obj) - print('dump RawObject:', obj) +local function dump_obj(obj) + print('dump OdbObject:', obj) if obj == nil then return end - print('hash = ', obj:hash()) - print('data = "' .. tostring(obj:data()) .. '"') - print('len = ', obj:len()) + print('id = ', obj:id()) print('type = ', obj:type()) end --- create database -local db = assert(git2.Database.new()) -print("dump Database interface") +-- create odb +local db = assert(git2.ODB.new()) +print("=============================================== new db=", db) +print("dump ODB interface") print(dbg_dump(db)) -- create backend @@ -40,62 +39,67 @@ local function get_obj(oid) end local cbs = { on_read = function(oid) - local raw_obj = nil print("------------------- read callback:", oid) - raw_obj = get_obj(oid) - if not raw_obj then + local obj = get_obj(oid) + if not obj then return nil, git2.ENOTFOUND end - return raw_obj, git2.SUCCESS + return obj.data, obj.otype +end, +on_read_prefix = function(short_oid, len) + print("------------------- read_prefix callback:", oid) + local obj = get_obj(short_oid) + if not obj then + if len ~= git2.OID.HEXSZ then + return nil, git2.ENOTIMPLEMENTED + end + return nil, git2.ENOTFOUND + end + return obj.data, obj.otype, short_oid end, on_read_header = function(oid) - local raw_obj = nil print("------------------- read_header callback:", oid) - raw_obj = get_obj(oid) - if not raw_obj then + local obj = get_obj(oid) + if not obj then return nil, git2.ENOTFOUND end - return raw_obj, git2.SUCCESS + return obj.len, obj.otype end, -on_write = function(raw_obj) - local oid = raw_obj:hash() - print("------------------- write callback:", raw_obj) +on_write = function(data, otype) + local oid = git2.ODB.hash(data, git2.Object.string2type(otype)) + print("------------------- write callback:", data, otype) if not oid then return nil, -1 end -- convert oid to string. local oid_str = tostring(oid) -- put raw object in cache - obj_cache[oid_str] = raw_obj - return oid, git2.SUCCESS + obj_cache[oid_str] = { data = data, len = #data, otype = otype} + return oid end, on_exists = function(oid) - local raw_obj = nil print("------------------- exists callback:", oid) - raw_obj = get_obj(oid) - if not raw_obj then - return raw_obj, git2.ENOTFOUND + local obj = get_obj(oid) + if not obj then + return false end - return git2.SUCCESS + return true end, on_free = function() print("------------------- free callback:") end, } -local backend = git2.DatabaseBackend(cbs) +local backend = git2.ODBBackend(cbs) print('add backend:', assert(db:add_backend(backend, 0))) -print('create test blob:') -local raw_obj = git2.RawObject.new('blob',"any ol content will do") - -print("test writing RawObject to database:") -local oid, err = db:write(raw_obj) +print("test writing test blob to odb:") +local oid, err = db:write("any ol content will do", 'blob') print('write:', oid, err) print() -print("test reading RawObjects from database:") +print("test reading RawObjects from odb:") local object_ids = { {'tree', "31f3d5703ce27f0b63c3eb0d829abdc95b51deae"}, {'commit', "d5a93c463d4cca0068750eb6af7b4b54eea8599b"}, @@ -103,10 +107,10 @@ local object_ids = { {'blob', "275a4019807c7bb7bc80c0ca8903bf84345e1bdf"}, } for _,obj in ipairs(object_ids) do - local oid = git2.OID.str(obj[2]) - local raw_obj, err = db:read(oid) - print('read', raw_obj, err) - dump_rawobj(raw_obj) + local oid = git2.OID.hex(obj[2]) + local obj, err = db:read(oid) + print('read', obj, err) + dump_obj(obj) print() end @@ -119,9 +123,10 @@ if not status then else print("Created repository with no backends from git repository:", git_path) end -db = rep:database() -backend = git2.DatabaseBackend(cbs) -print("add backend repository's database:", assert(db:add_backend(backend, 0))) +db = rep:odb() +print("=============================================== repo db=", db) +backend = git2.ODBBackend(cbs) +print("add backend repository's odb:", assert(db:add_backend(backend, 0))) print() print("try reading objects from repository:") @@ -132,7 +137,7 @@ local object_ids = { {'blob', "275a4019807c7bb7bc80c0ca8903bf84345e1bdf"}, } for _,obj in ipairs(object_ids) do - local oid = git2.OID.str(obj[2]) + local oid = git2.OID.hex(obj[2]) local obj, err = rep:lookup(oid, obj[1]) print('read', obj, err) print() @@ -140,6 +145,7 @@ end db = nil backend = nil +obj_cache = nil collectgarbage"collect" collectgarbage"collect" -- cgit v1.2.1