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