Gitolite support patch

The Ranger ranger at risk.ee
Tue Jan 31 19:31:27 CET 2012


On 31.01.2012 20:25, The Ranger wrote:
> I've created a quick patch to add gitolite config file parsing support
> to cgit.

diff -puNX exclude.pat cgit-0.9.0.2/cgit.c cgit-gitolite/cgit.c
--- cgit-0.9.0.2/cgit.c	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/cgit.c	2012-01-31 13:03:27.974747168 +0200
@@ -15,6 +15,7 @@
  #include "ui-shared.h"
  #include "ui-stats.h"
  #include "scan-tree.h"
+#include "gitolite.h"

  const char *cgit_version = CGIT_VERSION;

@@ -235,6 +236,9 @@ void config_cb(const char *name, const c
  		add_mimetype(name + 9, value);
  	else if (!strcmp(name, "include"))
  		parse_configfile(expand_macros(value), config_cb);
+	else if (!strcmp(name, "gitolite-conf")) {
+		ctx.cfg.gitolite_conf = gitolite_scan_conf(value, ctx.env.remote_user);
+	}
  }

  static void querystring_cb(const char *name, const char *value)
@@ -309,6 +313,7 @@ static void prepare_context(struct cgit_
  	ctx->cfg.cache_scanrc_ttl = 15;
  	ctx->cfg.cache_static_ttl = -1;
  	ctx->cfg.css = "/cgit.css";
+	ctx->cfg.gitolite_conf = NULL;
  	ctx->cfg.logo = "/cgit.png";
  	ctx->cfg.local_time = 0;
  	ctx->cfg.enable_gitweb_owner = 1;
@@ -345,6 +350,7 @@ static void prepare_context(struct cgit_
  	ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
  	ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
  	ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
+	ctx->env.remote_user = xstrdupn(getenv("REMOTE_USER"));
  	ctx->page.mimetype = "text/html";
  	ctx->page.charset = PAGE_ENCODING;
  	ctx->page.filename = NULL;
@@ -794,6 +800,9 @@ int main(int argc, const char **argv)
  		ctx.cfg.cache_size = 0;
  	err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
  			    ctx.qry.raw, ttl, process_request, &ctx);
+
+	gitolite_free_res(ctx.cfg.gitolite_conf);
+
  	if (err)
  		cgit_print_error(fmt("Error processing page: %s (%d)",
  				     strerror(err), err));
diff -puNX exclude.pat cgit-0.9.0.2/cgit.h cgit-gitolite/cgit.h
--- cgit-0.9.0.2/cgit.h	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/cgit.h	2012-01-25 18:15:01.687362057 +0200
@@ -222,6 +222,7 @@ struct cgit_config {
  	struct string_list mimetypes;
  	struct cgit_filter *about_filter;
  	struct cgit_filter *commit_filter;
+	struct gitolite_conf *gitolite_conf;
  	struct cgit_filter *source_filter;
  };

@@ -249,6 +250,7 @@ struct cgit_environment {
  	char *script_name;
  	char *server_name;
  	char *server_port;
+	char *remote_user;
  };

  struct cgit_context {
Common subdirectories: cgit-0.9.0.2/filters and cgit-gitolite/filters
diff -puNX exclude.pat cgit-0.9.0.2/gitolite.c cgit-gitolite/gitolite.c
--- cgit-0.9.0.2/gitolite.c	1970-01-01 03:00:00.000000000 +0300
+++ cgit-gitolite/gitolite.c	2012-01-31 19:52:42.605533772 +0200
@@ -0,0 +1,232 @@
+/*
+ * gitolite.c
+ *
+ *  Created on: 24.01.2012
+ *      Author: ivari
+ */
+
+#include <stdio.h>
+
+#include "cgit.h"
+#include "gitolite.h"
+
+struct gitolite_option {
+	char option[MAX_OPT_LEN];
+	char value[MAX_OPT_LEN];
+};
+
+//Parse configuration options from gitolite.conf
+static int gitolite_read_option(FILE *file, struct gitolite_option 
*option) {
+	int matches;
+	char line[sizeof(option->option) + sizeof(option->value)];
+	memset(option, 0, sizeof(struct gitolite_option));
+
+	if(fgets(line, sizeof(line), file) == NULL) return -1;
+	matches = sscanf(line, "%s%*[ =\t]%[^\n]s\n", option->option, 
option->value);
+	if(matches < 1) return 0;
+
+	//Handle one big string
+	if(matches == 1) {
+		char *p = strchr(option->option, '=');
+		if(p == NULL) return 0;
+		*p = '\0';
+		strncpy(option->value, p+1, sizeof(option->value));
+		option->value[sizeof(option->value)-1] = 0;
+	}
+
+	//Skip comments
+	if(option->option[0] == '#') return 0;
+	return 1;
+}
+
+//Add repo to list
+static struct gitolite_repo * gitolite_add_repo(struct gitolite_conf 
*conf) {
+	struct gitolite_repo *repo;
+	if(conf == NULL) return NULL;
+
+	repo = xmalloc(sizeof(*repo));
+	if(repo == NULL) return NULL;
+	memset(repo, 0, sizeof(struct gitolite_repo));
+
+	// First repo?
+	if(conf->r_first == NULL) conf->r_first = repo;
+
+	// We have more than one repo?
+	if(conf->r_last != NULL) conf->r_last->next = repo;
+
+	conf->r_last = repo;
+
+	return repo;
+}
+
+//Add group to list
+static struct gitolite_group * gitolite_add_group(struct gitolite_conf 
*conf) {
+	struct gitolite_group *group;
+	if(conf == NULL) return NULL;
+
+	group = xmalloc(sizeof(*group));
+	if(group == NULL) return NULL;
+	memset(group, 0, sizeof(struct gitolite_group));
+
+	if(conf->g_first == NULL) conf->g_first = group;
+	if(conf->g_last != NULL) conf->g_last->next = group;
+
+	conf->g_last = group;
+
+	return group;
+}
+
+static int gitolite_check_group(struct gitolite_conf *conf, const char 
*name) {
+	struct gitolite_group *group;
+
+	if(!strcmp(name, "@all")) return 1;
+
+	if(conf == NULL) return 0;
+
+	group = conf->g_first;
+	while(group != NULL) {
+		if(!strcmp(group->name, name)) return 1;
+		group = group->next;
+	}
+
+	return 0;
+}
+
+static void gitolite_parse_user(struct gitolite_conf *conf, struct 
gitolite_option *option, char *path, const char *user) {
+	struct gitolite_repo *repo;
+	char *p;
+
+	while((p = strrchr(option->value, ' ')) != NULL) {
+		*p = '\0';
+		if(*(p+1) == '@' && gitolite_check_group(conf, p+1) > 0) goto ADDREPO;
+		if(!strcmp(p+1, user)) goto ADDREPO;
+	}
+
+	if(option->value[0] == '@' && gitolite_check_group(conf, 
option->value) > 0) goto ADDREPO;
+
+	//If not current user, skip
+	if(strcmp(option->value, user)) return;
+
+ADDREPO:
+	repo = gitolite_add_repo(conf);
+	repo->path = xstrdup(path);
+}
+
+static void gitolite_parse_group(struct gitolite_conf *conf, struct 
gitolite_option *option, const char *user) {
+	struct gitolite_group *group;
+	char *p;
+
+	while((p = strrchr(option->value, ' ')) != NULL) {
+		*p = '\0';
+		if(strcmp(p+1, user)) continue;
+	}
+
+	if(strcmp(option->value, user)) return;
+
+	group = gitolite_add_group(conf);
+	group->name = xstrdup(option->option);
+}
+
+//Add repos from gitolite.conf file
+struct gitolite_conf * gitolite_scan_conf(const char *gitolite_path, 
const char *user) {
+	FILE *file;
+	struct gitolite_option option;
+	struct gitolite_conf *conf = NULL;
+
+	int i;
+	char *p;
+	char path[MAX_OPT_LEN];
+
+	conf = xmalloc(sizeof(*conf));
+	memset(conf, 0, sizeof(*conf));
+
+	//User not found, deny everything by default
+	if(user == NULL) return conf;
+
+	file = fopen(gitolite_path, "r");
+	if(file == NULL) {
+		fprintf(stderr, "Could not open gitolite config file %s\n", 
gitolite_path);
+		return conf;
+	}
+
+	//Remove @suffix from user names (gitolite does not like this)
+	if ((p = strchr(user, '@')) != NULL) *p = '\0';
+
+	while((i = gitolite_read_option(file, &option)) != -1) {
+		if(i == 0 || *(option.value) == 0) continue;
+
+		// Repo definition
+		if(!strcmp(option.option, "repo")) {
+			strncpy(path, option.value, sizeof(path));
+			path[sizeof(path)-1] = 0;
+			continue;
+		}
+
+		// Access definition
+		if(strcmp(option.option, "R") >= 0) {
+			gitolite_parse_user(conf, &option, path, user);
+			continue;
+		}
+
+		// Group definition
+		if(option.option[0] == '@') {
+			gitolite_parse_group(conf, &option, user);
+			continue;
+		}
+	}
+
+	fclose(file);
+	return conf;
+}
+
+
+
+//Check repo before showing it
+int gitolite_check_repo(struct gitolite_conf *conf, const char *base) {
+	char *p;
+	struct gitolite_repo *repo;
+
+	//No conf set up, disable this check
+	if(conf == NULL) return 1;
+
+	//Remove .git suffix
+	if ((p = strrchr(base, '.')) && !strcmp(p, ".git")) *p = '\0';
+
+	repo = conf->r_first;
+	while(repo != NULL) {
+		if(!strcmp(repo->path, base)) return 1;
+		repo = repo->next;
+	}
+
+	//Repo was not found, deny
+	return 0;
+}
+
+//Cleanup
+void gitolite_free_res(struct gitolite_conf *conf) {
+	struct gitolite_repo *repo;
+	struct gitolite_repo *n_repo;
+
+	struct gitolite_group *group;
+	struct gitolite_group *n_group;
+
+	if(conf == NULL) return;
+
+	//Empty struct, no repos?
+	repo = conf->r_first;
+
+	while(repo != NULL) {
+		n_repo = repo->next;
+		free(repo);
+		repo = n_repo;
+	}
+
+	group = conf->g_first;
+	while(group != NULL) {
+		n_group = group->next;
+		free(group);
+		group = n_group;
+	}
+
+	free(conf);
+}
diff -puNX exclude.pat cgit-0.9.0.2/gitolite.h cgit-gitolite/gitolite.h
--- cgit-0.9.0.2/gitolite.h	1970-01-01 03:00:00.000000000 +0300
+++ cgit-gitolite/gitolite.h	2012-01-31 17:44:02.025566452 +0200
@@ -0,0 +1,35 @@
+/*
+ * gitolite.h
+ *
+ *  Created on: 24.01.2012
+ *      Author: ivari
+ */
+
+#ifndef GITOLITE_H_
+#define GITOLITE_H_
+
+#define MAX_OPT_LEN 256
+
+struct gitolite_conf {
+	struct gitolite_repo *r_first;
+	struct gitolite_repo *r_last;
+
+	struct gitolite_group *g_first;
+	struct gitolite_group *g_last;
+};
+
+struct gitolite_repo {
+	char *path;
+	struct gitolite_repo *next;
+};
+
+struct gitolite_group {
+	char *name;
+	struct gitolite_group *next;
+};
+
+struct gitolite_conf * gitolite_scan_conf(const char *gitolite_path, 
const char *user);
+int gitolite_check_repo(struct gitolite_conf *conf, const char *base);
+void gitolite_free_res(struct gitolite_conf *conf);
+
+#endif /* GITOLITE_H_ */
diff -puNX exclude.pat cgit-0.9.0.2/Makefile cgit-gitolite/Makefile
--- cgit-0.9.0.2/Makefile	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/Makefile	2012-01-25 16:28:49.223364486 +0200
@@ -116,6 +116,7 @@ OBJECTS += ui-summary.o
  OBJECTS += ui-tag.o
  OBJECTS += ui-tree.o
  OBJECTS += vector.o
+OBJECTS += gitolite.o

  ifdef NEEDS_LIBICONV
  	EXTLIBS += -liconv
diff -puNX exclude.pat cgit-0.9.0.2/scan-tree.c cgit-gitolite/scan-tree.c
--- cgit-0.9.0.2/scan-tree.c	2011-07-21 17:24:10.000000000 +0300
+++ cgit-gitolite/scan-tree.c	2012-01-26 16:29:53.777586126 +0200
@@ -10,6 +10,7 @@
  #include "cgit.h"
  #include "configfile.h"
  #include "html.h"
+#include "gitolite.h"

  #define MAX_PATH 4096

@@ -99,6 +100,11 @@ static void add_repo(const char *base, c
  	if (!strcmp(rel + strlen(rel) - 5, "/.git"))
  		rel[strlen(rel) - 5] = '\0';

+	if (!gitolite_check_repo(ctx.cfg.gitolite_conf, rel)) {
+		free(rel);
+		return;
+	}
+
  	repo = cgit_add_repo(rel);
  	if (ctx.cfg.remove_suffix)
  		if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git"))
Common subdirectories: cgit-0.9.0.2/tests and cgit-gitolite/tests


-- 
rgrds,
Ranger






More information about the CGit mailing list