From b5b68cce8b92ca0e7bd48430617ac10c0f2c2923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 2 Mar 2013 02:56:58 +0100 Subject: [PATCH] Allow getting a tree entry --- c_src/geef.c | 3 +- c_src/object.c | 9 ++++-- c_src/object.h | 6 +++- c_src/tree.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ c_src/tree.h | 8 +++++ src/geef.erl | 6 +++- src/geef_records.hrl | 2 ++ src/geef_tree.erl | 28 ++++++++++++++++++ 8 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 c_src/tree.c create mode 100644 c_src/tree.h create mode 100644 src/geef_tree.erl diff --git a/c_src/geef.c b/c_src/geef.c index 6dbd1a6..e742869 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -4,6 +4,7 @@ #include "oid.h" #include "object.h" #include "commit.h" +#include "tree.h" #include "geef.h" #include #include @@ -43,7 +44,6 @@ static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info) if (geef_repository_type == NULL) return -1; - atoms.ok = enif_make_atom(env, "ok"); atoms.error = enif_make_atom(env, "error"); atoms.true = enif_make_atom(env, "true"); @@ -100,6 +100,7 @@ static ErlNifFunc geef_funcs[] = {"object_lookup", 2, geef_object_lookup}, {"commit_tree", 1, geef_commit_tree}, {"commit_tree_id", 1, geef_commit_tree_id}, + {"tree_bypath", 2, geef_tree_bypath}, }; ERL_NIF_INIT(geef, geef_funcs, load, NULL, NULL, unload) diff --git a/c_src/object.c b/c_src/object.c index adcaf97..00de74e 100644 --- a/c_src/object.c +++ b/c_src/object.c @@ -8,12 +8,13 @@ void geef_object_free(ErlNifEnv *env, void *cd) { geef_object *obj = (geef_object *) cd; + enif_release_resource(obj->repo); git_object_free(obj->obj); } -static ERL_NIF_TERM object_type(git_object *obj) +ERL_NIF_TERM geef_object_type2atom(const git_otype type) { - switch(git_object_type(obj)) { + switch(type) { case GIT_OBJ_COMMIT: return atoms.commit; case GIT_OBJ_TREE: @@ -57,6 +58,8 @@ geef_object_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) term_obj = enif_make_resource(env, obj); enif_release_resource(obj); + obj->repo = repo; + enif_keep_resource(repo); - return enif_make_tuple3(env, atoms.ok, object_type(obj->obj), term_obj); + return enif_make_tuple3(env, atoms.ok, geef_object_type2atom(git_object_type(obj->obj)), term_obj); } diff --git a/c_src/object.h b/c_src/object.h index 15be0d9..31bc2c8 100644 --- a/c_src/object.h +++ b/c_src/object.h @@ -3,15 +3,19 @@ #include "erl_nif.h" #include +#include "repository.h" extern ErlNifResourceType *geef_object_type; typedef struct { - git_object *obj; + git_object *obj; + geef_repository *repo; } geef_object; ERL_NIF_TERM geef_object_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM geef_object_type2atom(const git_otype type); + void geef_object_free(ErlNifEnv *env, void *cd); #endif diff --git a/c_src/tree.c b/c_src/tree.c new file mode 100644 index 0000000..1f7cfca --- /dev/null +++ b/c_src/tree.c @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "oid.h" +#include "geef.h" +#include "tree.h" + +static int geef_string_bin(ErlNifBinary *bin, const char *str) +{ + size_t len; + + len = strlen(str); + if (!enif_alloc_binary(len, bin)) + return -1; + + memcpy(bin->data, str, len); + + return 0; +} + +static ERL_NIF_TERM tree_entry_to_term(ErlNifEnv *env, const git_tree_entry *entry) +{ + ErlNifBinary name, oid; + + if (geef_oid_bin(&oid, git_tree_entry_id(entry)) < 0) + return atoms.error; + + if (geef_string_bin(&name, git_tree_entry_name(entry)) < 0) { + enif_release_binary(&name); + return atoms.error; + } + + return enif_make_tuple5(env, atoms.ok, enif_make_int(env, git_tree_entry_filemode(entry)), + geef_object_type2atom(git_tree_entry_type(entry)), + enif_make_binary(env, &oid), enif_make_binary(env, &name)); + +} + +ERL_NIF_TERM +geef_tree_bypath(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + char *path; + int error; + geef_object *obj; + ErlNifBinary bin; + git_tree_entry *entry; + + if (!enif_get_resource(env, argv[0], geef_object_type, (void **) &obj)) + return enif_make_badarg(env); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &bin)) + return enif_make_badarg(env); + + path = malloc(bin.size + 1); + if (!path) + return atoms.error; + + memcpy(path, bin.data, bin.size); + path[bin.size] = '\0'; + + error = git_tree_entry_bypath(&entry, (git_tree *)obj->obj, path); + free(path); + + if (error < 0) + return geef_error(env); + + return tree_entry_to_term(env, entry); +} diff --git a/c_src/tree.h b/c_src/tree.h new file mode 100644 index 0000000..de553e2 --- /dev/null +++ b/c_src/tree.h @@ -0,0 +1,8 @@ +#ifndef GEEF_TREE_H +#define GEEF_TREE_H + +#include "object.h" + +ERL_NIF_TERM geef_tree_bypath(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + +#endif diff --git a/src/geef.erl b/src/geef.erl index 3723462..6040eed 100644 --- a/src/geef.erl +++ b/src/geef.erl @@ -11,7 +11,7 @@ -export([oid_fmt/1, oid_parse/1]). % objects --export([object_lookup/2, commit_tree_id/1, commit_tree/1]). +-export([object_lookup/2, commit_tree_id/1, commit_tree/1, tree_bypath/2]). -on_load(load_enif/0). @@ -82,6 +82,10 @@ commit_tree_id(_Handle) -> commit_tree(_Handle) -> nif_error(?LINE). +-spec tree_bypath(term, iolist()) -> term(). +tree_bypath(_TreeHandle, _Path) -> + nif_error(?LINE). + nif_error(Line) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/src/geef_records.hrl b/src/geef_records.hrl index a8eb869..99b313f 100644 --- a/src/geef_records.hrl +++ b/src/geef_records.hrl @@ -3,9 +3,11 @@ -record(odb, {handle}). -record(oid, {oid}). -record(object, {type :: atom(), handle}). +-record(tree_entry, {mode, type :: atom(), id :: oid(), name :: binary()}). -type ref() :: #ref{}. -type repo() :: #repo{}. -type odb() :: #odb{}. -type oid() :: #oid{}. -type object() :: #object{}. +-type tree_entry() :: #tree_entry{}. diff --git a/src/geef_tree.erl b/src/geef_tree.erl new file mode 100644 index 0000000..e97cac3 --- /dev/null +++ b/src/geef_tree.erl @@ -0,0 +1,28 @@ +-module(geef_tree). + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. + +-export([bypath/2]). + +-include("geef_records.hrl"). + +bypath(#object{type=tree,handle=Handle}, Path) -> + case geef:tree_bypath(Handle, Path) of + {ok, Mode, Type, Id, Name} -> + {ok, #tree_entry{mode=Mode, type=Type, id=geef_oid:parse(Id), name=Name}}; + other -> + other + end. + +-ifdef(TEST). + +%% This is somewhat hacky, assuming that this is running under .eunit, +%% but it's good enough for now +bypath_test() -> + {ok, Repo} = geef_repo:open(".."), + {ok, Tree} = geef_object:lookup(Repo, geef_oid:parse("395e1c39cb203640b78da8458a42afdb92bef7aa")), + {ok, #tree_entry{type=blob, name= <<"README.md">>}} = geef_tree:bypath(Tree, "README.md"). + +-endif.