diff --git a/c_src/geef.c b/c_src/geef.c index 3d820f0..096164c 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -10,6 +10,7 @@ #include "library.h" #include "revwalk.h" #include "index.h" +#include "signature.h" #include "geef.h" #include #include @@ -178,6 +179,8 @@ static ErlNifFunc geef_funcs[] = {"index_add", 2, geef_index_add}, {"index_clear", 1, geef_index_clear}, {"index_read_tree", 2, geef_index_read_tree}, + {"signature_new", 2, geef_signature_new}, + {"signature_new", 3, geef_signature_new}, }; ERL_NIF_INIT(geef_nif, geef_funcs, load, NULL, upgrade, unload) diff --git a/c_src/signature.c b/c_src/signature.c new file mode 100644 index 0000000..b93fb85 --- /dev/null +++ b/c_src/signature.c @@ -0,0 +1,65 @@ +#include "geef.h" +#include +#include + +ERL_NIF_TERM +geef_signature_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary name, email; + git_signature *sig; + size_t len; + int error; + unsigned int at; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &name)) + return enif_make_badarg(env); + + if (!enif_inspect_iolist_as_binary(env, argv[1], &email)) + return enif_make_badarg(env); + + if (argc == 3 && !enif_get_uint(env, argv[2], &at)) + return enif_make_badarg(env); + + if (!geef_terminate_binary(&name)) + return atoms.error; + + if (!geef_terminate_binary(&email)) { + enif_release_binary(&name); + return atoms.error; + } + + if (argc == 3) + error = git_signature_now(&sig, (char *)name.data, (char *)email.data); + else + error = git_signature_new(&sig, (char *)name.data, (char *)email.data, at, 0); + + if (error < 0) + return geef_error(env); + + len = strlen(sig->name); + if (!enif_realloc_binary(&name, len)) + goto on_error; + + memcpy(name.data, sig->name, len); + + len = strlen(sig->email); + if (!enif_realloc_binary(&email, len)) + goto on_error; + + memcpy(email.data, sig->email, len); + git_signature_free(sig); + + if (argc == 3) + return enif_make_tuple3(env, atoms.ok, enif_make_binary(env, &name), enif_make_binary(env, &email)); + + return 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)); + +on_error: + git_signature_free(sig); + enif_release_binary(&name); + enif_release_binary(&email); + + return atoms.error; +} diff --git a/c_src/signature.h b/c_src/signature.h new file mode 100644 index 0000000..0fbaafa --- /dev/null +++ b/c_src/signature.h @@ -0,0 +1,3 @@ +#include "geef.h" + +ERL_NIF_TERM geef_signature_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); diff --git a/lib/geef/signature.ex b/lib/geef/signature.ex new file mode 100644 index 0000000..ec320b8 --- /dev/null +++ b/lib/geef/signature.ex @@ -0,0 +1,9 @@ +defrecord Geef.Signature, Record.extract(:geef_signature, from: "src/geef_records.hrl") do + + def new(name, email), do: :geef_sig.new(name, email) |> maybe_sig + def new(name, email, time), do: :geef_sig.new(name, email, time) |> maybe_sig + + defp maybe_sig({ok, sig}), do: {ok, Geef.Signature.new sig} + defp maybe_sig(error), do: error + +end diff --git a/src/geef_nif.erl b/src/geef_nif.erl index da26314..01ebd35 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -148,6 +148,12 @@ index_add(_Handle, _Entry) -> index_clear(_Handle) -> ?NIF_FN. +signature_new(_Name, _Email) -> + ?NIF_FN. + +signature_new(_Name, _Email, _Time) -> + ?NIF_FN. + nif_error(Line) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/src/geef_records.hrl b/src/geef_records.hrl index c1a2738..572b828 100644 --- a/src/geef_records.hrl +++ b/src/geef_records.hrl @@ -12,6 +12,7 @@ -record(geef_request, {service :: atom, path :: binary(), host :: binary()}). -record(geef_tree_entry, {mode, type, id, name}). +-record(geef_signature, {name :: iolist(), email :: iolist(), time :: geef_time()}). -type geef_reference() :: #geef_reference{}. -type geef_oid() :: #geef_oid{}. @@ -19,3 +20,5 @@ -type geef_index_entry() :: #geef_index_entry{}. -type geef_request() :: #geef_request{}. -type geef_tree_entry() :: #geef_tree_entry{}. +-type geef_signature() :: #geef_signature{}. +-type geef_time() :: {erlang:timestamp(), non_neg_integer()}. diff --git a/src/geef_sig.erl b/src/geef_sig.erl new file mode 100644 index 0000000..d57f476 --- /dev/null +++ b/src/geef_sig.erl @@ -0,0 +1,24 @@ +-module(geef_sig). + +-include("geef_records.hrl"). + +-export([new/2, new/3]). + +-spec new(iolist(), iolist()) -> geef_signature() | {error, term()}. +new(Name0, Email0) -> + case geef_nif:signature_new(Name0, Email0) of + {ok, Name, Email, Time0, Offset} -> + Time = {{Time0 div 1000000, Time0 rem 1000000, 0}, Offset}, + {ok, #geef_signature{name=Name, email=Email, time=Time}}; + Err -> + Err + end. + +-spec new(iolist(), iolist(), geef_time()) -> geef_signature() | {error, term()}. +new(Name0, Email0, Time) -> + case geef_nif:signature_new(Name0, Email0, 0) of + {ok, Name, Email} -> + {ok, #geef_signature{name=Name, email=Email, time=Time}}; + Err -> + Err + end. diff --git a/test/sig_test.erl b/test/sig_test.erl new file mode 100644 index 0000000..ede37df --- /dev/null +++ b/test/sig_test.erl @@ -0,0 +1,14 @@ +-module(sig_test). +-compile([export_all]). +-include_lib("eunit/include/eunit.hrl"). +-include("src/geef_records.hrl"). + +now_test() -> + Sig = geef_sig:new("Carlos", "a@b.c"), + ?assertMatch(#geef_signature{name = <<"Carlos">>, email = <<"a@b.c">>, time=_}, Sig). + +at_test() -> + Time = {os:timestamp(), 120}, + Actual = geef_sig:new("Carlos", "a@b.c", Time), + Expected = #geef_signature{name = <<"Carlos">>, email = <<"a@b.c">>, time = Time}, + ?assertEqual(Expected, Actual).