diff --git a/c_src/git_nif.c b/c_src/git_nif.c
index b92d923..6e73253 100644
--- a/c_src/git_nif.c
+++ b/c_src/git_nif.c
@@ -4,43 +4,15 @@
#include <erl_nif.h>
#include <git2.h>
-static char * enif_term_to_string (ErlNifEnv *env, const ERL_NIF_TERM term)
-{
- ErlNifBinary bin;
- unsigned len;
- char *str;
- switch (enif_term_type(env, term)) {
- case ERL_NIF_TERM_TYPE_BITSTRING:
- enif_inspect_binary(env, term, &bin);
- len = bin.size;
- str = malloc(len + 1);
- memcpy(str, bin.data, len);
- str[len] = 0;
- return str;
- case ERL_NIF_TERM_TYPE_LIST:
- enif_get_list_length(env, term, &len);
- str = malloc(len + 1);
- enif_get_string(env, term, str, len + 1, ERL_NIF_LATIN1);
- return str;
- default:
- return NULL;
- }
-}
-
-static ERL_NIF_TERM enif_string_to_term (ErlNifEnv *env, const char *str)
-{
- size_t len = strlen(str);
- ErlNifBinary bin;
- enif_alloc_binary(len, &bin);
- memcpy(bin.data, str, len);
- return enif_make_binary(env, &bin);
-}
-
-static ERL_NIF_TERM push_string (ErlNifEnv *env, const char *str, const ERL_NIF_TERM acc)
-{
- ERL_NIF_TERM term = enif_string_to_term(env, str);
- return enif_make_list_cell(env, term, acc);
-}
+static ERL_NIF_TERM enif_string_to_term (ErlNifEnv *env,
+ const char *str);
+static char * enif_term_to_string (ErlNifEnv *env,
+ const ERL_NIF_TERM term);
+static ERL_NIF_TERM git_nif_file (ErlNifEnv *env,
+ const git_tree_entry *entry,
+ const char *name);
+static ERL_NIF_TERM push_string (ErlNifEnv *env, const char *str,
+ const ERL_NIF_TERM acc);
static ERL_NIF_TERM branches_nif (ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[])
@@ -59,7 +31,7 @@ static ERL_NIF_TERM branches_nif (ErlNifEnv *env, int argc,
repo = enif_term_to_string(env, argv[0]);
if (!repo || !repo[0])
goto error;
- if (git_repository_open(&r, repo))
+ if (git_repository_open_bare(&r, repo))
goto error;
git_branch_iterator_new(&i, r, GIT_BRANCH_ALL);
acc = enif_make_list(env, 0);
@@ -101,7 +73,7 @@ static ERL_NIF_TERM content_nif (ErlNifEnv *env, int argc,
sha = enif_term_to_string(env, argv[1]);
if (!sha || !sha[0])
goto error;
- if (git_repository_open(&r, repo))
+ if (git_repository_open_bare(&r, repo))
goto error;
if (git_oid_fromstr(&oid, sha))
goto error;
@@ -124,40 +96,70 @@ static ERL_NIF_TERM content_nif (ErlNifEnv *env, int argc,
return enif_make_atom(env, "error");
}
-static ERL_NIF_TERM git_tree_entry_file_map (ErlNifEnv *env,
- const git_tree_entry *entry,
- const char *name)
+static ERL_NIF_TERM create_nif (ErlNifEnv *env, int argc,
+ const ERL_NIF_TERM argv[])
{
- git_object_t type;
- git_filemode_t mode;
- char sha[41];
- ERL_NIF_TERM k[4];
- ERL_NIF_TERM v[4];
- ERL_NIF_TERM file;
- if (!name) {
- fprintf(stderr, "name\n");
- name = git_tree_entry_name(entry);
+ ERL_NIF_TERM ok;
+ git_repository *r = NULL;
+ char *repo_dir = NULL;
+ ERL_NIF_TERM res;
+ if (argc != 1 || !argv || !argv[0]) {
+ res = enif_make_atom(env, "badarg");
+ goto error;
+ }
+ repo_dir = enif_term_to_string(env, argv[0]);
+ if (!repo_dir || !repo_dir[0]) {
+ res = enif_make_atom(env, "repo_dir_missing");
+ goto error;
+ }
+ if (git_repository_init(&r, repo_dir, 1)) {
+ res = enif_make_atom(env, "git_repository_init");
+ goto error;
+ }
+ git_repository_free(r);
+ free(repo_dir);
+ ok = enif_make_atom(env, "ok");
+ return ok;
+ error:
+ res = enif_make_tuple2(env, enif_make_atom(env, "error"), res);
+ enif_fprintf(stderr, "%T\n", res);
+ git_repository_free(r);
+ free(repo_dir);
+ return res;
+}
+
+static ERL_NIF_TERM enif_string_to_term (ErlNifEnv *env,
+ const char *str)
+{
+ size_t len = strlen(str);
+ ErlNifBinary bin;
+ enif_alloc_binary(len, &bin);
+ memcpy(bin.data, str, len);
+ return enif_make_binary(env, &bin);
+}
+
+static char * enif_term_to_string (ErlNifEnv *env,
+ const ERL_NIF_TERM term)
+{
+ ErlNifBinary bin;
+ unsigned len;
+ char *str;
+ switch (enif_term_type(env, term)) {
+ case ERL_NIF_TERM_TYPE_BITSTRING:
+ enif_inspect_binary(env, term, &bin);
+ len = bin.size;
+ str = malloc(len + 1);
+ memcpy(str, bin.data, len);
+ str[len] = 0;
+ return str;
+ case ERL_NIF_TERM_TYPE_LIST:
+ enif_get_list_length(env, term, &len);
+ str = malloc(len + 1);
+ enif_get_string(env, term, str, len + 1, ERL_NIF_LATIN1);
+ return str;
+ default:
+ return NULL;
}
- fprintf(stderr, "type\n");
- type = git_tree_entry_type(entry);
- fprintf(stderr, "mode\n");
- mode = git_tree_entry_filemode(entry);
- fprintf(stderr, "git_oid_tostr\n");
- git_oid_tostr(sha, 41, git_tree_entry_id(entry));
- k[0] = enif_make_atom(env, "name");
- v[0] = enif_string_to_term(env, name);
- k[1] = enif_make_atom(env, "type");
- if (type == GIT_OBJECT_TREE)
- v[1] = enif_make_atom(env, "tree");
- else
- v[1] = enif_make_atom(env, "blob");
- k[2] = enif_make_atom(env, "mode");
- v[2] = enif_make_int64(env, mode);
- k[3] = enif_make_atom(env, "sha1");
- v[3] = enif_string_to_term(env, sha);
- fprintf(stderr, "enif_make_map_from_arrays\n");
- enif_make_map_from_arrays(env, k, v, 4, &file);
- return file;
}
static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
@@ -202,10 +204,9 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
rev = malloc(rev_size);
strlcpy(rev, tree_name, rev_size);
strlcat(rev, "^{tree}", rev_size);
- fprintf(stderr, "files_nif '%s' '%s' '%s'\n", repo_dir, rev, path);
ok = enif_make_atom(env, "ok");
- if (git_repository_open(&r, repo_dir)) {
- res = enif_make_atom(env, "git_repository_open");
+ if (git_repository_open_bare(&r, repo_dir)) {
+ res = enif_make_atom(env, "git_repository_open_bare");
goto error;
}
if (git_revparse_single(&obj, r, rev)) {
@@ -213,7 +214,6 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
goto error;
}
tree = (git_tree*) obj;
- fprintf(stderr, "tree: %p\nentry\n", tree);
if (!path[0] || !strcmp(path, "."))
subtree = tree;
else {
@@ -221,13 +221,11 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
res = enif_make_atom(env, "git_tree_entry_bypath");
goto error;
}
- fprintf(stderr, "type\n");
type = git_tree_entry_type(entry);
switch (type) {
case GIT_OBJECT_BLOB:
- file = git_tree_entry_file_map(env, entry, path);
+ file = git_nif_file(env, entry, path);
files = enif_make_list(env, 1, file);
- fprintf(stderr, "free blob\n");
git_repository_free(r);
free(repo_dir);
free(tree_name);
@@ -235,7 +233,6 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
git_tree_entry_free(entry);
return enif_make_tuple2(env, ok, files);
case GIT_OBJECT_TREE:
- fprintf(stderr, "subtree\n");
if (git_tree_lookup(&subtree, r, git_tree_entry_id(entry))) {
res = enif_make_atom(env, "git_tree_lookup");
goto error;
@@ -246,18 +243,14 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
goto error;
}
}
- fprintf(stderr, "loop\n");
files = enif_make_list(env, 0);
count = git_tree_entrycount(subtree);
while (count--) {
const git_tree_entry *sub_entry;
- fprintf(stderr, "sub_entry\n");
sub_entry = git_tree_entry_byindex(subtree, count);
- file = git_tree_entry_file_map(env, sub_entry, NULL);
+ file = git_nif_file(env, sub_entry, NULL);
files = enif_make_list_cell(env, file, files);
- enif_fprintf(stderr, "files = %T\n", files);
}
- fprintf(stderr, "free\n");
git_repository_free(r);
free(repo_dir);
free(tree_name);
@@ -275,14 +268,62 @@ static ERL_NIF_TERM files_nif (ErlNifEnv *env, int argc,
return res;
}
-static ERL_NIF_TERM create_nif (ErlNifEnv *env, int argc,
- const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM git_nif_file (ErlNifEnv *env,
+ const git_tree_entry *entry,
+ const char *name)
+{
+ git_object_t type;
+ git_filemode_t mode;
+ char sha[41];
+ ERL_NIF_TERM k[4];
+ ERL_NIF_TERM v[4];
+ ERL_NIF_TERM file;
+ if (!name) {
+ name = git_tree_entry_name(entry);
+ }
+ type = git_tree_entry_type(entry);
+ mode = git_tree_entry_filemode(entry);
+ git_oid_tostr(sha, 41, git_tree_entry_id(entry));
+ k[0] = enif_make_atom(env, "name");
+ v[0] = enif_string_to_term(env, name);
+ k[1] = enif_make_atom(env, "type");
+ if (type == GIT_OBJECT_TREE)
+ v[1] = enif_make_atom(env, "tree");
+ else
+ v[1] = enif_make_atom(env, "blob");
+ k[2] = enif_make_atom(env, "mode");
+ v[2] = enif_make_int64(env, mode);
+ k[3] = enif_make_atom(env, "sha1");
+ v[3] = enif_string_to_term(env, sha);
+ fprintf(stderr, "enif_make_map_from_arrays\n");
+ enif_make_map_from_arrays(env, k, v, 4, &file);
+ return file;
+}
+
+int load (ErlNifEnv *env, void **a, ERL_NIF_TERM b)
{
+ (void) env;
+ (void) a;
+ (void) b;
+ fprintf(stderr, "git_nif load\n");
+ git_libgit2_init();
+ return 0;
+}
+
+static ERL_NIF_TERM log_nif (ErlNifEnv *env, int argc,
+ const ERL_NIF_TERM argv[])
+{
+ char *branch_name = NULL;
+ git_diff_options diffopts = {GIT_DIFF_OPTIONS_VERSION, 0, GIT_SUBMODULE_IGNORE_UNSPECIFIED, {NULL, 0}, NULL, NULL, NULL, 3, 0, 0, 0, 0, 0};
+ git_oid oid;
ERL_NIF_TERM ok;
+ char *path = NULL;
+ git_pathspec *ps = NULL;
git_repository *r = NULL;
char *repo_dir = NULL;
ERL_NIF_TERM res;
- if (argc != 1 || !argv || !argv[0]) {
+ git_revwalk *walker;
+ if (argc != 3 || !argv || !argv[0] || !argv[1] || !argv[2]) {
res = enif_make_atom(env, "badarg");
goto error;
}
@@ -291,37 +332,49 @@ static ERL_NIF_TERM create_nif (ErlNifEnv *env, int argc,
res = enif_make_atom(env, "repo_dir_missing");
goto error;
}
- if (git_repository_init(&r, repo_dir, 1)) {
- res = enif_make_atom(env, "git_repository_init");
+ branch_name = enif_term_to_string(env, argv[1]);
+ if (!branch_name || !branch_name[0]) {
+ res = enif_make_atom(env, "branch_name_missing");
+ goto error;
+ }
+ path = enif_term_to_string(env, argv[2]);
+ if (!path) {
+ res = enif_make_atom(env, "path_missing");
goto error;
}
+ if (git_repository_open_bare(&r, repo_dir)) {
+ res = enif_make_atom(env, "git_repository_open_bare");
+ goto error;
+ }
+ diffopts.pathspec.strings = &path;
+ diffopts.pathspec.count = 1;
+ if (diffopts.pathspec.count > 0)
+ git_pathspec_new(&ps, &diffopts.pathspec);
+
git_repository_free(r);
free(repo_dir);
+ free(branch_name);
+ free(path);
ok = enif_make_atom(env, "ok");
- return ok;
+ res = enif_make_list(env, 0);
+ res = enif_make_tuple2(env, ok, res);
+ return res;
error:
res = enif_make_tuple2(env, enif_make_atom(env, "error"), res);
enif_fprintf(stderr, "%T\n", res);
git_repository_free(r);
free(repo_dir);
+ free(branch_name);
+ free(path);
+
return res;
}
-static ErlNifFunc funcs[] = {
- {"branches_nif", 1, branches_nif, 0},
- {"content_nif", 2, content_nif, 0},
- {"create_nif", 1, create_nif, 0},
- {"files_nif", 3, files_nif, 0},
-};
-
-int load (ErlNifEnv *env, void **a, ERL_NIF_TERM b)
+static ERL_NIF_TERM push_string (ErlNifEnv *env, const char *str,
+ const ERL_NIF_TERM acc)
{
- (void) env;
- (void) a;
- (void) b;
- fprintf(stderr, "git_nif load\n");
- git_libgit2_init();
- return 0;
+ ERL_NIF_TERM term = enif_string_to_term(env, str);
+ return enif_make_list_cell(env, term, acc);
}
void unload (ErlNifEnv *env, void *a)
@@ -332,4 +385,12 @@ void unload (ErlNifEnv *env, void *a)
fprintf(stderr, "git_nif unload\n");
}
+static ErlNifFunc funcs[] = {
+ {"branches_nif", 1, branches_nif, 0},
+ {"content_nif", 2, content_nif, 0},
+ {"create_nif", 1, create_nif, 0},
+ {"files_nif", 3, files_nif, 0},
+ {"log_nif", 3, log_nif, 0},
+};
+
ERL_NIF_INIT(Elixir.Kmxgit.Git, funcs, load, NULL, NULL, unload);
diff --git a/lib/kmxgit/git.ex b/lib/kmxgit/git.ex
index 0fa85f2..69241ba 100644
--- a/lib/kmxgit/git.ex
+++ b/lib/kmxgit/git.ex
@@ -3,10 +3,11 @@ defmodule Kmxgit.Git do
@git_root "priv/git"
- def init do
- path = "bin/libgit_nif"
- |> String.to_charlist()
- :ok = :erlang.load_nif(path, 0)
+ # common functions
+
+ def git_dir(repo) do
+ if String.match?(repo, ~r/(^|\/)\.\.($|\/)/), do: raise "invalid git dir"
+ "#{@git_root}/#{repo}.git"
end
# NIFs
@@ -59,10 +60,20 @@ defmodule Kmxgit.Git do
exit(:nif_not_loaded)
end
- # common functions
+ def init do
+ path = "bin/libgit_nif"
+ |> String.to_charlist()
+ :ok = :erlang.load_nif(path, 0)
+ end
- def git_dir(repo) do
- if String.match?(repo, ~r/(^|\/)\.\.($|\/)/), do: raise "invalid git dir"
- "#{@git_root}/#{repo}.git"
+ def log(repo, tree \\ "HEAD", path \\ "") do
+ tree = tree || "HEAD"
+ dir = git_dir(repo)
+ log_nif(dir, tree, path)
+ # %{author: author, author_email: email, hash: hash, date: date, message: msg}
+ end
+
+ def log_nif(repo, tree, path) do
+ exit(:nif_not_loaded)
end
end
diff --git a/lib/kmxgit_web/controllers/repository_controller.ex b/lib/kmxgit_web/controllers/repository_controller.ex
index ebfde53..38c937d 100644
--- a/lib/kmxgit_web/controllers/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/repository_controller.ex
@@ -346,12 +346,7 @@ defmodule KmxgitWeb.RepositoryController do
defp git_log(repo, tree, path) do
slug = Repository.full_slug(repo)
- result = if path do
- GitManager.log_file(slug, path, tree)
- else
- GitManager.log(slug, tree)
- end
- case result do
+ case Git.log(slug, tree, path || "") do
{:ok, log} -> log
{:error, reason} ->
Logger.error(inspect(reason))