Merge branch 'pure-ref'

This commit is contained in:
Carlos Martín Nieto
2013-08-31 17:34:48 +02:00
7 changed files with 187 additions and 199 deletions

View File

@@ -18,7 +18,6 @@
ErlNifResourceType *geef_repository_type;
ErlNifResourceType *geef_odb_type;
ErlNifResourceType *geef_ref_type;
ErlNifResourceType *geef_ref_iter_type;
ErlNifResourceType *geef_object_type;
ErlNifResourceType *geef_revwalk_type;
@@ -42,12 +41,6 @@ static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
if (geef_odb_type == NULL)
return -1;
geef_ref_type = enif_open_resource_type(env, NULL,
"ref_type", geef_ref_free, ERL_NIF_RT_CREATE, NULL);
if (geef_ref_type == NULL)
return -1;
geef_ref_iter_type = enif_open_resource_type(env, NULL,
"ref_iter_type", geef_ref_iter_free, ERL_NIF_RT_CREATE, NULL);
@@ -160,10 +153,7 @@ static ErlNifFunc geef_funcs[] =
{"reference_lookup", 2, geef_reference_lookup},
{"reference_iterator", 2, geef_reference_iterator},
{"reference_next", 1, geef_reference_next},
{"reference_resolve", 1, geef_reference_resolve},
{"reference_target", 1, geef_reference_target},
{"reference_type", 1, geef_reference_type},
{"reference_name", 1, geef_reference_name},
{"reference_resolve", 2, geef_reference_resolve},
{"reference_create", 5, geef_reference_create},
{"reference_dwim", 2, geef_reference_dwim},
{"oid_fmt", 1, geef_oid_fmt},

View File

