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