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.
This commit is contained in:
Carlos Martín Nieto
2014-02-13 17:19:51 +01:00
parent d9822de604
commit 22ab293910
12 changed files with 127 additions and 12 deletions

View File

@@ -12,6 +12,7 @@
#include "index.h" #include "index.h"
#include "signature.h" #include "signature.h"
#include "revparse.h" #include "revparse.h"
#include "reflog.h"
#include "geef.h" #include "geef.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -72,6 +73,7 @@ static int load(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
atoms.blob = enif_make_atom(env, "blob"); atoms.blob = enif_make_atom(env, "blob");
atoms.tag = enif_make_atom(env, "tag"); atoms.tag = enif_make_atom(env, "tag");
atoms.undefined = enif_make_atom(env, "undefined"); atoms.undefined = enif_make_atom(env, "undefined");
atoms.reflog_entry = enif_make_atom(env, "geef_reflog_entry");
/* Revwalk */ /* Revwalk */
atoms.toposort = enif_make_atom(env, "sort_topo"); atoms.toposort = enif_make_atom(env, "sort_topo");
atoms.timesort = enif_make_atom(env, "sort_time"); 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; size_t len;
if (str == NULL)
len = 0;
else
len = strlen(str); len = strlen(str);
if (!enif_alloc_binary(len, bin)) if (!enif_alloc_binary(len, bin))
return -1; return -1;
@@ -170,6 +176,7 @@ static ErlNifFunc geef_funcs[] =
{"reference_create", 5, geef_reference_create}, {"reference_create", 5, geef_reference_create},
{"reference_dwim", 2, geef_reference_dwim}, {"reference_dwim", 2, geef_reference_dwim},
{"reference_has_log", 2, geef_reference_has_log}, {"reference_has_log", 2, geef_reference_has_log},
{"reflog_read", 2, geef_reflog_read},
{"oid_fmt", 1, geef_oid_fmt}, {"oid_fmt", 1, geef_oid_fmt},
{"oid_parse", 1, geef_oid_parse}, {"oid_parse", 1, geef_oid_parse},
{"object_lookup", 2, geef_object_lookup}, {"object_lookup", 2, geef_object_lookup},

View File

@@ -23,6 +23,7 @@ typedef struct {
ERL_NIF_TERM timesort; ERL_NIF_TERM timesort;
ERL_NIF_TERM reversesort; ERL_NIF_TERM reversesort;
ERL_NIF_TERM iterover; ERL_NIF_TERM iterover;
ERL_NIF_TERM reflog_entry;
ERL_NIF_TERM enomem; ERL_NIF_TERM enomem;
ERL_NIF_TERM eunknown; ERL_NIF_TERM eunknown;

View File

@@ -6,8 +6,10 @@
int geef_oid_bin(ErlNifBinary *bin, const git_oid *id) 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; return -1;
}
memcpy(bin->data, id, GIT_OID_RAWSZ); memcpy(bin->data, id, GIT_OID_RAWSZ);
return 0; return 0;

66
c_src/reflog.c Normal file
View File

@@ -0,0 +1,66 @@
#include "geef.h"
#include "repository.h"
#include "reference.h"
#include "oid.h"
#include "signature.h"
#include <string.h>
#include <git2.h>
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);
}

9
c_src/reflog.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef GEEF_REFLOG_H
#define GEEF_REFLOG_H
#include "erl_nif.h"
#include <git2.h>
ERL_NIF_TERM geef_reflog_read(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
#endif

View File

@@ -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; ErlNifBinary name, email;

View File

@@ -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[]); 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_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 #endif

View File

@@ -73,6 +73,10 @@ reference_dwim(_Handle, _Name) ->
reference_has_log(_Handle, _Name) -> reference_has_log(_Handle, _Name) ->
?NIF_FN. ?NIF_FN.
-spec reflog_read(term(), iolist()) -> {ok, geef_reflog:reflog()} | {error, term()}.
reflog_read(_Handle, _Name) ->
?NIF_FN.
odb_object_exists(_Val, _Val) -> odb_object_exists(_Val, _Val) ->
nif_error(?LINE). nif_error(?LINE).

