From 0aa11d85327bff36aba0cde7f414afb1b66f36c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 2 May 2013 06:24:15 +0200 Subject: [PATCH] Allow creation of refs --- c_src/geef.c | 1 + c_src/reference.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++ c_src/reference.h | 1 + src/geef_nif.erl | 5 ++++- src/geef_ref.erl | 8 ++++++- src/geef_repo.erl | 14 +++++++++++- test/repo_test.erl | 12 +++++++++- 7 files changed, 92 insertions(+), 4 deletions(-) diff --git a/c_src/geef.c b/c_src/geef.c index 1a0d14d..1b08a58 100644 --- a/c_src/geef.c +++ b/c_src/geef.c @@ -128,6 +128,7 @@ static ErlNifFunc geef_funcs[] = {"reference_resolve", 1, geef_reference_resolve}, {"reference_target", 1, geef_reference_target}, {"reference_type", 1, geef_reference_type}, + {"reference_create", 5, geef_reference_create}, {"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 ab050af..bae2ce8 100644 --- a/c_src/reference.c +++ b/c_src/reference.c @@ -246,3 +246,58 @@ geef_reference_type(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return term_type; } + +ERL_NIF_TERM +geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + geef_repository *repo; + geef_ref *ref; + ErlNifBinary name, target; + ERL_NIF_TERM term_ref; + int error, force; + const char *pname, *ptarget; + + 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 (!enif_inspect_iolist_as_binary(env, argv[3], &target)) + return enif_make_badarg(env); + + /* Allocate the extra byte for the NUL terminator */ + if (!enif_realloc_binary(&name, name.size + 1)) + return atoms.error; + + name.data[name.size-1] = '\0'; + + ref = enif_alloc_resource(geef_ref_type, sizeof(geef_ref)); + + force = enif_is_identical(argv[4], atoms.true); + + pname = (const char *) name.data; + if (enif_is_identical(argv[2], atoms.oid)) { + const git_oid *oid = (const git_oid *) target.data; + error = git_reference_create(&ref->ref, repo->repo, pname, oid, force); + } else if (enif_is_identical(argv[2], atoms.symbolic)) { + /* Allocate the extra byte for the NUL terminator */ + if (!enif_realloc_binary(&target, target.size + 1)) + return atoms.error; + + target.data[target.size - 1] = '\0'; + ptarget = (const char *) target.data; + error = git_reference_symbolic_create(&ref->ref, repo->repo, pname, ptarget, force); + } else { + return enif_make_badarg(env); + } + + if (error < 0) + return geef_error(env); + + term_ref = enif_make_resource(env, ref); + enif_release_resource(ref); + + return enif_make_tuple2(env, atoms.ok, term_ref); + +} diff --git a/c_src/reference.h b/c_src/reference.h index 4dc1bc7..241bd20 100644 --- a/c_src/reference.h +++ b/c_src/reference.h @@ -17,6 +17,7 @@ ERL_NIF_TERM geef_reference_lookup(ErlNifEnv *env, int argc, const ERL_NIF_TERM ERL_NIF_TERM geef_reference_resolve(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM geef_reference_target(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM geef_reference_type(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM geef_reference_create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); void geef_ref_free(ErlNifEnv *env, void *cd); diff --git a/src/geef_nif.erl b/src/geef_nif.erl index 99f0b58..ab9a5d1 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -2,7 +2,7 @@ %%% NIF functions, not to be used directly. -module(geef_nif). --export([reference_list/1, +-export([reference_list/1, reference_create/5, reference_to_id/2, reference_glob/2, reference_lookup/2, reference_resolve/1, reference_target/1, reference_type/1, odb_object_exists/2, odb_write/3]). @@ -60,6 +60,9 @@ repository_discover(_Path) -> reference_list(_Repo) -> nif_error(?LINE). +reference_create(_Repo, _Refname, _Type, _Target, _Force) -> + ?NIF_FN. + reference_to_id(_Repo, _Refname) -> nif_error(?LINE). diff --git a/src/geef_ref.erl b/src/geef_ref.erl index fdf2311..77dbd54 100644 --- a/src/geef_ref.erl +++ b/src/geef_ref.erl @@ -1,6 +1,6 @@ -module(geef_ref). --export([lookup/2, resolve/1, target/1, name_to_id/2]). +-export([lookup/2, resolve/1, target/1, name_to_id/2, create/4]). -include("geef_records.hrl"). @@ -16,6 +16,12 @@ new(Handle) -> end, #ref{handle=Handle, type=Type, target=Target}. +-spec create(pid(), iolist(), oid() | binary(), boolean()) -> {ok, ref()} | {error, term()} +. +create(Repo, Refname, Target, Force) -> + {ok, Ref} = geef_repo:create_reference(Repo, Refname, Target, Force), + {ok, new(Ref)}. + -spec lookup(pid(), iolist()) -> {ok, ref()} | {error, term()}. lookup(Repo, Refname) -> case geef_repo:lookup_reference(Repo, Refname) of diff --git a/src/geef_repo.erl b/src/geef_repo.erl index 3df1ed5..459215c 100644 --- a/src/geef_repo.erl +++ b/src/geef_repo.erl @@ -16,7 +16,7 @@ %% API -export([open/1, init/2, path/1, workdir/1, odb/1, is_bare/1, references/1, discover/1, - lookup_object/2, lookup_reference/2, revwalk/1, stop/1, handle/1]). + lookup_object/2, lookup_reference/2, create_reference/4, revwalk/1, stop/1, handle/1]). -include("geef_records.hrl"). -record(state, {handle}). @@ -85,6 +85,10 @@ lookup_object(Pid, Oid) -> lookup_reference(Pid, Name) -> gen_server:call(Pid, {lookup_reference, Name}). +%% @private +create_reference(Pid, Name, Target, Force) -> + gen_server:call(Pid, {create_reference, Name, Target, Force}). + %% @doc Create a revision walker for the given repository. revwalk(Pid) -> gen_server:call(Pid, revwalk). @@ -127,6 +131,9 @@ handle_call({lookup_object, Oid}, _From, State = #state{handle=Handle}) -> handle_call({lookup_reference, Name}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:reference_lookup(Handle, Name), {reply, Reply, State}; +handle_call({create_reference, Name, Target, Force}, _From, State = #state{handle=Handle}) -> + Reply = handle_create_reference(Handle, Name, Target, Force), + {reply, Reply, State}; handle_call(stop, _From, State) -> {stop, normal, ok, State}; handle_call(revwalk, _From, State = #state{handle=Handle}) -> @@ -182,3 +189,8 @@ handle_revwalk(Handle) -> Error -> Error end. + +handle_create_reference(Repo, Refname, #oid{oid=Oid}, Force) -> + geef_nif:reference_create(Repo, Refname, oid, Oid, Force); +handle_create_reference(Repo, Refname, Target, Force) -> + geef_nif:reference_create(Repo, Refname, symbolic, Target, Force). diff --git a/test/repo_test.erl b/test/repo_test.erl index 679d878..20750b6 100644 --- a/test/repo_test.erl +++ b/test/repo_test.erl @@ -3,7 +3,7 @@ -include_lib("eunit/include/eunit.hrl"). repo_test_() -> - {foreach, fun start/0, fun stop/1, [fun bare_test/1, fun odb_write_test/1]}. + {foreach, fun start/0, fun stop/1, [fun bare_test/1, fun odb_write_test/1, fun create_ref_test/1]}. start() -> {A, B, C} = now(), @@ -22,5 +22,15 @@ odb_write_test(Repo) -> Expected = geef_oid:parse("c300118399f01fe52b316061b5d32beb27e0adfd"), [?_assertEqual(Actual, Expected)]. +create_ref_test(Repo) -> + odb_write_test(Repo), + Id = geef_oid:parse("c300118399f01fe52b316061b5d32beb27e0adfd"), + {ok, _} = geef_ref:create(Repo, "refs/heads/branch", Id, true), + {ok, _} = geef_ref:create(Repo, "refs/heads/other", "refs/heads/branch", true), + {ok, Ref0} = geef_ref:lookup(Repo, "refs/heads/branch"), + {ok, Ref1} = geef_ref:lookup(Repo, "refs/heads/other"), + [?_assertEqual(geef_ref:target(Ref0), Id), + ?_assertEqual(geef_ref:target(Ref1), <<"refs/heads/branch">>)]. + stop(Repo) -> geef_repo:stop(Repo).