Work towards elixir 14

While here, make the object be an elixir struct instead of delegating to
the erlang code.

As part of this, geef_nif:commit_tree() has been fixed to return the id,
insted of the type, as we know it's going to be a tree, but not then id.
This commit is contained in:
Carlos Martín Nieto
2014-06-19 08:12:30 +02:00
parent 3cafc28a35
commit 808646a5ca
15 changed files with 155 additions and 142 deletions

View File

@@ -28,6 +28,7 @@ geef_commit_tree_id(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
ERL_NIF_TERM
geef_commit_tree(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
ErlNifBinary bin;
geef_object *obj, *tree;
ERL_NIF_TERM term_obj;
@@ -42,8 +43,10 @@ geef_commit_tree(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
term_obj = enif_make_resource(env, obj);
enif_release_resource(obj);
return enif_make_tuple3(env, atoms.ok, atoms.tree, term_obj);
if (geef_oid_bin(&bin, git_object_id(tree->obj)) < 0)
return geef_oom(env);
return enif_make_tuple3(env, atoms.ok, enif_make_binary(env, &bin), term_obj);
}
ERL_NIF_TERM

View File

@@ -1,22 +1,17 @@
defmodule Geef.Blob do
alias Geef.Object
import Object, only: :macros
use Geef
def lookup(repo, id) do
case :geef_obj.lookup(repo, id) do
{:ok, obj} ->
{:ok, Object.from_erl obj}
error ->
error
end
Object.lookup(repo, id, :blob)
end
def size(obj = Object[type: :blob]) do
:geef_blob.size(rebind(obj))
def size(obj = %Object{type: :blob, handle: handle}) do
:geef_nif.blob_size(handle)
end
def content(obj = Object[type: :blob]) do
:geef_blob.content(rebind(obj))
def content(obj = %Object{type: :blob, handle: handle}) do
:geef_nif.blob_content(handle)
end
end

View File

@@ -1,39 +1,34 @@
defmodule Geef.Commit do
use Geef
import Object, only: :macros
@type t :: Object[type: :commit]
@spec lookup(pid, Oid.t) :: Commit.t
def lookup(repo, id) do
case :geef_commit.lookup(repo, id) do
{:ok, commit} ->
{:ok, Object.from_erl commit}
error ->
error
end
Object.lookup(repo, id, :commit)
end
@spec tree_id(Object.t) :: Oid.t
def tree_id(commit = Object[type: :commit]) do
:geef_commit.tree_id(rebind(commit))
def tree_id(commit = %Object{type: :commit, handle: handle}) do
:geef_nif.commit_tree_id(handle)
end
@spec tree(t) :: {:ok, Tree.t} | {:error, any}
def tree(commit = Object[type: :commit]) do
case :geef_commit.tree(rebind(commit)) do
{:ok, tree} ->
{:ok, Object.from_erl(tree)}
def tree(commit = %Object{type: :commit, handle: handle}) do
case :geef_nif.commit_tree(handle) do
{:ok, id, handle} ->
{:ok, %Object{type: :tree, id: id, handle: handle}}
error = {:error, _} ->
error
end
end
@spec tree!(t) :: Tree.t
def tree!(commit = Object[type: :commit]), do: tree(commit) |> Geef.assert_ok
def tree!(commit = %Object{type: :commit}), do: tree(commit) |> Geef.assert_ok
@spec create(pid, Signature.t, Signature.t, iolist, Oid.t, [Oid.t], [:proplists.property()]) :: {:ok, Oid.t} | {:error, term}
def create(repo, author = Signature[], committer = Signature[], message, tree, parents, opts \\ []) do
:geef_commit.create(repo, Signature.to_erl(author), Signature.to_erl(committer), message, tree, parents, opts)
def create(repo, author = %Signature{}, committer = %Signature{}, message, tree, parents, opts \\ []) do
:geef_commit.create(repo, Signature.to_record(author), Signature.to_record(committer), message, tree, parents, opts)
end
end

View File

@@ -1,22 +1,28 @@
require Record
defmodule Geef.Index.Entry do
record = Record.extract(:geef_index_entry, from: "src/geef_records.hrl")
keys = :lists.map(&elem(&1, 0), record)
vals = :lists.map(&{&1, [], nil}, keys)
pairs = :lists.zip(keys, vals)
defstruct keys
def from_record({:geef_index_entry, unquote_splicing(vals)}) do
%Geef.Index.Entry{unquote_splicing(pairs)}
end
def to_record(%Geef.Index.Entry{unquote_splicing(pairs)}) do
{:geef_index_entry, unquote_splicing(vals)}
end
end
defmodule Geef.Index do
use Geef
alias Geef.Index.Entry
defmacrop to_erl(entry) do
quote do
set_elem(unquote(entry), 0, :geef_index_entry)
end
end
defmacrop from_erl(entry) do
quote do
set_elem(unquote(entry), 0, Geef.Index.Entry)
end
end
defp maybe_entry({:ok, entry}), do: {:ok, from_erl(entry)}
defp maybe_entry({:ok, entry}), do: {:ok, Entry.from_record(entry)}
defp maybe_entry(error = {:error, _}), do: error
@spec new :: {:ok, pid()} | :ignore | {:error, term()}
@@ -26,7 +32,7 @@ defmodule Geef.Index do
@spec add(pid(), Entry.t()) :: :ok | {:error, term()}
def add(pid, entry) do
:geef_index.add(pid, to_erl(entry))
:geef_index.add(pid, Entry.to_record(entry))
end
@spec clear(pid()) :: :ok
@@ -68,5 +74,3 @@ defmodule Geef.Index do
end
end
defrecord Geef.Index.Entry, Record.extract(:geef_index_entry, from: "src/geef_records.hrl")

View File

@@ -1,22 +1,25 @@
require Record
defrecord Geef.Iterator, Record.extract(:geef_iterator, from: "src/geef_records.hrl") do
defmodule Geef.Iterator do
alias Geef.Iterator
alias Geef.Reference
@doc false
defmacro rebind(obj) do
quote do
set_elem(unquote(obj), 0, :geef_iterator)
end
record = Record.extract(:geef_iterator, from: "src/geef_records.hrl")
keys = :lists.map(&elem(&1, 0), record)
vals = :lists.map(&{&1, [], nil}, keys)
pairs = :lists.zip(keys, vals)
defstruct keys
def from_record({:geef_iterator, unquote_splicing(vals)}) do
%Geef.Iterator{unquote_splicing(pairs)}
end
@spec from_erl(term()) :: t
def from_erl(iterator) do
set_elem(iterator, 0, Geef.Iterator)
def to_record(%Geef.Iterator{unquote_splicing(pairs)}) do
{:geef_iterator, unquote_splicing(vals)}
end
def stream!(Iterator[type: :ref, repo: repo, regexp: regexp]) do
def stream!(%Iterator{type: :ref, repo: repo, regexp: regexp}) do
iter =
case :geef_ref.iterator(repo, regexp) do
{:ok, iter} ->
@@ -27,8 +30,8 @@ defrecord Geef.Iterator, Record.extract(:geef_iterator, from: "src/geef_records.
&do_stream(iter, &1, &2)
end
defp do_stream(iter = Iterator[type: :ref], acc, fun) do
case :geef_ref.next(rebind(iter)) do
defp do_stream(iter = %Iterator{type: :ref}, acc, fun) do
case :geef_ref.next(to_record(iter)) do
{:ok, ref} ->
do_stream(iter, fun.(Reference.from_erl(ref), acc), fun)
{:error, :iterover} ->
@@ -39,4 +42,6 @@ defrecord Geef.Iterator, Record.extract(:geef_iterator, from: "src/geef_records.
end
end
defexception Geef.IteratorError, [message: nil]
defmodule Geef.IteratorError do
defexception [message: nil]
end

View File

@@ -1,26 +1,21 @@
require Record
defrecord Geef.Object, Record.extract(:geef_object, from: "src/geef_records.hrl") do
defmodule Geef.Object do
defstruct type: nil, id: nil, handle: nil
@doc false
defmacro rebind(obj) do
quote do
set_elem(unquote(obj), 0, :geef_object)
def lookup(repo, id) do
case :geef_repo.lookup_object(repo, id) do
{:ok, type, handle} ->
{:ok, %Geef.Object{type: type, id: id, handle: handle}}
error ->
error
end
end
def from_erl(obj) when elem(obj, 1) == :tree do
set_elem(obj, 0, Geef.Tree)
end
def from_erl(obj) do
set_elem(obj, 0, Geef.Object)
end
def lookup(repo, id) do
case :geef_obj.lookup(repo, id) do
def lookup(repo, id, type) do
case lookup(repo, id) do
{:ok, obj} ->
{:ok, Geef.Object.from_erl obj}
{:ok, obj = %Geef.Object{type: type}}
error ->
error
end

View File

@@ -1,6 +1,8 @@
require Record
defrecord Geef.Request, Record.extract(:geef_request, from: "src/geef_records.hrl")
defmodule Geef.Request do
defstruct Record.extract(:geef_request, from: "src/geef_records.hrl")
end
defmodule Geef.Pkt do

View File

@@ -1,13 +1,25 @@
require Record
defrecord Geef.Reference, Record.extract(:geef_reference, from: "src/geef_records.hrl") do
defmodule Geef.Reference do
import Geef
alias Geef.Reference
def from_erl(ref), do: set_elem(ref, 0, Geef.Reference)
def to_erl(ref), do: set_elem(ref, 0, :geef_reference)
record = Record.extract(:geef_reference, from: "src/geef_records.hrl")
keys = :lists.map(&elem(&1, 0), record)
vals = :lists.map(&{&1, [], nil}, keys)
pairs = :lists.zip(keys, vals)
defp maybe_ref({:ok, ref}), do: {:ok, Reference.from_erl ref}
defstruct keys
def to_record(%Geef.Reference{unquote_splicing(pairs)}) do
{:geef_reference, unquote_splicing(vals)}
end
def from_record({:geef_reference, unquote_splicing(vals)}) do
%Geef.Reference{unquote_splicing(pairs)}
end
defp maybe_ref({:ok, ref}), do: {:ok, Reference.from_record(ref)}
defp maybe_ref(err = {:error, _}), do: err
def create(repo, name, target, force \\ :false) do
@@ -26,13 +38,13 @@ defrecord Geef.Reference, Record.extract(:geef_reference, from: "src/geef_record
def lookup(repo, name), do: :geef_ref.lookup(repo, name) |> maybe_ref
def lookup!(repo, name), do: lookup(repo, name) |> assert_ok
def resolve(ref = Reference[]), do: :geef_ref.resolve(to_erl(ref)) |> maybe_ref
def resolve!(ref =Reference[]), do: resolve(ref) |> assert_ok
def resolve(ref = %Reference{}), do: :geef_ref.resolve(to_record(ref)) |> maybe_ref
def resolve!(ref = %Reference{}), do: resolve(ref) |> assert_ok
def dwim(repo, name), do: :geef_ref.dwim(repo, name) |> maybe_ref
def dwim!(repo, name), do: dwim(repo, name) |> assert_ok
def shorthand(Reference[name: name]) do
def shorthand(%Reference{name: name}) do
:geef_ref.shorthand(name)
end
def shorthand(name) do

View File

@@ -1,17 +1,17 @@
require Record
defrecord Geef.Signature, Record.extract(:geef_signature, from: "src/geef_records.hrl") do
defmodule Geef.Signature do
defstruct Record.extract(:geef_signature, from: "src/geef_records.hrl")
def now(name, email), do: :geef_sig.now(name, email) |> from_erl
def now(name, email), do: :geef_sig.now(name, email) |> from_record
def default(repo), do: :geef_sig.default(repo) |> maybe_sig
defp maybe_sig({:ok, sig}), do: from_erl(sig)
defp maybe_sig({:ok, sig}), do: from_record(sig)
defp maybe_sig(error = {:error, _}), do: error
defp from_erl(sig), do: set_elem(sig, 0, Geef.Signature)
@spec to_erl(t) :: :geef_sig.signature
def to_erl(sig), do: set_elem(sig, 0, :geef_signature)
def from_record({:geef_signature}) do
%Geef.Signature{}
end
end

View File

@@ -1,17 +1,20 @@
defmodule Geef.Tag do
alias Geef.Object
import Object, only: :macros
import Geef
def peel(tag = Object[type: :tag]) do
case :geef_tag.peel(rebind(tag)) do
{:ok, peeled} ->
{:ok, Object.from_erl peeled}
def lookup(repo, id) do
Object.lookup(repo, id, :tag)
end
def peel(tag = %Object{type: :tag, handle: handle}) do
case :geef_nif.tag_peel(handle) do
{:ok, type, id, peeled_handle} ->
{:ok, %Object{type: type, id: id, handle: peeled_handle}}
error ->
error
end
end
def peel!(tag = Object[type: :tag]), do: peel(tag) |> assert_ok
def peel!(tag = %Object{type: :tag}), do: peel(tag) |> assert_ok
end

View File

@@ -1,60 +1,67 @@
require Record
defrecord Geef.TreeEntry, Record.extract(:geef_tree_entry, from: "src/geef_records.hrl") do
@spec from_erl(term()) :: t
def from_erl(obj) do
set_elem(obj, 0, Geef.TreeEntry)
end
defmodule Geef.TreeEntry do
defstruct mode: nil, type: nil, id: nil, name: nil
end
defrecord Geef.Tree, Record.extract(:geef_object, from: "src/geef_records.hrl") do
defmodule Geef.Tree do
alias Geef.Object
alias Geef.TreeEntry
import Object, only: :macros
@type t :: Object[type: :commit]
@type t :: Object[type: :tree]
def lookup(repo, id) do
case :geef_tree.lookup(repo, id) do
{:ok, obj} ->
{:ok, Object.from_erl obj}
error ->
error
end
Object.lookup(repo, id, :tree)
end
defp maybe_entry({:ok, entry}), do: {:ok, TreeEntry.from_erl entry}
defp maybe_entry({:ok, mode, type, id, name}) do
{:ok, %TreeEntry{mode: mode, type: type, id: id, name: name}}
end
defp maybe_entry(error = {:error, _}), do: error
def get(tree, path), do: :geef_tree.get(rebind(tree), path) |> maybe_entry
def nth(tree, pos), do: :geef_tree.nth(rebind(tree), pos) |> maybe_entry
def get(%Object{type: :tree, handle: handle}, path) do
:geef_nif.tree_bypath(handle, path) |> maybe_entry
end
def count(tree), do: :geef_tree.count(rebind(tree))
def nth(%Object{type: :tree, handle: handle}, nth) do
:geef_nif.tree_nth(handle, nth) |> maybe_entry
end
def count(%Object{type: :tree, handle: handle}) do
:geef_nif.tree_count(handle)
end
end
defimpl Access, for: Geef.Tree do
defimpl Access, for: Geef.Object do
alias Geef.Object
alias Geef.Tree
def access(tree, key) when is_number(key) do
def get(tree = %Object{type: :tree}, key) when is_number(key) do
case Tree.nth(tree, key) do
{:ok, entry} -> entry
{:error, _} -> nil
end
end
def access(tree, key) do
def get(tree = %Object{type: :tree}, key) do
case Tree.get(tree, key) do
{:ok, entry} -> entry
{:error, _} -> nil
end
end
# Git data is immutable
def get_and_update(_tree, _key, _fun) do
raise ArgumentError
end
end
defexception Geef.TreeError, reason: nil do
def message(Geef.TreeError[reason: reason]) do
defmodule Geef.TreeError do
defexception [reason: nil]
def message(%Geef.TreeError{reason: reason}) do
"tree error #{inspect reason}"
end
end

View File

@@ -14,8 +14,8 @@ tree_id(#geef_object{type=commit,handle=Handle}) ->
-spec tree(commit()) -> {ok, geef_tree:tree()} | {error, term()}.
tree(#geef_object{type=commit,handle=Handle}) ->
case geef_nif:commit_tree(Handle) of
{ok, Type, Handle} ->
{ok, #geef_object{type=Type, handle=Handle}};
{ok, Id, Handle} ->
{ok, #geef_object{id=Id, handle=Handle}};
Other ->
Other
end.

View File

@@ -1,21 +1,15 @@
Code.require_file "../test_helper.exs", __FILE__
defmodule ObjectTest do
use ExUnit.Case
use Geef
import RepoHelpers
setup do
{{:ok, repo}, path} = tmp_bare()
{repo, path} = tmp_bare()
Process.link(repo)
on_exit(fn -> File.rm_rf!(path) end)
{:ok, [repo: repo, path: path]}
end
teardown meta do
Repository.stop(meta[:repo])
File.rm_rf!(meta[:path])
:ok
end
test "object OO helpers", meta do
repo = meta[:repo]
{ :ok, odb } = Repository.odb(repo)
@@ -23,5 +17,7 @@ defmodule ObjectTest do
content = "I'm some content"
Odb.write(odb, content, :blob)
Repository.stop(repo)
end
end

View File

@@ -1,21 +1,14 @@
Code.require_file "../test_helper.exs", __FILE__
defmodule ReferenceTest do
use ExUnit.Case
use Geef
import RepoHelpers
setup do
{{:ok, repo}, path} = tmp_bare()
{repo, path} = tmp_bare()
on_exit(fn -> File.rm_rf!(path) end)
{:ok, [repo: repo, path: path]}
end
teardown meta do
Repository.stop(meta[:repo])
File.rm_rf!(meta[:path])
:ok
end
test "creating and looking up", meta do
repo = meta[:repo]
{ :ok, odb } = Repository.odb(repo)
@@ -25,12 +18,14 @@ defmodule ReferenceTest do
refname = "refs/tags/foo"
{:ok, ref} = Reference.create(repo, refname, id)
{:ok, looked_up} = Reference.lookup(repo, refname)
ref == looked_up
assert ref == looked_up
refname = "refs/tags/foo2"
{:ok, ref} = Reference.create_symbolic(repo, refname, id)
{:ok, looked_up} = Reference.lookup(repo, refname)
ref == looked_up
assert ref == looked_up
Repository.stop(repo)
end
end

View File

@@ -6,6 +6,7 @@ defmodule RepoHelpers do
n = node()
dir = :io_lib.format("geef-~p~p~p~p.git", [n, a, b, c])
path = Path.join(System.tmp_dir!, dir)
{Geef.Repository.init(path, true), path}
{:ok, repo} = Geef.Repository.init(path, true)
{repo, path}
end
end