@@ -40,14 +40,59 @@ on_error:
return geef_oom(env);
}
static int ref_target(ERL_NIF_TERM *out, ErlNifEnv *env, git_reference *ref)
{
ErlNifBinary bin;
if (git_reference_type(ref) == GIT_REF_OID) {
const git_oid *id;
id = git_reference_target(ref);
if (geef_oid_bin(&bin, id) < 0)
return -1;
} else {
const char *name;
size_t len;
name = git_reference_symbolic_target(ref);
len = strlen(name);
if (enif_alloc_binary(len, &bin) < 0)
return -1;
memcpy(bin.data, name, len);
}
*out = enif_make_binary(env, &bin);
return 0;
}
static ERL_NIF_TERM ref_type(git_reference *ref)
{
ERL_NIF_TERM type;
switch (git_reference_type(ref)) {
case GIT_REF_OID:
type = atoms.oid;
break;
case GIT_REF_SYMBOLIC:
type = atoms.symbolic;
break;
default:
type = atoms.error;
break;
}
return type;
}
ERL_NIF_TERM
geef_reference_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_repository *repo;
geef_ref *res_ref;
git_reference *ref;
git_reference *ref = NULL;
ERL_NIF_TERM target, type;
ErlNifBinary bin;
ERL_NIF_TERM term_ref;
int error;
if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo))
@@ -57,20 +102,24 @@ geef_reference_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
if (!geef_terminate_binary(&bin))
return geef_oom(env);
goto on_oom;
error = git_reference_lookup(&ref, repo->repo, (char *)bin.data);
enif_release_binary(&bin);
if (error < 0)
return geef_error(env);
res_ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref));
res_ref->ref = ref;
term_ref = enif_make_resource(env, res_ref);
enif_release_resource(res_ref);
type = ref_type(ref);
if (ref_target(&target, env, ref) < 0)
goto on_oom;
return enif_make_tuple2(env, atoms.ok, term_ref);
return enif_make_tuple3(env, atoms.ok, type, target);
on_oom:
git_reference_free(ref);
enif_release_binary(&bin);
return geef_oom(env);
}
ERL_NIF_TERM
@@ -120,10 +169,12 @@ ERL_NIF_TERM
geef_reference_next(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
int error;
geef_ref *res_ref;
size_t len;
const char *name;
git_reference *ref;
ErlNifBinary bin;
geef_ref_iter *iter;
ERL_NIF_TERM term_ref;
ERL_NIF_TERM type, target;
if (!enif_get_resource(env, argv[0], geef_ref_iter_type, (void **) &iter))
return enif_make_badarg(env);
@@ -134,12 +185,22 @@ geef_reference_next(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
if (error < 0)
return geef_error(env);
res_ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref));
res_ref->ref = ref;
term_ref = enif_make_resource(env, res_ref);
enif_release_resource(res_ref);
type = ref_type(ref);
if (ref_target(&target, env, ref) < 0) {
git_reference_free(ref);
return geef_oom(env);
}
return enif_make_tuple2(env, atoms.ok, term_ref);
name = git_reference_name(ref);
len = strlen(name);
if (!enif_alloc_binary(len, &bin)) {
git_reference_free(ref);
return geef_oom(env);
}
memcpy(bin.data, name, len);
return enif_make_tuple4(env, atoms.ok, enif_make_binary(env, &bin), type, target);
}
void geef_ref_iter_free(ErlNifEnv *env, void *cd)
@@ -152,31 +213,57 @@ void geef_ref_iter_free(ErlNifEnv *env, void *cd)
ERL_NIF_TERM
geef_reference_resolve(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_ref *in_ref, *res_ref;
ERL_NIF_TERM term_ref;
git_reference *ref;
size_t len;
const char *name;
ErlNifBinary bin, id;
geef_repository *repo;
git_reference *ref, *resolved;
if (!enif_get_resource(env, argv[0], geef_ref_type, (void **) &in_ref))
if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo))
return enif_make_badarg(env);
if (git_reference_resolve(&ref, in_ref->ref) < 0)
if (!enif_inspect_binary(env, argv[1], &bin))
return enif_make_badarg(env);
if (!geef_terminate_binary(&bin))
return geef_oom(env);
if (git_reference_lookup(&ref, repo->repo, (char *) bin.data) < 0)
return geef_error(env);
res_ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref));
res_ref->ref = ref;
term_ref = enif_make_resource(env, res_ref);
enif_release_resource(res_ref);
if (git_reference_resolve(&resolved, ref) < 0)
return geef_error(env);
return enif_make_tuple2(env, atoms.ok, term_ref);
git_reference_free(ref);
name = git_reference_name(resolved);
len = strlen(name);
if (enif_realloc_binary(&bin, len) < 0)
goto on_oom;
memcpy(bin.data, name, len);
if (geef_oid_bin(&id, git_reference_target(resolved)) < 0)
goto on_oom;
git_reference_free(resolved);
return enif_make_tuple3(env, atoms.ok, enif_make_binary(env, &bin), enif_make_binary(env, &id));
on_oom:
git_reference_free(resolved);
return geef_oom(env);
}
ERL_NIF_TERM
geef_reference_dwim(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
geef_ref *ref;
ERL_NIF_TERM term_ref;
ERL_NIF_TERM target, type;
geef_repository *repo;
git_reference *ref;
const char *name;
size_t len;
if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo))
return enif_make_badarg(env);
@@ -187,22 +274,27 @@ geef_reference_dwim(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
if (!geef_terminate_binary(&bin))
return geef_oom(env);
ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref));
if (git_reference_dwim(&ref->ref, repo->repo, (char *)bin.data) < 0) {
if (git_reference_dwim(&ref, repo->repo, (char *)bin.data) < 0) {
enif_release_binary(&bin);
return geef_error(env);
}
term_ref = enif_make_resource(env, ref);
enif_release_resource(ref);
type = ref_type(ref);
if (ref_target(&target, env, ref) < 0) {
git_reference_free(ref);
return geef_oom(env);
}
return enif_make_tuple2(env, atoms.ok, term_ref);
}
name = git_reference_name(ref);
len = strlen(name);
if (!enif_realloc_binary(&bin, len)) {
git_reference_free(ref);
enif_release_binary(&bin);
}
void geef_ref_free(ErlNifEnv *env, void *cd)
{
geef_ref *ref = (geef_ref *) cd;
git_reference_free(ref->ref);
memcpy(bin.data, name, len);
return enif_make_tuple4(env, atoms.ok, enif_make_binary(env, &bin), type, target);
}
struct list_data {
@@ -253,37 +345,6 @@ geef_reference_glob(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return data.list;
}
ERL_NIF_TERM
geef_reference_target(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_ref *ref;
ErlNifBinary bin;
if (!enif_get_resource(env, argv[0], geef_ref_type, (void **) &ref))
return enif_make_badarg(env);
if (git_reference_type(ref->ref) == GIT_REF_OID) {
const git_oid *id;
id = git_reference_target(ref->ref);
if (geef_oid_bin(&bin, id) < 0)
return geef_oom(env);
} else {
const char *name;
size_t len;
name = git_reference_symbolic_target(ref->ref);
len = strlen(name);
if (enif_alloc_binary(len, &bin) < 0)
return geef_oom(env);
memcpy(bin.data, name, len + 1);
}
return enif_make_binary(env, &bin);
}
ERL_NIF_TERM
geef_reference_to_id(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
@@ -309,63 +370,13 @@ geef_reference_to_id(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return enif_make_tuple2(env, atoms.ok, enif_make_binary(env, &bin));
}
ERL_NIF_TERM
geef_reference_type(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_ref *ref;
int type;
ERL_NIF_TERM term_type;
if (!enif_get_resource(env, argv[0], geef_ref_type, (void **) &ref))
return enif_make_badarg(env);
type = git_reference_type(ref->ref);
switch (type) {
case GIT_REF_OID:
term_type = atoms.oid;
break;
case GIT_REF_SYMBOLIC:
term_type = atoms.symbolic;
break;
default:
term_type = atoms.error;
break;
}
return term_type;
}
ERL_NIF_TERM
geef_reference_name(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_ref *ref;
const char *name;
ErlNifBinary bin;
size_t len;
if (!enif_get_resource(env, argv[0], geef_ref_type, (void **) &ref))
return enif_make_badarg(env);
name = git_reference_name(ref->ref);
len = strlen(name);
if (enif_alloc_binary(len, &bin) < 0)
return geef_oom(env);
memcpy(bin.data, name, len + 1);
return enif_make_tuple2(env, atoms.ok, enif_make_binary(env, &bin));
}
ERL_NIF_TERM
geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
geef_repository *repo;
geef_ref *ref;
ErlNifBinary name, target;
ERL_NIF_TERM term_ref;
int error, force;
git_reference *ref;
const char *pname, *ptarget;
if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo))
@@ -380,20 +391,18 @@ geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
if (!geef_terminate_binary(&name))
return geef_oom(env);
ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref));
force = enif_is_identical(argv[4], atoms.true);
pname = (const char *) name.data;
if (enif_is_identical(argv[2], atoms.oid)) {
const git_oid *oid = (const git_oid *) target.data;
error = git_reference_create(&ref->ref, repo->repo, pname, oid, force);
error = git_reference_create(&ref, repo->repo, pname, oid, force);
} else if (enif_is_identical(argv[2], atoms.symbolic)) {
if (!geef_terminate_binary(&target))
return geef_oom(env);
ptarget = (const char *) target.data;
error = git_reference_symbolic_create(&ref->ref, repo->repo, pname, ptarget, force);
error = git_reference_symbolic_create(&ref, repo->repo, pname, ptarget, force);
enif_release_binary(&target);
} else {
enif_release_binary(&target);
@@ -401,14 +410,11 @@ geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return enif_make_badarg(env);
}
git_reference_free(ref);
enif_release_binary(&name);
if (error < 0)
return geef_error(env);
term_ref = enif_make_resource(env, ref);
enif_release_resource(ref);
return enif_make_tuple2(env, atoms.ok, term_ref);
return atoms.ok;
}

