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) ->