From 79f89bcd4121a358e9f4b891dc6f03e341a1d4c7 Mon Sep 17 00:00:00 2001 From: Ramon Snir Date: Sat, 18 Jul 2015 20:36:14 +0300 Subject: [PATCH] add Geef.Revwalk module for Elixir --- c_src/revwalk.c | 12 ++++++++++++ c_src/revwalk.h | 1 + lib/geef.ex | 1 + lib/geef/repository.ex | 1 + lib/geef/revwalk.ex | 32 ++++++++++++++++++++++++++++++++ src/geef_nif.erl | 3 +++ src/geef_repo.erl | 40 ++++++++++++++++++++-------------------- src/geef_revwalk.erl | 19 +++++++++++++++++-- test/revwalk_test.erl | 16 ++++++++-------- test/revwalk_test.exs | 29 +++++++++++++++++++++++++++++ test/test_helper.exs | 23 ++++++++++++++++++++++- 11 files changed, 146 insertions(+), 31 deletions(-) create mode 100644 lib/geef/revwalk.ex create mode 100644 test/revwalk_test.exs diff --git a/c_src/revwalk.c b/c_src/revwalk.c index 0a85f60..8ae6013 100644 --- a/c_src/revwalk.c +++ b/c_src/revwalk.c @@ -108,6 +108,18 @@ geef_revwalk_sorting(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) return atoms.ok; } +ERL_NIF_TERM +geef_revwalk_simplify_first_parent(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ + geef_revwalk *walk; + + if (!enif_get_resource(env, argv[0], geef_revwalk_type, (void **) &walk)) + return enif_make_badarg(env); + + git_revwalk_simplify_first_parent(walk->walk); + + return atoms.ok; +} ERL_NIF_TERM geef_revwalk_reset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) diff --git a/c_src/revwalk.h b/c_src/revwalk.h index c10b898..881c424 100644 --- a/c_src/revwalk.h +++ b/c_src/revwalk.h @@ -18,6 +18,7 @@ ERL_NIF_TERM geef_revwalk_new(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[ ERL_NIF_TERM geef_revwalk_next(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM geef_revwalk_push(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM geef_revwalk_sorting(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); +ERL_NIF_TERM geef_revwalk_simplify_first_parent(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM geef_revwalk_reset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]); #endif diff --git a/lib/geef.ex b/lib/geef.ex index 90745b5..0269d8d 100644 --- a/lib/geef.ex +++ b/lib/geef.ex @@ -12,6 +12,7 @@ defmodule Geef do alias Geef.Oid alias Geef.Reference alias Geef.Repository + alias Geef.Revwalk alias Geef.Signature alias Geef.Tree alias Geef.Tag diff --git a/lib/geef/repository.ex b/lib/geef/repository.ex index ef6b189..189bac5 100644 --- a/lib/geef/repository.ex +++ b/lib/geef/repository.ex @@ -18,6 +18,7 @@ defmodule Geef.Repository do def gitdir(repo), do: :geef_repo.path(repo) def workdir(repo), do: :geef_repo.workdir(repo) def config(repo), do: :geef_repo.config(repo) + def revwalk(repo), do: :geef_repo.revwalk(repo) def reference_names(repo), do: :geef_repo.references(repo) end diff --git a/lib/geef/revwalk.ex b/lib/geef/revwalk.ex new file mode 100644 index 0000000..262e906 --- /dev/null +++ b/lib/geef/revwalk.ex @@ -0,0 +1,32 @@ +defmodule Geef.Revwalk do + import Geef + alias Geef.Object + + def stop(walk), do: :geef_revwalk.stop(walk) + + def open(repo) when is_pid(repo), do: Repository.revwalk(repo) + def open!(arg), do: open(arg) |> assert_ok + + def push(walk, %Object{type: :commit, id: commit}), do: push(walk, commit) + def push(walk, commit), do: :geef_revwalk.push(walk, commit) + + def hide(walk, %Object{type: :commit, id: commit}), do: hide(walk, commit) + def hide(walk, commit), do: :geef_revwalk.hide(walk, commit) + + def simplify_first_parent(walk), do: :geef_revwalk.simplify_first_parent(walk) + + def sorting(walk, flags \\ []) + def sorting(walk, flags) when is_list(flags) do + flags = Enum.map(flags, &compile_sorting_flag/1) + :geef_revwalk.sorting(walk, flags) + end + def sorting(walk, flag), do: sorting(walk, [flag]) + + def next(walk), do: :geef_revwalk.next(walk) + + def reset(walk), do: :geef_revwalk.reset(walk) + + defp compile_sorting_flag(:topological_sort), do: :toposort + defp compile_sorting_flag(:time_sort), do: :timesort + defp compile_sorting_flag(:reverse_sort), do: :reversesort +end diff --git a/src/geef_nif.erl b/src/geef_nif.erl index 96a262b..df6e4e3 100644 --- a/src/geef_nif.erl +++ b/src/geef_nif.erl @@ -159,6 +159,9 @@ revwalk_next(_Walk) -> revwalk_sorting(_Walk, _Sort) -> ?NIF_FN. +revwalk_simplify_first_parent(_Walk) -> + ?NIF_FN. + revwalk_reset(_Walk) -> ?NIF_FN. diff --git a/src/geef_repo.erl b/src/geef_repo.erl index d8e684c..f64a4e3 100644 --- a/src/geef_repo.erl +++ b/src/geef_repo.erl @@ -7,12 +7,12 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3]). %% API -export([open/1, init/2, path/1, workdir/1, odb/1, is_bare/1, references/1, discover/1, - lookup_object/2, revwalk/1, stop/1, - reference_dwim/2, handle/1, iterator/2]). + lookup_object/2, revwalk/1, stop/1, + reference_dwim/2, handle/1, iterator/2]). -export([reference_has_log/2]). -export([reference_resolve/2]). -export([reflog_read/2, reflog_delete/2]). @@ -37,21 +37,21 @@ discover(Path) -> -spec open(iolist()) -> {ok, pid()} | {error, term()}. open(Path) -> case geef_nif:repository_open(Path) of - {ok, Handle} -> - start_link(Handle); - Other -> - Other + {ok, Handle} -> + start_link(Handle); + Other -> + Other end. %% @doc Initialize a new repository -spec init(iolist(), boolean()) -> {ok, pid()} | {error, term()}. init(Path, Bare) -> case geef_nif:repository_init(Path, Bare) of - {ok, Handle} -> - start_link(Handle); - Other -> - Other - end. + {ok, Handle} -> + start_link(Handle); + Other -> + Other + end. %% @doc The repository's git-dir path -spec path(pid()) -> binary(). @@ -224,18 +224,18 @@ start_link(Handle) -> handle_odb(Handle) -> case geef_nif:repository_get_odb(Handle) of - {ok, OdbHandle} -> - geef_odb:start_link(OdbHandle); - Other -> - Other + {ok, OdbHandle} -> + geef_odb:start_link(OdbHandle); + Other -> + Other end. handle_revwalk(Handle) -> case geef_nif:revwalk_new(Handle) of - {ok, WalkHandle} -> - geef_revwalk:start_link(WalkHandle); - Error -> - Error + {ok, WalkHandle} -> + geef_revwalk:start_link(WalkHandle); + Error -> + Error end. handle_config(Handle) -> diff --git a/src/geef_revwalk.erl b/src/geef_revwalk.erl index 14d2ec2..10a9dd1 100644 --- a/src/geef_revwalk.erl +++ b/src/geef_revwalk.erl @@ -12,11 +12,11 @@ %% API -export([start_link/1]). --export([push/2, hide/2, next/1, sorting/2, stop/1]). +-export([push/2, hide/2, next/1, sorting/2, simplify_first_parent/1, reset/1, stop/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). + terminate/2, code_change/3]). -record(state, {handle}). -include("geef_records.hrl"). @@ -46,7 +46,16 @@ sorting(Pid, Opts) when is_list(Opts) -> sorting(Pid, Opt) when is_atom(Opt) -> gen_server:call(Pid, {sort, [Opt]}). +-spec simplify_first_parent(pid) -> ok. +simplify_first_parent(Pid) -> + gen_server:call(Pid, simplify_first_parent). + +-spec reset(pid) -> ok. +reset(Pid) -> + gen_server:call(Pid, reset). + %% @doc Next commit in the walk +-spec next(pid) -> {ok, geef_oid:oid()} | {error, iterover}. next(Pid) -> gen_server:call(Pid, next). @@ -76,12 +85,18 @@ init(Handle) -> handle_call({sort, Opts}, _From, State = #state{handle=Handle}) -> geef_nif:revwalk_sorting(Handle, Opts), {reply, ok, State}; +handle_call(simplify_first_parent, _From, State = #state{handle=Handle}) -> + geef_nif:revwalk_simplify_first_parent(Handle), + {reply, ok, State}; handle_call({push, Oid}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:revwalk_push(Handle, Oid, false), {reply, Reply, State}; handle_call({hide, Oid}, _From, State = #state{handle=Handle}) -> Reply = geef_nif:revwalk_push(Handle, Oid, true), {reply, Reply, State}; +handle_call(reset, _From, State = #state{handle=Handle}) -> + geef_nif:revwalk_reset(Handle), + {reply, ok, State}; handle_call(next, _From, State = #state{handle=Handle}) -> Reply = geef_nif:revwalk_next(Handle), {reply, Reply, State}; diff --git a/test/revwalk_test.erl b/test/revwalk_test.erl index 3f79664..c938b32 100644 --- a/test/revwalk_test.erl +++ b/test/revwalk_test.erl @@ -4,10 +4,10 @@ repo_test_() -> case os:getenv("GEEF_RESOURCES") of - false -> - []; - _ -> - {foreach, fun start/0, fun stop/1, [fun amount_test/1]} + false -> + []; + _ -> + {foreach, fun start/0, fun stop/1, [fun amount_test/1]} end. start() -> @@ -18,10 +18,10 @@ start() -> count_walk(Walk, Acc) -> case geef_revwalk:next(Walk) of - {ok, _} -> - count_walk(Walk, Acc + 1); - {error, iterover} -> - Acc + {ok, _} -> + count_walk(Walk, Acc + 1); + {error, iterover} -> + Acc end. amount_test(Repo) -> diff --git a/test/revwalk_test.exs b/test/revwalk_test.exs new file mode 100644 index 0000000..0fcbea6 --- /dev/null +++ b/test/revwalk_test.exs @@ -0,0 +1,29 @@ +defmodule RevwalkTest do + use ExUnit.Case + use Geef + import RepoHelpers + + + setup do + {repo, path, head, boring_ancestor} = tmp_commit_line + Process.link(repo) + {:ok, walk} = Repository.revwalk(repo) + on_exit(fn -> File.rm_rf!(path) end) + {:ok, [walk: walk, head: head, boring_ancestor: boring_ancestor]} + end + + test "walk and count", meta do + walk = meta[:walk] + Revwalk.push(walk, meta[:head]) + Revwalk.hide(walk, meta[:boring_ancestor]) + assert 3 = count_walk(walk) + end + + defp count_walk walk, acc \\ 0 + defp count_walk walk, acc do + case Revwalk.next(walk) do + {:ok, _} -> count_walk(walk, acc + 1) + {:error, :iterover} -> acc + end + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index 0217d3c..d0959c7 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,12 +1,33 @@ ExUnit.start defmodule RepoHelpers do + use Geef + def tmp_bare do {a, b, c} = :erlang.timestamp() n = node() dir = :io_lib.format("geef-~p~p~p~p.git", [n, a, b, c]) path = Path.join(System.tmp_dir!, dir) - {:ok, repo} = Geef.Repository.init(path, true) + {:ok, repo} = Repository.init(path, true) {repo, path} end + + def tmp_commit_line do + {repo, path} = tmp_bare() + sig = Signature.now("Geef Test", "test@geef") + message = "commit message" + {:ok, idx} = Index.new() + {:ok, empty_index} = Index.write_tree(idx, repo) + + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, []) + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, [c]) + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, [c]) + boring_ancestor = c + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, [c]) + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, [c]) + {:ok, c} = Commit.create(repo, sig, sig, message, empty_index, [c]) + head = c + + {repo, path, head, boring_ancestor} + end end