ref: f12b2f1cd7cd26033457a54454456158e1572834
author: sirjofri <sirjofri@sirjofri.de>
date: Tue Jun 11 13:52:22 EDT 2024
working commit, add, rm
--- /dev/null
+++ b/git.c
@@ -1,0 +1,220 @@
+#include <u.h>
+#include <libc.h>
+#include "git.h"
+
+char *Enoinit = "not initialized";
+
+char *gitdir = "/mnt/git";
+int initialized = 0;
+char *repodir = nil;
+char *indexfile = nil;
+
+enum {
+ FAIL = 0,
+ SUCCESS = 1,
+};
+
+enum {
+ ADD,
+ BRANCH,
+ COMMIT,
+ DIFF,
+ LOG,
+ RM,
+};
+
+char *cmds[] = {
+ [ADD] nil,
+ [BRANCH] nil,
+ [COMMIT] "/bin/git/commit",
+ [DIFF] nil,
+ [LOG] nil,
+ [RM] nil,
+};
+
+char *cname[] = {
+ [ADD] nil,
+ [BRANCH] nil,
+ [COMMIT] "commit",
+ [DIFF] nil,
+ [LOG] nil,
+ [RM] nil,
+};
+
+static int
+isinitialized(void)
+{
+ return initialized;
+}
+#define checkinitialized() if (!isinitialized()){ werrstr(Enoinit); return FAIL; }
+
+int
+initgit(char *dir)
+{
+ if (initialized) {
+ werrstr("already initialized");
+ return FAIL;
+ }
+
+ repodir = strdup(dir);
+ indexfile = smprint("%s/.git/INDEX9", dir);
+ if (!repodir || !indexfile) {
+ if (repodir) free(repodir);
+ if (indexfile) free(indexfile);
+ return FAIL;
+ }
+
+ switch (fork()) {
+ case 0: /* child */
+ if (chdir(dir) < 0)
+ sysfatal("unable to chdir: %r");
+ execl("/bin/git/fs", "fs", "-m", gitdir, nil);
+ sysfatal("unable to exec: %r");
+ break;
+ case -1: /* error */
+ werrstr("unable to fork: %r");
+ return FAIL;
+ break;
+ default: /* parent */
+ break;
+ }
+ initialized = 1;
+ return SUCCESS;
+}
+
+/* args[0] reserved for argv0 */
+static int
+gitcmd(int cmd, char **args)
+{
+ int pid;
+ char *c;
+ Waitmsg *wmsg;
+
+ c = cmds[cmd];
+ if (!c) {
+ werrstr("not implemented");
+ return FAIL;
+ }
+ args[0] = cname[cmd];
+
+ fprint(2, "command: %s", c);
+ for (char **a = args; *a; a++)
+ fprint(2, " '%s'", *a);
+ fprint(2, "\n");
+
+ switch (pid = fork()) {
+ case 0: /* child */
+ if (chdir(repodir) < 0)
+ sysfatal("%r");
+ exec(c, args);
+ break;
+ case -1: /* error */
+ werrstr("unable to fork: %r");
+ return FAIL;
+ break;
+ default: /* parent */
+ break;
+ }
+
+ for (;;) {
+ wmsg = wait();
+ if (wmsg->pid == pid)
+ break;
+ }
+
+ if (wmsg->msg && *wmsg->msg) {
+ werrstr("%s", wmsg->msg);
+ free(wmsg);
+ return FAIL;
+ }
+ if (wmsg) free(wmsg);
+ return SUCCESS;
+}
+
+int
+gitcommit(char *msg, char *file, ...)
+{
+ va_list args;
+ char *files[32];
+ char *f;
+ int nfile = 1;
+
+ checkinitialized();
+
+ files[nfile++] = "-m";
+ files[nfile++] = msg;
+
+ files[nfile++] = file;
+
+ va_start(args, file);
+ while (f = va_arg(args, char*)) {
+ files[nfile++] = f;
+ if (nfile >= sizeof(files)) {
+ files[nfile] = nil;
+ if (!gitcmd(COMMIT, files))
+ return FAIL;
+ nfile = 3;
+ }
+ }
+ va_end(args);
+
+ if (nfile > 3) {
+ files[nfile] = nil;
+ if (!gitcmd(COMMIT, files))
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static int
+gitaddrm(char *F, char *file, va_list args)
+{
+ char *ofile;
+ int fd;
+
+ ofile = strdup(file);
+ file = cleanname(ofile);
+
+ fd = open(indexfile, OWRITE);
+ if (fd < 0)
+ return FAIL;
+ seek(fd, 0, 2);
+
+ fprint(fd, "%s NOQID 0 %s\n", F, file);
+ free(ofile);
+
+ while ((ofile = va_arg(args, char*)) != nil) {
+ ofile = strdup(ofile);
+ file = cleanname(ofile);
+
+ fprint(fd, "%s NOQID 0 %s\n", F, file);
+ free(ofile);
+ }
+
+ va_end(args);
+ close(fd);
+ return SUCCESS;
+}
+
+int
+gitadd(char *file, ...)
+{
+ va_list args;
+
+ checkinitialized();
+
+ va_start(args, file);
+ return gitaddrm("A", file, args);
+}
+
+int
+gitrm(char *file, ...)
+{
+ va_list args;
+
+ checkinitialized();
+
+ va_start(args, file);
+ return gitaddrm("R", file, args);
+}
--- /dev/null
+++ b/git.h
@@ -1,0 +1,10 @@
+#pragma lib "libgit.a"
+#pragma src "/sys/src/libgit"
+
+/* initialize git system */
+int initgit(char*);
+
+/* git commands. files must be relative within repository */
+int gitcommit(char *msg, char* file, ...);
+int gitadd(char* file, ...);
+int gitrm(char* file, ...);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,8 @@
+</$objtype/mkfile
+
+LIB=/$objtype/lib/libgit.a
+OFILES=git.$O
+
+HFILES=/sys/include/git.h
+
+</sys/src/cmd/mksyslib
--- /dev/null
+++ b/test/gtest.c
@@ -1,0 +1,31 @@
+#include <u.h>
+#include <libc.h>
+#include "../git.h"
+
+char *dir = "/tmp/repo";
+char *addfile = "test";
+
+#define test(A, B) if (!A) { sysfatal("%s: %r\n", B); }
+
+void
+main(void)
+{
+ int fd;
+ char buf[128];
+
+ if (!initgit("/tmp/repo"))
+ sysfatal("gitinit: %r");
+
+ snprint(buf, sizeof(buf), "%s/%s", dir, addfile);
+
+ fd = create(buf, OWRITE, 0666);
+ if (fd < 0)
+ sysfatal("%r");
+ fprint(fd, "hello world\n");
+ close(fd);
+
+ test(gitadd(addfile, nil), "add file");
+ test(gitcommit("add file", addfile, nil), "commit add");
+ test(gitrm(addfile, nil), "rm file");
+ test(gitcommit("remove file", addfile, nil), "commit rm");
+}
--- /dev/null
+++ b/test/mkfile
@@ -1,0 +1,6 @@
+</$objtype/mkfile
+
+TARG=gtest
+OFILES=gtest.$O
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/test/test.rc
@@ -1,0 +1,38 @@
+#!/bin/rc
+
+rfork en
+
+t=`{pwd}
+t=$t/6.out
+
+mk -a
+ramfs
+
+mkdir -p /tmp/repo
+cd /tmp/repo
+git/init .
+
+echo testfile > beforetest
+git/add beforetest
+git/commit -m init beforetest
+
+cat <<EOF >.git/config
+[user]
+ name = testuser
+ email = testmail
+EOF
+
+cat .git/INDEX9
+
+echo '========== run test ============'
+$t
+echo '========== end test ============'
+
+echo git/log: should contain "remove file" and "add file" commits
+git/log
+echo ''
+echo INDEX9: should contain "R NOQID 0 test" line
+cat .git/INDEX9
+echo walk
+walk
+rc -i