diff --git a/Makefile b/Makefile
index 3af7cc2..0cbb1ef 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,25 @@
-gitport = bin/gitport
-gitport_SRC = c_src/gitport.c
-gitport_SRC_O = c_src/gitport.o
-gitport_LIBS = -lgit2
+CFLAGS = -W -Wall -Werror
+CPPFLAGS = -I/usr/local/include -I/usr/local/lib/erlang24/usr/include
+LDFLAGS = -L/usr/local/lib -L/usr/local/lib/erlang24/usr/lib
+
+git_nif = bin/libgit_nif.so
+git_nif_SRC = c_src/git_nif.c
+git_nif_SRC_O = c_src/git_nif.o
+git_nif_LIBS = -lgit2
size = bin/size
size_SRC = c_src/size.c
size_SRC_O = c_src/size.o
size_LIBS =
-PROGS = ${gitport} ${size}
+PROGS = ${git_nif} ${size}
all: ${PROGS}
+${git_nif}: ${git_nif_SRC_O}
+ ${CC} -fPIC -shared ${LDFLAGS} ${git_nif_SRC_O} ${git_nif_LIBS} -o ${git_nif}
+
${gitport}: ${gitport_SRC_O}
${CC} ${CFLAGS} ${LDFLAGS} ${gitport_SRC_O} ${gitport_LIBS} -o ${gitport}
diff --git a/c_src/git_nif.c b/c_src/git_nif.c
new file mode 100644
index 0000000..e556e8a
--- /dev/null
+++ b/c_src/git_nif.c
@@ -0,0 +1,104 @@
+#include <erl_nif.h>
+#include <git2.h>
+#include <stdlib.h>
+#include <string.h>
+
+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;
+ }
+}
+
+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);
+}
+
+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 branches (ErlNifEnv *env, int argc,
+ const ERL_NIF_TERM argv[])
+{
+ git_repository *r = NULL;
+ git_branch_iterator *i = NULL;
+ git_reference *ref = NULL;
+ git_branch_t ref_type = 0;
+ char *branch = NULL;
+ char *path = NULL;
+ ERL_NIF_TERM branches;
+ fprintf(stderr, "branches %d\n", argc);
+ if (argc != 1 || !argv || !argv[0])
+ goto error;
+ path = enif_term_to_string(env, argv[0]);
+ fprintf(stderr, "path: '%s'\n", path);
+ if (!path || !path[0])
+ goto error;
+ if (git_repository_open(&r, path))
+ goto error;
+ git_branch_iterator_new(&i, r, GIT_BRANCH_ALL);
+ branches = enif_make_list(env, 0);
+ while (!git_branch_next(&ref, &ref_type, i)) {
+ git_branch_name((const char **) &branch, ref);
+ fprintf(stderr, " %s", branch);
+ branches = push_string(env, branch, branches);
+ }
+ git_branch_iterator_free(i);
+ free(path);
+ //free(branch);
+ fprintf(stderr, "\n");
+ return branches;
+ error:
+ fprintf(stderr, "error\n");
+ free(path);
+ //free(branch);
+ return enif_make_atom(env, "error");
+}
+
+static ErlNifFunc funcs[] = {
+ {"branches_nif", 1, branches, 0},
+};
+
+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;
+}
+
+void unload (ErlNifEnv *env, void *a)
+{
+ (void) env;
+ (void) a;
+ git_libgit2_shutdown();
+ fprintf(stderr, "git_nif unload\n");
+}
+
+ERL_NIF_INIT(Elixir.Kmxgit.Git, funcs, load, NULL, NULL, unload);
diff --git a/c_src/gitport.c b/c_src/gitport.c
deleted file mode 100644
index 7f2a8b3..0000000
--- a/c_src/gitport.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <git2.h>
-
-typedef int (*f_fun) (int argc, const char **argv);
-
-typedef struct fun {
- const char *name;
- f_fun fun;
-} s_fun;
-
-int branches (int argc, const char **argv)
-{
- const char *path;
- git_repository **r = malloc(sizeof(void*));
- git_branch_iterator **i = malloc(sizeof(void*));
- git_reference **ref = malloc(sizeof(void*));
- git_branch_t *ref_type = malloc(sizeof(git_branch_t));
- const char **branch = malloc(sizeof(void*));
- fprintf(stderr, "branches %d\n", argc);
- if (argc != 1 || !argv || !argv[1])
- goto error;
- path = argv[1];
- if (git_repository_open(r, path))
- goto error;
- git_branch_iterator_new(i, *r, GIT_BRANCH_ALL);
- while (!git_branch_next(ref, ref_type, *i)) {
- git_branch_name(branch, *ref);
- fprintf(stderr, " %s", *branch);
- printf(" %s", *branch);
- }
- git_branch_iterator_free(*i);
- free(i);
- free(r);
- free(ref);
- free(ref_type);
- free(branch);
- fprintf(stderr, "\n");
- printf("\n");
- fflush(stdout);
- return 0;
- error:
- fprintf(stderr, "error\n");
- printf("error\n");
- free(i);
- free(r);
- free(ref);
- free(ref_type);
- free(branch);
- return 1;
-}
-
-s_fun g_fun[] = {
- {"branches", branches},
- {NULL, NULL}
-};
-
-f_fun find_fun (const char *name)
-{
- s_fun *f = g_fun;
- while (f->name && strcmp(name, f->name))
- f++;
- if (f->name)
- return f->fun;
- return NULL;
-}
-
-int repl (FILE *in)
-{
- int ret = 0;
- int run = 1;
- ssize_t size = 1024;
- char *line = malloc(size);
- int argc;
- char **argv = malloc(sizeof(char*) * 16);
- char *argvp;
- f_fun f = NULL;
- if (!line)
- return -1;
- while (1) {
- size = getline(&line, &size, in);
- if (size < 0)
- break;
- if (size == 0)
- continue;
- line[size - 1] = 0;
- argvp = line;
- argc = 0;
- while ((argv[argc] = strsep(&argvp, " ")))
- argc++;
- argc--;
- if ((f = find_fun(argv[0]))) {
- f(argc, (const char **) argv);
- }
- }
- free(line);
- return ret;
-}
-
-int main (int argc, char **argv)
-{
- fprintf(stderr, "gitport started\n");
- git_libgit2_init();
- repl(stdin);
- git_libgit2_shutdown();
- fprintf(stderr, "gitport exiting\n");
- return 0;
-}
diff --git a/lib/kmxgit/application.ex b/lib/kmxgit/application.ex
index d906375..79c4264 100644
--- a/lib/kmxgit/application.ex
+++ b/lib/kmxgit/application.ex
@@ -10,7 +10,6 @@ defmodule Kmxgit.Application do
children = [
# Start the Ecto repository
Kmxgit.Repo,
- Kmxgit.Git,
# Start the Telemetry supervisor
KmxgitWeb.Telemetry,
# Start the PubSub system
diff --git a/lib/kmxgit/git.ex b/lib/kmxgit/git.ex
index c506f15..baf3f7a 100644
--- a/lib/kmxgit/git.ex
+++ b/lib/kmxgit/git.ex
@@ -1,46 +1,25 @@
defmodule Kmxgit.Git do
- use GenServer
+ @on_load :init
@git_root "priv/git"
- def start_link(opts) do
- GenServer.start_link(__MODULE__, opts, name: __MODULE__)
+ def init do
+ path = "bin/libgit_nif"
+ |> String.to_charlist()
+ :ok = :erlang.load_nif(path, 0)
end
# Functions
def branches(repo) do
- GenServer.call(__MODULE__, {:branches, repo})
- |> String.trim()
- |> String.split(" ")
+ repo
+ |> git_dir()
+ |> IO.inspect()
+ |> branches_nif()
end
- # Callbacks
-
- @impl true
- def init(_) do
- cmd = {:spawn_executable, "bin/gitport"}
- IO.inspect(cmd)
- port = Port.open(cmd, [:binary])
- {:ok, %{from: [], port: port}}
- end
-
- @impl true
- def handle_call(arg = {:branches, repo}, from, state) do
- IO.inspect({:handle_cast, arg})
- dir = git_dir(repo)
- cmd = "branches #{dir}\n"
- send(state.port, {self(), {:command, cmd}})
- {:noreply, %{state | from: state.from ++ [from]}}
- end
-
- @impl true
- def handle_info(arg = {port, {:data, data}}, state = %{from: [from | rest], port: port}) do
- GenServer.reply(from, data)
- {:noreply, %{state | from: rest}}
- end
- def handle_info(arg, state) do
- {:noreply, %{state | from: tl(state.from)}}
+ def branches_nif(_path) do
+ exit(:nif_not_loaded)
end
# common functions