Commit 1cd85fb5244fe5c92d0a94fe8a67d4f5af747f62

Thomas de Grivel 2022-05-02T18:12:13

use gitport for branches

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