add Geef.Revwalk module for Elixir

This commit is contained in:
Ramon Snir
2015-07-18 20:36:14 +03:00
committed by Carlos Martín Nieto
parent 01254f2f90
commit 79f89bcd41
11 changed files with 146 additions and 31 deletions

View File

@@ -108,6 +108,18 @@ geef_revwalk_sorting(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
return atoms.ok; 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 ERL_NIF_TERM
geef_revwalk_reset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) geef_revwalk_reset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])

View File

@@ -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_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_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_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[]); ERL_NIF_TERM geef_revwalk_reset(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
#endif #endif

View File

@@ -12,6 +12,7 @@ defmodule Geef do
alias Geef.Oid alias Geef.Oid
alias Geef.Reference alias Geef.Reference
alias Geef.Repository alias Geef.Repository
alias Geef.Revwalk
alias Geef.Signature alias Geef.Signature
alias Geef.Tree alias Geef.Tree
alias Geef.Tag alias Geef.Tag

View File

@@ -18,6 +18,7 @@ defmodule Geef.Repository do
def gitdir(repo), do: :geef_repo.path(repo) def gitdir(repo), do: :geef_repo.path(repo)
def workdir(repo), do: :geef_repo.workdir(repo) def workdir(repo), do: :geef_repo.workdir(repo)
def config(repo), do: :geef_repo.config(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) def reference_names(repo), do: :geef_repo.references(repo)
end end

32
lib/geef/revwalk.ex Normal file
View File

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

View File

@@ -159,6 +159,9 @@ revwalk_next(_Walk) ->
revwalk_sorting(_Walk, _Sort) -> revwalk_sorting(_Walk, _Sort) ->
?NIF_FN. ?NIF_FN.
revwalk_simplify_first_parent(_Walk) ->
?NIF_FN.
revwalk_reset(_Walk) -> revwalk_reset(_Walk) ->
?NIF_FN. ?NIF_FN.

View File

@@ -7,12 +7,12 @@
%% gen_server callbacks %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]). terminate/2, code_change/3]).
%% API %% API
-export([open/1, init/2, path/1, workdir/1, odb/1, is_bare/1, references/1, discover/1, -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, 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([reference_resolve/2]). -export([reference_resolve/2]).
-export([reflog_read/2, reflog_delete/2]). -export([reflog_read/2, reflog_delete/2]).
@@ -37,20 +37,20 @@ discover(Path) ->
-spec open(iolist()) -> {ok, pid()} | {error, term()}. -spec open(iolist()) -> {ok, pid()} | {error, term()}.
open(Path) -> open(Path) ->
case geef_nif:repository_open(Path) of case geef_nif:repository_open(Path) of
{ok, Handle} -> {ok, Handle} ->
start_link(Handle); start_link(Handle);
Other -> Other ->
Other Other
end. end.
%% @doc Initialize a new repository %% @doc Initialize a new repository
-spec init(iolist(), boolean()) -> {ok, pid()} | {error, term()}. -spec init(iolist(), boolean()) -> {ok, pid()} | {error, term()}.
init(Path, Bare) -> init(Path, Bare) ->
case geef_nif:repository_init(Path, Bare) of case geef_nif:repository_init(Path, Bare) of
{ok, Handle} -> {ok, Handle} ->
start_link(Handle); start_link(Handle);
Other -> Other ->
Other Other
end. end.
%% @doc The repository's git-dir path %% @doc The repository's git-dir path
@@ -224,18 +224,18 @@ start_link(Handle) ->
handle_odb(Handle) -> handle_odb(Handle) ->
case geef_nif:repository_get_odb(Handle) of case geef_nif:repository_get_odb(Handle) of
{ok, OdbHandle} -> {ok, OdbHandle} ->
geef_odb:start_link(OdbHandle); geef_odb:start_link(OdbHandle);
Other -> Other ->
Other Other
end. end.
handle_revwalk(Handle) -> handle_revwalk(Handle) ->
case geef_nif:revwalk_new(Handle) of case geef_nif:revwalk_new(Handle) of
{ok, WalkHandle} -> {ok, WalkHandle} ->
geef_revwalk:start_link(WalkHandle); geef_revwalk:start_link(WalkHandle);
Error -> Error ->
Error Error
end. end.
handle_config(Handle) -> handle_config(Handle) ->

View File

@@ -12,11 +12,11 @@
%% API %% API
-export([start_link/1]). -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 %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, -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}). -record(state, {handle}).
-include("geef_records.hrl"). -include("geef_records.hrl").
@@ -46,7 +46,16 @@ sorting(Pid, Opts) when is_list(Opts) ->
sorting(Pid, Opt) when is_atom(Opt) -> sorting(Pid, Opt) when is_atom(Opt) ->
gen_server:call(Pid, {sort, [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 %% @doc Next commit in the walk
-spec next(pid) -> {ok, geef_oid:oid()} | {error, iterover}.
next(Pid) -> next(Pid) ->
gen_server:call(Pid, next). gen_server:call(Pid, next).
@@ -76,12 +85,18 @@ init(Handle) ->
handle_call({sort, Opts}, _From, State = #state{handle=Handle}) -> handle_call({sort, Opts}, _From, State = #state{handle=Handle}) ->
geef_nif:revwalk_sorting(Handle, Opts), geef_nif:revwalk_sorting(Handle, Opts),
{reply, ok, State}; {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}) -> handle_call({push, Oid}, _From, State = #state{handle=Handle}) ->
Reply = geef_nif:revwalk_push(Handle, Oid, false), Reply = geef_nif:revwalk_push(Handle, Oid, false),
{reply, Reply, State}; {reply, Reply, State};
handle_call({hide, Oid}, _From, State = #state{handle=Handle}) -> handle_call({hide, Oid}, _From, State = #state{handle=Handle}) ->
Reply = geef_nif:revwalk_push(Handle, Oid, true), Reply = geef_nif:revwalk_push(Handle, Oid, true),
{reply, Reply, State}; {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}) -> handle_call(next, _From, State = #state{handle=Handle}) ->
Reply = geef_nif:revwalk_next(Handle), Reply = geef_nif:revwalk_next(Handle),
{reply, Reply, State}; {reply, Reply, State};

View File

@@ -4,10 +4,10 @@
repo_test_() -> repo_test_() ->
case os:getenv("GEEF_RESOURCES") of case os:getenv("GEEF_RESOURCES") of
false -> false ->
[]; [];
_ -> _ ->
{foreach, fun start/0, fun stop/1, [fun amount_test/1]} {foreach, fun start/0, fun stop/1, [fun amount_test/1]}
end. end.
start() -> start() ->
@@ -18,10 +18,10 @@ start() ->
count_walk(Walk, Acc) -> count_walk(Walk, Acc) ->
case geef_revwalk:next(Walk) of case geef_revwalk:next(Walk) of
{ok, _} -> {ok, _} ->
count_walk(Walk, Acc + 1); count_walk(Walk, Acc + 1);
{error, iterover} -> {error, iterover} ->
Acc Acc
end. end.
amount_test(Repo) -> amount_test(Repo) ->

29
test/revwalk_test.exs Normal file
View File

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

View File

@@ -1,12 +1,33 @@
ExUnit.start ExUnit.start
defmodule RepoHelpers do defmodule RepoHelpers do
use Geef
def tmp_bare do def tmp_bare do
{a, b, c} = :erlang.timestamp() {a, b, c} = :erlang.timestamp()
n = node() n = node()
dir = :io_lib.format("geef-~p~p~p~p.git", [n, a, b, c]) dir = :io_lib.format("geef-~p~p~p~p.git", [n, a, b, c])
path = Path.join(System.tmp_dir!, dir) path = Path.join(System.tmp_dir!, dir)
{:ok, repo} = Geef.Repository.init(path, true) {:ok, repo} = Repository.init(path, true)
{repo, path} {repo, path}
end 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 end