View File

@@ -4,13 +4,8 @@
#include "erl_nif.h"
#include <git2.h>
extern ErlNifResourceType *geef_ref_type;
extern ErlNifResourceType *geef_ref_iter_type;
typedef struct {
git_reference *ref;
} geef_ref;
typedef struct {
git_reference_iterator *iter;
geef_repository *repo;
@@ -21,15 +16,11 @@ ERL_NIF_TERM geef_reference_to_id(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
ERL_NIF_TERM geef_reference_glob(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_resolve(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_target(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_type(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_name(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_dwim(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_iterator(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM geef_reference_next(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
void geef_ref_free(ErlNifEnv *env, void *cd);
void geef_ref_iter_free(ErlNifEnv *env, void *cd);
#endif

View File

@@ -49,28 +49,20 @@ reference_to_id(_Repo, _Refname) ->
reference_glob(_Repo, _Glob) ->
nif_error(?LINE).
reference_lookup(_Repo, _Refname) ->
-spec reference_lookup(term(), binary() | iolist()) -> {ok, geef_ref:ref_type(), geef_oid:oid()} | {error, term()}.
reference_lookup(_RepoHandle, _Refname) ->
nif_error(?LINE).
-spec reference_iterator(term(), iolist() | undefined) -> {ok, geef_ref:iterator()} | {error, term()}.
reference_iterator(_Repo, _Regexp) ->
nif_error(?LINE).
-spec reference_next(geef_ref:iterator()) -> {ok, term()} | {error, iterover | term()}.
-spec reference_next(geef_ref:iterator()) -> {ok, binary(), geef_ref:ref_type(), geef_oid:oid() | binary()} | {error, iterover | term()}.
reference_next(_Handle) ->
nif_error(?LINE).
reference_target(_Handle) ->
nif_error(?LINE).
reference_resolve(_Handle) ->
nif_error(?LINE).
reference_type(_Handle) ->
nif_error(?LINE).
-spec reference_name(term()) -> {ok, binary()} | {error, term()}.
reference_name(_Handle) ->
-spec reference_resolve(term(), binary()) -> {ok, geef_oid:oid()} | {error, term()}.
reference_resolve(_RepoHandle, _Name) ->
nif_error(?LINE).
reference_dwim(_Handle, _Name) ->

View File

@@ -1,4 +1,4 @@
-record(geef_reference, {handle, name :: binary(), type :: oid | symbolic, target :: binary() | geef_oid:oid()}).
-record(geef_reference, {repo :: pid(), name :: binary(), type :: geef_ref:type(), target :: geef_ref:target()}).
-record(geef_oid, {oid :: binary()}).
-record(geef_object, {type :: atom(), id :: geef_oid:oid(), handle}).
-record(geef_index_entry,

View File

@@ -5,41 +5,46 @@
-include("geef_records.hrl").
-type iterator() :: #geef_iterator{type :: ref}.
-type type() :: oid | symbolic.
-type target() :: binary | geef_oid:oid().
-type ref() :: #geef_reference{name :: binary()}.
-export_type([reference/0, iterator/0]).
-spec new(term()) -> ref().
new(Handle) ->
{ok, Name} = geef_nif:reference_name(Handle),
new(Name, Handle).
-spec new(binary(), term()) -> ref().
new(Name, Handle) ->
Type = geef_nif:reference_type(Handle),
Bin = geef_nif:reference_target(Handle),
Target = case Type of
symbolic ->
Bin;
oid ->
#geef_oid{oid=Bin}
end,
#geef_reference{handle=Handle, name=Name, type=Type, target=Target}.
-spec create(pid(), iolist(), geef_oid:oid() | binary(), boolean()) -> {ok, ref()} | {error, term()}.
-spec create(pid(), iolist(), target(), boolean()) -> {ok, ref()} | {error, term()}.
create(Repo, Refname, Target, Force) ->
case geef_repo:create_reference(Repo, Refname, Target, Force) of
{ok, Ref} ->
{ok, new(Refname, Ref)};
RepoHandle = geef_repo:handle(Repo),
case do_create(RepoHandle, Refname, Target, Force) of
ok ->
{ok, make(Repo, Refname, Target)};
Err = {error, _} ->
Err
end.
-spec do_create(term(), binary(), target(), boolean()) -> ok | {error, term}.
do_create(RepoHandle, Refname, #geef_oid{oid=Oid}, Force) ->
geef_nif:reference_create(RepoHandle, Refname, oid, Oid, Force);
do_create(RepoHandle, Refname, Target, Force) ->
geef_nif:reference_create(RepoHandle, Refname, symbolic, Target, Force).
-spec make(pid(), binary(), target()) -> ref().
make(Repo, Name, Target = #geef_oid{}) ->
#geef_reference{repo=Repo, name=Name, type=oid, target=Target};
make(Repo, Name, Target) ->
#geef_reference{repo=Repo, name=Name, type=symbolic, target=Target}.
-spec make(pid(), binary(), type(), binary()) -> ref().
make(Repo, Name, oid, Target) ->
#geef_reference{repo=Repo, name=Name, type=oid, target=#geef_oid{oid=Target}};
make(Repo, Name, symbolic, Target) ->
#geef_reference{repo=Repo, name=Name, type=symbolic, target=Target}.
-spec lookup(pid(), iolist()) -> {ok, ref()} | {error, term()}.
lookup(Repo, Refname) ->
Name = iolist_to_binary(Refname),
case geef_repo:lookup_reference(Repo, Name) of
{ok, Ref} ->
{ok, new(Name, Ref)};
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_lookup(RepoHandle, Name) of
{ok, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other ->
Other
end.
@@ -58,10 +63,10 @@ iterator(Repo) ->
iterator(Repo, undefined).
-spec next(iterator()) -> {ok, ref()} | {error, term()}.
next(#geef_iterator{type=ref, handle=Handle}) ->
next(#geef_iterator{type=ref, repo=Repo, handle=Handle}) ->
case geef_nif:reference_next(Handle) of
{ok, RefHandle} ->
{ok, new(RefHandle)};
{ok, Name, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other ->
Other
end.
@@ -69,20 +74,22 @@ next(#geef_iterator{type=ref, handle=Handle}) ->
-spec resolve(ref()) -> {ok, ref()} | {error, term()}.
resolve(Ref = #geef_reference{type=oid}) ->
{ok, Ref}; % resolving an oid ref is a no-op, skip going into the NIF
resolve(#geef_reference{type=symbolic, handle=Handle}) ->
case geef_nif:reference_resolve(Handle) of
{ok, Ref} ->
{ok, new(Ref)};
resolve(#geef_reference{repo=Repo, name=Name, type=symbolic}) ->
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_resolve(RepoHandle, Name) of
{ok, Type, Target} ->
{ok, make(Repo, Name, Type, Target)};
Other = {error, _} ->
Other
end.
-spec dwim(pid(), iolist()) -> {ok, ref()} | {error, term()}.
dwim(Repo, Name) ->
case geef_repo:reference_dwim(Repo, Name) of
{ok, Handle} ->
{ok, new(Handle)};
Err ->
RepoHandle = geef_repo:handle(Repo),
case geef_nif:reference_dwim(RepoHandle, Name) of
{ok, RealName, Type, Target} ->
{ok, make(Repo, RealName, Type, Target)};
Err = {error, _}->
Err
end.

View File

@@ -43,10 +43,12 @@ ref_test(Repo) ->
{ok, _} = geef_ref:create(Repo, "refs/heads/other", "refs/heads/branch", true),
{ok, Ref0} = geef_ref:lookup(Repo, "refs/heads/branch"),
{ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"),
{ok, Ref2} = geef_ref:resolve(Ref0),
{ok, Dwimed} = geef_ref:dwim(Repo, "branch"),
[?_assertEqual(Ref0#geef_reference.target, Id),
?_assertEqual(Ref1#geef_reference.target, <<"refs/heads/branch">>),
?_assertEqual(<<"branch">>, geef_ref:shorthand(Ref0)),
?_assertEqual(Ref2#geef_reference.target, Id),
?_assertEqual(Ref0, Dwimed)].
ref_iter_test(Repo) ->