View File

@@ -14,4 +14,8 @@
-record(geef_signature, {name :: iolist(), email :: iolist(), time :: geef_sig:time()}). -record(geef_signature, {name :: iolist(), email :: iolist(), time :: geef_sig:time()}).
-record(geef_iterator, {type :: atom(), repo :: pid(), regexp :: iolist(), handle}). -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{}. -type geef_request() :: #geef_request{}.

16
src/geef_reflog.erl Normal file
View File

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

View File

@@ -1,11 +1,6 @@
%%%------------------------------------------------------------------- %% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*-
%%% @author Carlos Martín Nieto <cmn@dwim.me> %%% @copyright (C) 2013-2014, Carlos Martín Nieto <cmn@dwim.me>
%%% @copyright (C) 2013, Carlos Martín Nieto
%%% @doc
%%%
%%% @end
%%% Created : 6 Apr 2013 by Carlos Martín Nieto <cmn@dwim.me>
%%%-------------------------------------------------------------------
-module(geef_repo). -module(geef_repo).
-behaviour(gen_server). -behaviour(gen_server).
@@ -19,6 +14,7 @@
lookup_object/2, revwalk/1, stop/1, lookup_object/2, revwalk/1, stop/1,
reference_dwim/2, handle/1, iterator/2]). reference_dwim/2, handle/1, iterator/2]).
-export([reference_has_log/2]). -export([reference_has_log/2]).
-export([reflog_read/2]).
-include("geef_records.hrl"). -include("geef_records.hrl").
-record(state, {handle}). -record(state, {handle}).
@@ -100,6 +96,10 @@ revwalk(Pid) ->
reference_has_log(Pid, Name) -> reference_has_log(Pid, Name) ->
gen_server:call(Pid, {has_log, Name}). gen_server:call(Pid, {has_log, Name}).
%% @private
reflog_read(Pid, Name) ->
gen_server:call(Pid, {reflog_read, Name}).
stop(Pid) -> stop(Pid) ->
gen_server:call(Pid, stop). 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 = geef_nif:reference_has_log(Handle, Name),
{reply, Reply, State}; {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) -> handle_call(stop, _From, State) ->
{stop, normal, ok, State}; {stop, normal, ok, State};
handle_call(revwalk, _From, State = #state{handle=Handle}) -> handle_call(revwalk, _From, State = #state{handle=Handle}) ->

View File

@@ -59,11 +59,13 @@ ref_test(Repo) ->
{ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"), {ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"),
{ok, Ref2} = geef_ref:resolve(Ref0), {ok, Ref2} = geef_ref:resolve(Ref0),
{ok, Dwimed} = geef_ref:dwim(Repo, "branch"), {ok, Dwimed} = geef_ref:dwim(Repo, "branch"),
{ok, Reflog} = geef_reflog:read(Repo, "refs/heads/branch"),
[?_assertEqual(Ref0#geef_reference.target, Id), [?_assertEqual(Ref0#geef_reference.target, Id),
?_assertEqual(Ref1#geef_reference.target, <<"refs/heads/branch">>), ?_assertEqual(Ref1#geef_reference.target, <<"refs/heads/branch">>),
?_assertEqual(<<"branch">>, geef_ref:shorthand(Ref0)), ?_assertEqual(<<"branch">>, geef_ref:shorthand(Ref0)),
?_assertEqual(Ref2#geef_reference.target, Id), ?_assertEqual(Ref2#geef_reference.target, Id),
?_assertEqual({ok, true}, geef_ref:has_log(Ref0)), ?_assertEqual({ok, true}, geef_ref:has_log(Ref0)),
?_assertEqual(1, length(Reflog)),
?_assertEqual(Ref0, Dwimed)]. ?_assertEqual(Ref0, Dwimed)].
ref_iter_test(Repo) -> ref_iter_test(Repo) ->