shithub: libgit

ref: 073882f6a2a8c065375b94dc77c59eb7d8b2091f
dir: /git.c/

View raw version
#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);
}