diff --git a/.gitignore b/.gitignore
index b2e22f0..556991d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,5 +39,6 @@ npm-debug.log
/priv/repo/dumps/
/priv/static/
+/bin/gitport
/bin/size
*.o
diff --git a/Makefile b/Makefile
index 90c84be..3af7cc2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,28 @@
-PROG = bin/size
-SRC = c_src/size.c
-SRC_O = c_src/size.o
+gitport = bin/gitport
+gitport_SRC = c_src/gitport.c
+gitport_SRC_O = c_src/gitport.o
+gitport_LIBS = -lgit2
-all: ${PROG}
+size = bin/size
+size_SRC = c_src/size.c
+size_SRC_O = c_src/size.o
+size_LIBS =
-${PROG}: ${SRC_O}
- ${CC} ${CFLAGS} ${LDFLAGS} ${SRC_O} ${LIBS} -o ${PROG}
+PROGS = ${gitport} ${size}
+
+all: ${PROGS}
+
+${gitport}: ${gitport_SRC_O}
+ ${CC} ${CFLAGS} ${LDFLAGS} ${gitport_SRC_O} ${gitport_LIBS} -o ${gitport}
+
+${size}: ${size_SRC_O}
+ ${CC} ${CFLAGS} ${LDFLAGS} ${size_SRC_O} ${size_LIBS} -o ${size}
.c.o:
${CC} ${CPPFLAGS} ${CFLAGS} -c $< -o $@
clean:
- rm -f ${SRC_O} ${PROG}
+ rm -f c_src/*.o ${PROGS}
.PHONY: all clean
diff --git a/c_src/gitport.c b/c_src/gitport.c
new file mode 100644
index 0000000..7f2a8b3
--- /dev/null
+++ b/c_src/gitport.c
@@ -0,0 +1,109 @@
+#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 79c4264..d906375 100644
--- a/lib/kmxgit/application.ex
+++ b/lib/kmxgit/application.ex
@@ -10,6 +10,7 @@ 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
new file mode 100644
index 0000000..c506f15
--- /dev/null
+++ b/lib/kmxgit/git.ex
@@ -0,0 +1,52 @@
+defmodule Kmxgit.Git do
+ use GenServer
+
+ @git_root "priv/git"
+
+ def start_link(opts) do
+ GenServer.start_link(__MODULE__, opts, name: __MODULE__)
+ end
+
+ # Functions
+
+ def branches(repo) do
+ GenServer.call(__MODULE__, {:branches, repo})
+ |> String.trim()
+ |> String.split(" ")
+ 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)}}
+ end
+
+ # common functions
+
+ def git_dir(repo) do
+ if String.match?(repo, ~r/(^|\/)\.\.($|\/)/), do: raise "invalid git dir"
+ "#{@git_root}/#{repo}.git"
+ end
+end