From 9501ed2377c2afed68f168b2927b83665c172e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 10:47:14 +0100 Subject: [PATCH 1/6] Add reference has_log() --- c_src/geef.c | 1 + c_src/reference.c | 31 +++++++++++++++++++++++++++++++ c_src/reference.h | 1 + src/geef_nif.erl | 4 ++++ src/geef_ref.erl | 10 ++++++++++ src/geef_repo.erl | 12 +++++++++++- test/repo_test.erl | 1 + 7 files changed, 59 insertions(+), 1 deletion(-) diff --git a/c_src/geef.c b/c_src/geef.c index bee4dad..3c6a0cd 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -157,6 +157,7 @@ static ErlNifFunc geef_funcs[] = {"reference_resolve", 2, geef_reference_resolve}, {"reference_create", 5, geef_reference_create}, {"reference_dwim", 2, geef_reference_dwim}, + {"reference_has_log", 2, geef_reference_has_log}, {"oid_fmt", 1, geef_oid_fmt}, {"oid_parse", 1, geef_oid_parse}, {"object_lookup", 2, geef_object_lookup}, diff --git a/c_src/reference.c b/c_src/reference.c index e6c73a0..1994d6f 100644 --- a/c_src/reference.c +++ b/c_src/reference.c @@ -418,3 +418,34 @@ geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return atoms.ok; } + +ERL_NIF_TERM +geef_reference_has_log(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + geef_repository *repo; + ErlNifBinary name; + int error; + const char *pname; + ERL_NIF_TERM ret; + + if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) + return enif_make_badarg(env); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &name)) + return enif_make_badarg(env); + + if (!geef_terminate_binary(&name)) + return geef_oom(env); + + pname = (char *) name.data; + error = git_reference_has_log(repo->repo, pname); + + enif_release_binary(&name); + + if (error < 0) + return geef_error(env); + + ret = error ? atoms.true : atoms.false; + + return enif_make_tuple2(env, atoms.ok, ret); +} diff --git a/c_src/reference.h b/c_src/reference.h index 89bd0bb..492e00d 100644 --- a/c_src/reference.h +++ b/c_src/reference.h @@ -20,6 +20,7 @@ ERL_NIF_TERM geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM 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[]); +ERL_NIF_TERM geef_reference_has_log(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); void geef_ref_iter_free(ErlNifEnv *env, void *cd); diff --git a/src/geef_nif.erl b/src/geef_nif.erl index dd7241f..be8220a 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -69,6 +69,10 @@ reference_resolve(_RepoHandle, _Name) -> reference_dwim(_Handle, _Name) -> ?NIF_FN. +-spec reference_has_log(term(), iolist()) -> {ok, boolean()} | {error, term()}. +reference_has_log(_Handle, _Name) -> + ?NIF_FN. + odb_object_exists(_Val, _Val) -> nif_error(?LINE). diff --git a/src/geef_ref.erl b/src/geef_ref.erl index 2e28467..d4ad65d 100644 --- a/src/geef_ref.erl +++ b/src/geef_ref.erl @@ -1,6 +1,7 @@ -module(geef_ref). -export([lookup/2, iterator/1, iterator/2, next/1, resolve/1, create/4, create_symbolic/4, dwim/2, shorthand/1]). +-export([has_log/1, has_log/2]). -include("geef_records.hrl"). @@ -103,3 +104,12 @@ shorthand(<<"refs/", Rest/binary>>) -> Rest; shorthand(#geef_reference{name=Name}) -> shorthand(Name). + +%% @doc Return whether the reference has a reflog +-spec has_log(pid(), iolist()) -> {ok, boolean()} | {error, term()}. +has_log(Repo, Name) -> + geef_repo:reference_has_log(Repo, Name). + +-spec has_log(ref()) -> boolean() | {ok, boolean()} | {error | term()}. +has_log(#geef_reference{repo=Repo, name=Name}) -> + has_log(Repo, Name). diff --git a/src/geef_repo.erl b/src/geef_repo.erl index 1dcdd80..63df575 100644 --- a/src/geef_repo.erl +++ b/src/geef_repo.erl @@ -18,6 +18,7 @@ -export([open/1, init/2, path/1, workdir/1, odb/1, is_bare/1, references/1, discover/1, lookup_object/2, revwalk/1, stop/1, reference_dwim/2, handle/1, iterator/2]). +-export([reference_has_log/2]). -include("geef_records.hrl"). -record(state, {handle}). @@ -95,11 +96,15 @@ reference_dwim(Pid, Name) -> revwalk(Pid) -> gen_server:call(Pid, revwalk). +%% @private +reference_has_log(Pid, Name) -> + gen_server:call(Pid, {has_log, Name}). + stop(Pid) -> gen_server:call(Pid, stop). %% @private -%% @doc Get the underlying repo resource6 +%% @doc Get the underlying repo resource handle(Pid) -> gen_server:call(Pid, handle). @@ -136,6 +141,11 @@ handle_call({iterator, Regexp}, _From, State = #state{handle=Handle}) -> handle_call({dwim_reference, Name}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:reference_dwim(Handle, Name), {reply, Reply, State}; + +handle_call({has_log, Name}, _From, State = #state{handle=Handle}) -> + Reply = geef_nif:reference_has_log(Handle, Name), + {reply, Reply, State}; + handle_call(stop, _From, State) -> {stop, normal, ok, State}; handle_call(revwalk, _From, State = #state{handle=Handle}) -> diff --git a/test/repo_test.erl b/test/repo_test.erl index 54c8d4e..7f67d72 100644 --- a/test/repo_test.erl +++ b/test/repo_test.erl @@ -63,6 +63,7 @@ ref_test(Repo) -> ?_assertEqual(Ref1#geef_reference.target, <<"refs/heads/branch">>), ?_assertEqual(<<"branch">>, geef_ref:shorthand(Ref0)), ?_assertEqual(Ref2#geef_reference.target, Id), + ?_assertEqual({ok, true}, geef_ref:has_log(Ref0)), ?_assertEqual(Ref0, Dwimed)]. ref_iter_test(Repo) -> From d4204b4b792b537d15068c9250a450297fc3cb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 16:32:46 +0100 Subject: [PATCH 2/6] Extract signature conversion code --- c_src/signature.c | 41 ++++++++++++++++++++++++++++------------- c_src/signature.h | 2 ++ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/c_src/signature.c b/c_src/signature.c index 5719f39..30d2d57 100644 --- a/c_src/signature.c +++ b/c_src/signature.c @@ -102,37 +102,52 @@ static int geef_string_to_bin(ErlNifBinary *bin, const char *str) return 0; } -ERL_NIF_TERM -geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, git_signature *sig) { - git_signature *sig; - geef_repository *repo; ErlNifBinary name, email; - if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) - return enif_make_badarg(env); - memset(&name, 0, sizeof(ErlNifBinary)); memset(&email, 0, sizeof(ErlNifBinary)); - if (git_signature_default(&sig, repo->repo) < 0) - return geef_error(env); - if (geef_string_to_bin(&name, sig->name) < 0) goto oom; if (geef_string_to_bin(&email, sig->email) < 0) goto oom; - return enif_make_tuple5(env, atoms.ok, + *out = enif_make_tuple5(env, atoms.ok, enif_make_binary(env, &name), enif_make_binary(env, &email), enif_make_ulong(env, sig->when.time), enif_make_uint(env, sig->when.offset)); + + return 0; + oom: - git_signature_free(sig); enif_release_binary(&name); enif_release_binary(&email); + return -1; +} - return geef_oom(env); +ERL_NIF_TERM +geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + git_signature *sig; + geef_repository *repo; + ERL_NIF_TERM term_sig; + int error; + + if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) + return enif_make_badarg(env); + + if (git_signature_default(&sig, repo->repo) < 0) + return geef_error(env); + + error = geef_signature_to_erl(&term_sig, env, sig); + git_signature_free(sig); + + if (error < 0) + return geef_oom(env); + + return term_sig; } ERL_NIF_TERM diff --git a/c_src/signature.h b/c_src/signature.h index b3e1e97..9018293 100644 --- a/c_src/signature.h +++ b/c_src/signature.h @@ -7,4 +7,6 @@ ERL_NIF_TERM geef_signature_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg ERL_NIF_TERM geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); int geef_signature_from_erl(git_signature **out, ErlNifEnv *env, ERL_NIF_TERM *err, ERL_NIF_TERM term); +int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, git_signature *sig); + #endif From d9822de604770d147e84baca44f568924c71c826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 16:36:10 +0100 Subject: [PATCH 3/6] Extract string->binary conversion --- c_src/geef.c | 12 ++++++++++++ c_src/geef.h | 2 ++ c_src/signature.c | 12 ------------ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/c_src/geef.c b/c_src/geef.c index 3c6a0cd..b99d876 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -137,6 +137,18 @@ int geef_terminate_binary(ErlNifBinary *bin) return 1; } +int geef_string_to_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 ErlNifFunc geef_funcs[] = { {"repository_init", 2, geef_repository_init}, diff --git a/c_src/geef.h b/c_src/geef.h index e3dec2a..fd8fa2e 100644 --- a/c_src/geef.h +++ b/c_src/geef.h @@ -32,5 +32,7 @@ extern geef_atoms atoms; /** NUL-terminate a binary */ int geef_terminate_binary(ErlNifBinary *bin); +/** Copy a string into a binary */ +int geef_string_to_bin(ErlNifBinary *bin, const char *str); #endif diff --git a/c_src/signature.c b/c_src/signature.c index 30d2d57..5db1baa 100644 --- a/c_src/signature.c +++ b/c_src/signature.c @@ -90,18 +90,6 @@ on_oom: } -static int geef_string_to_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; -} - int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, git_signature *sig) { ErlNifBinary name, email; From 22ab29391020b2fa738deeb6a0f7b6077bb01c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 17:19:51 +0100 Subject: [PATCH 4/6] Basic reflog support For now it simply includes reading in the reflog as a list of entries. This does mean that the drop/append functions don't need to be wrapped, as we can use erlang's list handling. It however also means that we cannot write this back out, as there is currently no way to create an empty reflog that we can fill with our own list. --- c_src/geef.c | 9 +++++- c_src/geef.h | 1 + c_src/oid.c | 4 ++- c_src/reflog.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ c_src/reflog.h | 9 ++++++ c_src/signature.c | 2 +- c_src/signature.h | 2 +- src/geef_nif.erl | 4 +++ src/geef_records.hrl | 4 +++ src/geef_reflog.erl | 16 +++++++++++ src/geef_repo.erl | 20 ++++++++------ test/repo_test.erl | 2 ++ 12 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 c_src/reflog.c create mode 100644 c_src/reflog.h create mode 100644 src/geef_reflog.erl diff --git a/c_src/geef.c b/c_src/geef.c index b99d876..57e26ba 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -12,6 +12,7 @@ #include "index.h" #include "signature.h" #include "revparse.h" +#include "reflog.h" #include "geef.h" #include #include @@ -72,6 +73,7 @@ static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info) atoms.blob = enif_make_atom(env, "blob"); atoms.tag = enif_make_atom(env, "tag"); atoms.undefined = enif_make_atom(env, "undefined"); + atoms.reflog_entry = enif_make_atom(env, "geef_reflog_entry"); /* Revwalk */ atoms.toposort = enif_make_atom(env, "sort_topo"); atoms.timesort = enif_make_atom(env, "sort_time"); @@ -141,7 +143,11 @@ int geef_string_to_bin(ErlNifBinary *bin, const char *str) { size_t len; - len = strlen(str); + if (str == NULL) + len = 0; + else + len = strlen(str); + if (!enif_alloc_binary(len, bin)) return -1; @@ -170,6 +176,7 @@ static ErlNifFunc geef_funcs[] = {"reference_create", 5, geef_reference_create}, {"reference_dwim", 2, geef_reference_dwim}, {"reference_has_log", 2, geef_reference_has_log}, + {"reflog_read", 2, geef_reflog_read}, {"oid_fmt", 1, geef_oid_fmt}, {"oid_parse", 1, geef_oid_parse}, {"object_lookup", 2, geef_object_lookup}, diff --git a/c_src/geef.h b/c_src/geef.h index fd8fa2e..e06e2d4 100644 --- a/c_src/geef.h +++ b/c_src/geef.h @@ -23,6 +23,7 @@ typedef struct { ERL_NIF_TERM timesort; ERL_NIF_TERM reversesort; ERL_NIF_TERM iterover; + ERL_NIF_TERM reflog_entry; ERL_NIF_TERM enomem; ERL_NIF_TERM eunknown; diff --git a/c_src/oid.c b/c_src/oid.c index a0cf889..00ff35a 100644 --- a/c_src/oid.c +++ b/c_src/oid.c @@ -6,8 +6,10 @@ int geef_oid_bin(ErlNifBinary *bin, const git_oid *id) { - if (!enif_alloc_binary(GIT_OID_RAWSZ, bin)) + if (!enif_alloc_binary(GIT_OID_RAWSZ, bin)) { + printf("cannot alloc an id!\n"); return -1; + } memcpy(bin->data, id, GIT_OID_RAWSZ); return 0; diff --git a/c_src/reflog.c b/c_src/reflog.c new file mode 100644 index 0000000..72e17ba --- /dev/null +++ b/c_src/reflog.c @@ -0,0 +1,66 @@ +#include "geef.h" +#include "repository.h" +#include "reference.h" +#include "oid.h" +#include "signature.h" +#include +#include + +ERL_NIF_TERM +geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + git_reflog *reflog; + geef_repository *repo; + ErlNifBinary bin; + int error; + size_t count, i; + ERL_NIF_TERM list; + + if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) + return enif_make_badarg(env); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &bin)) + return enif_make_badarg(env); + + if (!geef_terminate_binary(&bin)) + return geef_oom(env); + + if ((error = git_reflog_read(&reflog, repo->repo, (char *)bin.data)) < 0) + return geef_error(env); + + count = git_reflog_entrycount(reflog); + list = enif_make_list(env, 0); + + for (i = count; i > 0; i--) { + ErlNifBinary id_old, id_new, message; + ERL_NIF_TERM committer, tentry; + const git_reflog_entry *entry; + + entry = git_reflog_entry_byindex(reflog, i-1); + + if (geef_oid_bin(&id_old, git_reflog_entry_id_old(entry))) + goto on_oom; + + if (geef_oid_bin(&id_new, git_reflog_entry_id_new(entry))) + goto on_oom; + + if (geef_signature_to_erl(&committer, env, git_reflog_entry_committer(entry))) + goto on_oom; + + if (geef_string_to_bin(&message, git_reflog_entry_message(entry))) + goto on_oom; + + tentry = enif_make_tuple5(env, atoms.reflog_entry, committer, + enif_make_binary(env, &id_old), + enif_make_binary(env, &id_new), + enif_make_binary(env, &message)); + list = enif_make_list_cell(env, tentry, list); + } + + git_reflog_free(reflog); + return enif_make_tuple2(env, atoms.ok, list); + +on_oom: + git_reflog_free(reflog); + return geef_oom(env); +} diff --git a/c_src/reflog.h b/c_src/reflog.h new file mode 100644 index 0000000..398dfb0 --- /dev/null +++ b/c_src/reflog.h @@ -0,0 +1,9 @@ +#ifndef GEEF_REFLOG_H +#define GEEF_REFLOG_H + +#include "erl_nif.h" +#include + +ERL_NIF_TERM geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); + +#endif diff --git a/c_src/signature.c b/c_src/signature.c index 5db1baa..8bb81e3 100644 --- a/c_src/signature.c +++ b/c_src/signature.c @@ -90,7 +90,7 @@ on_oom: } -int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, git_signature *sig) +int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, const git_signature *sig) { ErlNifBinary name, email; diff --git a/c_src/signature.h b/c_src/signature.h index 9018293..61a2462 100644 --- a/c_src/signature.h +++ b/c_src/signature.h @@ -7,6 +7,6 @@ ERL_NIF_TERM geef_signature_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg ERL_NIF_TERM geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); int geef_signature_from_erl(git_signature **out, ErlNifEnv *env, ERL_NIF_TERM *err, ERL_NIF_TERM term); -int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, git_signature *sig); +int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, const git_signature *sig); #endif diff --git a/src/geef_nif.erl b/src/geef_nif.erl index be8220a..5f873fa 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -73,6 +73,10 @@ reference_dwim(_Handle, _Name) -> reference_has_log(_Handle, _Name) -> ?NIF_FN. +-spec reflog_read(term(), iolist()) -> {ok, geef_reflog:reflog()} | {error, term()}. +reflog_read(_Handle, _Name) -> + ?NIF_FN. + odb_object_exists(_Val, _Val) -> nif_error(?LINE). diff --git a/src/geef_records.hrl b/src/geef_records.hrl index 6f5931f..6fa0edb 100644 --- a/src/geef_records.hrl +++ b/src/geef_records.hrl @@ -14,4 +14,8 @@ -record(geef_signature, {name :: iolist(), email :: iolist(), time :: geef_sig:time()}). -record(geef_iterator, {type :: atom(), repo :: pid(), regexp :: iolist(), handle}). +-record(geef_reflog_entry, {committer :: geef_sig:signature(), + id_old :: geef_oid:oid(), id_new :: geef_oid:oid(), + message :: iolist()}). + -type geef_request() :: #geef_request{}. diff --git a/src/geef_reflog.erl b/src/geef_reflog.erl new file mode 100644 index 0000000..a7a676a --- /dev/null +++ b/src/geef_reflog.erl @@ -0,0 +1,16 @@ +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*- + +-module(geef_reflog). + +-include("geef_records.hrl"). + +-type entry() :: #geef_reflog_entry{}. +-export_type([entry/0]). + +%% API +-export([read/2]). + +%% @doc Read in a reflog +-spec read(pid(), iolist()) -> {ok, [entry()]} | {error, term()}. +read(Repo, Name) -> + geef_repo:reflog_read(Repo, Name). diff --git a/src/geef_repo.erl b/src/geef_repo.erl index 63df575..c904c0b 100644 --- a/src/geef_repo.erl +++ b/src/geef_repo.erl @@ -1,11 +1,6 @@ -%%%------------------------------------------------------------------- -%%% @author Carlos Martín Nieto -%%% @copyright (C) 2013, Carlos Martín Nieto -%%% @doc -%%% -%%% @end -%%% Created : 6 Apr 2013 by Carlos Martín Nieto -%%%------------------------------------------------------------------- +%% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*- +%%% @copyright (C) 2013-2014, Carlos Martín Nieto + -module(geef_repo). -behaviour(gen_server). @@ -19,6 +14,7 @@ lookup_object/2, revwalk/1, stop/1, reference_dwim/2, handle/1, iterator/2]). -export([reference_has_log/2]). +-export([reflog_read/2]). -include("geef_records.hrl"). -record(state, {handle}). @@ -100,6 +96,10 @@ revwalk(Pid) -> reference_has_log(Pid, Name) -> gen_server:call(Pid, {has_log, Name}). +%% @private +reflog_read(Pid, Name) -> + gen_server:call(Pid, {reflog_read, Name}). + stop(Pid) -> gen_server:call(Pid, stop). @@ -146,6 +146,10 @@ handle_call({has_log, Name}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:reference_has_log(Handle, Name), {reply, Reply, State}; +handle_call({reflog_read, Name}, _From, State = #state{handle=Handle}) -> + Reply = geef_nif:reflog_read(Handle, Name), + {reply, Reply, State}; + handle_call(stop, _From, State) -> {stop, normal, ok, State}; handle_call(revwalk, _From, State = #state{handle=Handle}) -> diff --git a/test/repo_test.erl b/test/repo_test.erl index 7f67d72..bf6666b 100644 --- a/test/repo_test.erl +++ b/test/repo_test.erl @@ -59,11 +59,13 @@ ref_test(Repo) -> {ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"), {ok, Ref2} = geef_ref:resolve(Ref0), {ok, Dwimed} = geef_ref:dwim(Repo, "branch"), + {ok, Reflog} = geef_reflog:read(Repo, "refs/heads/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({ok, true}, geef_ref:has_log(Ref0)), + ?_assertEqual(1, length(Reflog)), ?_assertEqual(Ref0, Dwimed)]. ref_iter_test(Repo) -> From 5520efb72aaa14cb5783f6ff5e1ea38e2e6356e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 18:13:33 +0100 Subject: [PATCH 5/6] Correct the signature output from the reflog The function to convert signatures into erlang terms was returning ok with the rest of the tuple which geef_sig expects. We do not want the ok there, so let that function give us the four terms and decide what to do in each case. The signature functions still want to return with ok before it, but the reflog wants them together with the other parameters. --- c_src/reflog.c | 7 ++++--- c_src/signature.c | 15 ++++++++------- c_src/signature.h | 2 +- src/geef_nif.erl | 2 +- src/geef_reflog.erl | 12 +++++++++++- src/geef_sig.erl | 12 +++++++++--- test/repo_test.erl | 2 +- 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/c_src/reflog.c b/c_src/reflog.c index 72e17ba..0708118 100644 --- a/c_src/reflog.c +++ b/c_src/reflog.c @@ -33,7 +33,7 @@ geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) for (i = count; i > 0; i--) { ErlNifBinary id_old, id_new, message; - ERL_NIF_TERM committer, tentry; + ERL_NIF_TERM tentry, name, email, time, offset; const git_reflog_entry *entry; entry = git_reflog_entry_byindex(reflog, i-1); @@ -44,13 +44,14 @@ geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) if (geef_oid_bin(&id_new, git_reflog_entry_id_new(entry))) goto on_oom; - if (geef_signature_to_erl(&committer, env, git_reflog_entry_committer(entry))) + if (geef_signature_to_erl(&name, &email, &time, &offset, + env, git_reflog_entry_committer(entry))) goto on_oom; if (geef_string_to_bin(&message, git_reflog_entry_message(entry))) goto on_oom; - tentry = enif_make_tuple5(env, atoms.reflog_entry, committer, + tentry = enif_make_tuple7(env, name, email, time, offset, enif_make_binary(env, &id_old), enif_make_binary(env, &id_new), enif_make_binary(env, &message)); diff --git a/c_src/signature.c b/c_src/signature.c index 8bb81e3..771b7b1 100644 --- a/c_src/signature.c +++ b/c_src/signature.c @@ -90,7 +90,7 @@ on_oom: } -int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, const git_signature *sig) +int geef_signature_to_erl(ERL_NIF_TERM *out_name, ERL_NIF_TERM *out_email, ERL_NIF_TERM *out_time, ERL_NIF_TERM *out_offset, ErlNifEnv *env, const git_signature *sig) { ErlNifBinary name, email; @@ -103,9 +103,10 @@ int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, const git_signature if (geef_string_to_bin(&email, sig->email) < 0) goto oom; - *out = enif_make_tuple5(env, atoms.ok, - enif_make_binary(env, &name), enif_make_binary(env, &email), - enif_make_ulong(env, sig->when.time), enif_make_uint(env, sig->when.offset)); + *out_name = enif_make_binary(env, &name); + *out_email = enif_make_binary(env, &email); + *out_time = enif_make_ulong(env, sig->when.time); + *out_offset = enif_make_uint(env, sig->when.offset); return 0; @@ -120,7 +121,7 @@ geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { git_signature *sig; geef_repository *repo; - ERL_NIF_TERM term_sig; + ERL_NIF_TERM name, email, time, offset; int error; if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) @@ -129,13 +130,13 @@ geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) if (git_signature_default(&sig, repo->repo) < 0) return geef_error(env); - error = geef_signature_to_erl(&term_sig, env, sig); + error = geef_signature_to_erl(&name, &email, &time, &offset, env, sig); git_signature_free(sig); if (error < 0) return geef_oom(env); - return term_sig; + return enif_make_tuple5(env, atoms.ok, name, email, time, offset); } ERL_NIF_TERM diff --git a/c_src/signature.h b/c_src/signature.h index 61a2462..a6cc28f 100644 --- a/c_src/signature.h +++ b/c_src/signature.h @@ -7,6 +7,6 @@ ERL_NIF_TERM geef_signature_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg ERL_NIF_TERM geef_signature_default(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); int geef_signature_from_erl(git_signature **out, ErlNifEnv *env, ERL_NIF_TERM *err, ERL_NIF_TERM term); -int geef_signature_to_erl(ERL_NIF_TERM *out, ErlNifEnv *env, const git_signature *sig); +int geef_signature_to_erl(ERL_NIF_TERM *out_name, ERL_NIF_TERM *out_email, ERL_NIF_TERM *out_time, ERL_NIF_TERM *out_offset, ErlNifEnv *env, const git_signature *sig); #endif diff --git a/src/geef_nif.erl b/src/geef_nif.erl index 5f873fa..1ae9347 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -73,7 +73,7 @@ reference_dwim(_Handle, _Name) -> reference_has_log(_Handle, _Name) -> ?NIF_FN. --spec reflog_read(term(), iolist()) -> {ok, geef_reflog:reflog()} | {error, term()}. +-spec reflog_read(term(), iolist()) -> {ok, binary(), binary(), non_neg_integer(), non_neg_integer()} | {error, term()}. reflog_read(_Handle, _Name) -> ?NIF_FN. diff --git a/src/geef_reflog.erl b/src/geef_reflog.erl index a7a676a..334e152 100644 --- a/src/geef_reflog.erl +++ b/src/geef_reflog.erl @@ -3,6 +3,7 @@ -module(geef_reflog). -include("geef_records.hrl"). +-include_lib("eunit/include/eunit.hrl"). -type entry() :: #geef_reflog_entry{}. -export_type([entry/0]). @@ -10,7 +11,16 @@ %% API -export([read/2]). +to_entry({Name, Email, Timestamp, Offset, IdOld, IdNew, Message}) -> + Sig = geef_sig:convert(Name, Email, Timestamp, Offset), + #geef_reflog_entry{committer=Sig, id_old=IdOld, id_new=IdNew, message=Message}. + %% @doc Read in a reflog -spec read(pid(), iolist()) -> {ok, [entry()]} | {error, term()}. read(Repo, Name) -> - geef_repo:reflog_read(Repo, Name). + case geef_repo:reflog_read(Repo, Name) of + {ok, List} -> + {ok, lists:map(fun to_entry/1, List)}; + Other -> + Other + end. diff --git a/src/geef_sig.erl b/src/geef_sig.erl index 22a49f0..d8bab2f 100644 --- a/src/geef_sig.erl +++ b/src/geef_sig.erl @@ -7,6 +7,7 @@ -export_type([time/0, signature/0]). -export([default/1, now/2]). +-export([convert/4]). %% @doc Create a signature for the repository's configured username and %% email, with a timestamp of now. @@ -15,9 +16,7 @@ default(Repo) -> RepoHandle = geef_repo:handle(Repo), case geef_nif:signature_default(RepoHandle) of {ok, Name, Email, Timestamp, Offset} -> - Time = {{Timestamp div 1000000, Timestamp rem 1000000, 0}, Offset}, - Sig = #geef_signature{name=Name, email=Email, time=Time}, - {ok, Sig}; + {ok, convert(Name, Email, Timestamp, Offset)}; Err = {error, _} -> Err end. @@ -32,3 +31,10 @@ now(Name, Email) -> UTC = calendar:datetime_to_gregorian_seconds(calendar:now_to_universal_time(Now)), Offset = (Local - UTC) div 60, #geef_signature{name=Name, email=Email, time={Now, Offset}}. + +%% @private +%% @doc convert the return from the NIF to a signature +-spec convert(binary(), binary(), non_neg_integer(), non_neg_integer()) -> signature(). +convert(Name, Email, Timestamp, Offset) -> + Time = {{Timestamp div 1000000, Timestamp rem 1000000, 0}, Offset}, + #geef_signature{name=Name, email=Email, time=Time}. diff --git a/test/repo_test.erl b/test/repo_test.erl index bf6666b..610b326 100644 --- a/test/repo_test.erl +++ b/test/repo_test.erl @@ -59,7 +59,7 @@ ref_test(Repo) -> {ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"), {ok, Ref2} = geef_ref:resolve(Ref0), {ok, Dwimed} = geef_ref:dwim(Repo, "branch"), - {ok, Reflog} = geef_reflog:read(Repo, "refs/heads/branch"), + {ok, Reflog} = ?debugVal(geef_reflog:read(Repo, "refs/heads/branch")), [?_assertEqual(Ref0#geef_reference.target, Id), ?_assertEqual(Ref1#geef_reference.target, <<"refs/heads/branch">>), ?_assertEqual(<<"branch">>, geef_ref:shorthand(Ref0)), From 73af429633970002c00af17812029fc32464f772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 13 Feb 2014 18:24:42 +0100 Subject: [PATCH 6/6] Add geef_reflog:delete() --- c_src/geef.c | 1 + c_src/reflog.c | 23 +++++++++++++++++++++++ c_src/reflog.h | 1 + src/geef_nif.erl | 4 ++++ src/geef_reflog.erl | 6 ++++-- src/geef_repo.erl | 10 +++++++++- test/repo_test.erl | 7 +++++-- 7 files changed, 47 insertions(+), 5 deletions(-) diff --git a/c_src/geef.c b/c_src/geef.c index 57e26ba..4e111fa 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -177,6 +177,7 @@ static ErlNifFunc geef_funcs[] = {"reference_dwim", 2, geef_reference_dwim}, {"reference_has_log", 2, geef_reference_has_log}, {"reflog_read", 2, geef_reflog_read}, + {"reflog_delete", 2, geef_reflog_delete}, {"oid_fmt", 1, geef_oid_fmt}, {"oid_parse", 1, geef_oid_parse}, {"object_lookup", 2, geef_object_lookup}, diff --git a/c_src/reflog.c b/c_src/reflog.c index 0708118..0efbdf6 100644 --- a/c_src/reflog.c +++ b/c_src/reflog.c @@ -65,3 +65,26 @@ on_oom: git_reflog_free(reflog); return geef_oom(env); } + +ERL_NIF_TERM +geef_reflog_delete(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + geef_repository *repo; + ErlNifBinary bin; + int error; + + if (!enif_get_resource(env, argv[0], geef_repository_type, (void **) &repo)) + return enif_make_badarg(env); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &bin)) + return enif_make_badarg(env); + + if (!geef_terminate_binary(&bin)) + return geef_oom(env); + + error = git_reflog_delete(repo->repo, (char *) bin.data); + + enif_release_binary(&bin); + + return error ? geef_error(env) : atoms.ok; +} diff --git a/c_src/reflog.h b/c_src/reflog.h index 398dfb0..d1717c1 100644 --- a/c_src/reflog.h +++ b/c_src/reflog.h @@ -5,5 +5,6 @@ #include ERL_NIF_TERM geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM geef_reflog_delete(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); #endif diff --git a/src/geef_nif.erl b/src/geef_nif.erl index 1ae9347..1134adf 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -77,6 +77,10 @@ reference_has_log(_Handle, _Name) -> reflog_read(_Handle, _Name) -> ?NIF_FN. +-spec reflog_delete(term(), iolist()) -> ok | {error, term()}. +reflog_delete(_Handle, _Name) -> + ?NIF_FN. + odb_object_exists(_Val, _Val) -> nif_error(?LINE). diff --git a/src/geef_reflog.erl b/src/geef_reflog.erl index 334e152..706f37d 100644 --- a/src/geef_reflog.erl +++ b/src/geef_reflog.erl @@ -3,13 +3,12 @@ -module(geef_reflog). -include("geef_records.hrl"). --include_lib("eunit/include/eunit.hrl"). -type entry() :: #geef_reflog_entry{}. -export_type([entry/0]). %% API --export([read/2]). +-export([read/2, delete/2]). to_entry({Name, Email, Timestamp, Offset, IdOld, IdNew, Message}) -> Sig = geef_sig:convert(Name, Email, Timestamp, Offset), @@ -24,3 +23,6 @@ read(Repo, Name) -> Other -> Other end. + +delete(Repo, Name) -> + geef_repo:reflog_delete(Repo, Name). diff --git a/src/geef_repo.erl b/src/geef_repo.erl index c904c0b..6ebf507 100644 --- a/src/geef_repo.erl +++ b/src/geef_repo.erl @@ -14,7 +14,7 @@ lookup_object/2, revwalk/1, stop/1, reference_dwim/2, handle/1, iterator/2]). -export([reference_has_log/2]). --export([reflog_read/2]). +-export([reflog_read/2, reflog_delete/2]). -include("geef_records.hrl"). -record(state, {handle}). @@ -100,6 +100,10 @@ reference_has_log(Pid, Name) -> reflog_read(Pid, Name) -> gen_server:call(Pid, {reflog_read, Name}). +%% @private +reflog_delete(Pid, Name) -> + gen_server:call(Pid, {reflog_delete, Name}). + stop(Pid) -> gen_server:call(Pid, stop). @@ -150,6 +154,10 @@ handle_call({reflog_read, Name}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:reflog_read(Handle, Name), {reply, Reply, State}; +handle_call({reflog_delete, Name}, _From, State = #state{handle=Handle}) -> + Reply = geef_nif:reflog_delete(Handle, Name), + {reply, Reply, State}; + handle_call(stop, _From, State) -> {stop, normal, ok, State}; handle_call(revwalk, _From, State = #state{handle=Handle}) -> diff --git a/test/repo_test.erl b/test/repo_test.erl index 610b326..c9b0f28 100644 --- a/test/repo_test.erl +++ b/test/repo_test.erl @@ -59,13 +59,16 @@ ref_test(Repo) -> {ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"), {ok, Ref2} = geef_ref:resolve(Ref0), {ok, Dwimed} = geef_ref:dwim(Repo, "branch"), - {ok, Reflog} = ?debugVal(geef_reflog:read(Repo, "refs/heads/branch")), + {ok, Reflog0} = geef_reflog:read(Repo, "refs/heads/branch"), + ok = geef_reflog:delete(Repo, "refs/heads/branch"), + {ok, Reflog1} = geef_reflog:read(Repo, "refs/heads/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({ok, true}, geef_ref:has_log(Ref0)), - ?_assertEqual(1, length(Reflog)), + ?_assertEqual(1, length(Reflog0)), + ?_assertEqual(0, length(Reflog1)), ?_assertEqual(Ref0, Dwimed)]. ref_iter_test(Repo) ->