summaryrefslogtreecommitdiffstatshomepage
path: root/cgit.h
Commit message (Expand)AuthorAge
* Add parameter to adjust max message length in log listingsLars Hjemli2007-01-28
* Add function cgit_parse_tag()Lars Hjemli2007-01-17
* WIP: add paths/backlinks to tree/blobviewLars Hjemli2007-01-12
* Remove troublesome chars from cachefile namesLars Hjemli2007-01-12
* Move cache_prepare() to cgitLars Hjemli2007-01-12
* Handle %xx encoding in querystringLars Hjemli2007-01-04
* Add basic log filteringLars Hjemli2006-12-28
* Add generic support for search box in page headerLars Hjemli2006-12-28
* Only show first 80 characters of commit subject in log and summaryLars Hjemli2006-12-22
* Add basic diff viewLars Hjemli2006-12-20
* Show list of modified files in ui-commit.cLars Hjemli2006-12-17
* Add cgit_free_commitinfo() and use where neededLars Hjemli2006-12-16
* Teach commit parser about author/committer email + timestampLars Hjemli2006-12-16
* Add argument parsing + switch for uncached operationLars Hjemli2006-12-16
* Move cgit_print_date into ui-shared, reuse in ui-summaryLars Hjemli2006-12-16
* Add ui-commit.c + misc ui cleanupsLars Hjemli2006-12-16
* Add a common commit parserLars Hjemli2006-12-15
* Add simple pager to log pageLars Hjemli2006-12-14
* Add display of tree content w/ui-tree.cLars Hjemli2006-12-13
* Don't truncate valid cachefilesLars Hjemli2006-12-11
* Move global variables + callback functions into shared.cLars Hjemli2006-12-11
* Move functions for generic object output into ui-view.cLars Hjemli2006-12-11
* Move log-functions into ui-log.cLars Hjemli2006-12-11
* Move repo summary functions into ui-summary.cLars Hjemli2006-12-11
* Move functions for repolist output into ui-repolist.cLars Hjemli2006-12-11
* Move common output-functions into ui-shared.cLars Hjemli2006-12-11
* Rename config.c to parsing.c + move cgit_parse_query from cgit.c to parsing.cLars Hjemli2006-12-11
* Avoid infinite loops in caching layerLars Hjemli2006-12-11
* Fix cache algorithm loopholeLars Hjemli2006-12-11
* Add caching infrastructureLars Hjemli2006-12-10
* Import cgit prototype from git treeLars Hjemli2006-12-09
nterpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#include "cgit.h"
#include "configfile.h"
#include "html.h"

#define MAX_PATH 4096

/* return 1 if path contains a objects/ directory and a HEAD file */
static int is_git_dir(const char *path)
{
	struct stat st;
	static char buf[MAX_PATH];

	if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) {
		fprintf(stderr, "Insanely long path: %s\n", path);
		return 0;
	}
	if (stat(buf, &st)) {
		if (errno != ENOENT)
			fprintf(stderr, "Error checking path %s: %s (%d)\n",
				path, strerror(errno), errno);
		return 0;
	}
	if (!S_ISDIR(st.st_mode))
		return 0;

	sprintf(buf, "%s/HEAD", path);
	if (stat(buf, &st)) {
		if (errno != ENOENT)
			fprintf(stderr, "Error checking path %s: %s (%d)\n",
				path, strerror(errno), errno);
		return 0;
	}
	if (!S_ISREG(st.st_mode))
		return 0;

	return 1;
}

struct cgit_repo *repo;
repo_config_fn config_fn;

static void repo_config(const char *name, const char *value)
{
	config_fn(repo, name, value);
}

static void add_repo(const char *base, const char *path, repo_config_fn fn)
{
	struct stat st;
	struct passwd *pwd;
	char *p;
	size_t size;

	if (stat(path, &st)) {
		fprintf(stderr, "Error accessing %s: %s (%d)\n",
			path, strerror(errno), errno);
		return;
	}
	if ((pwd = getpwuid(st.st_uid)) == NULL) {
		fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
			path, strerror(errno), errno);
		return;
	}
	if (base == path)
		p = fmt("%s", path);
	else
		p = fmt("%s", path + strlen(base) + 1);

	if (!strcmp(p + strlen(p) - 5, "/.git"))
		p[strlen(p) - 5] = '\0';

	repo = cgit_add_repo(xstrdup(p));
	repo->name = repo->url;
	repo->path = xstrdup(path);
	p = (pwd && pwd->pw_gecos) ? strchr(pwd->pw_gecos, ',') : NULL;
	if (p)
		*p = '\0';
	repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : "");

	p = fmt("%s/description", path);
	if (!stat(p, &st))
		readfile(p, &repo->desc, &size);

	p = fmt("%s/README.html", path);
	if (!stat(p, &st))
		repo->readme = "README.html";

	p = fmt("%s/cgitrc", path);
	if (!stat(p, &st)) {
		config_fn = fn;
		parse_configfile(xstrdup(p), &repo_config);
	}
}

static void scan_path(const char *base, const char *path, repo_config_fn fn)
{
	DIR *dir;
	struct dirent *ent;
	char *buf;
	struct stat st;

	if (is_git_dir(path)) {
		add_repo(base, path, fn);
		return;
	}
	if (is_git_dir(fmt("%s/.git", path))) {
		add_repo(base, fmt("%s/.git", path), fn);
		return;
	}
	dir = opendir(path);
	if (!dir) {
		fprintf(stderr, "Error opening directory %s: %s (%d)\n",
			path, strerror(errno), errno);
		return;
	}
	while((ent = readdir(dir)) != NULL) {
		if (ent->d_name[0] == '.') {
			if (ent->d_name[1] == '\0')
				continue;
			if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
				continue;
		}
		buf = malloc(strlen(path) + strlen(ent->d_name) + 2);
		if (!buf) {
			fprintf(stderr, "Alloc error on %s: %s (%d)\n",
				path, strerror(errno), errno);
			exit(1);
		}
		sprintf(buf, "%s/%s", path, ent->d_name);
		if (stat(buf, &st)) {
			fprintf(stderr, "Error checking path %s: %s (%d)\n",
				buf, strerror(errno), errno);
			free(buf);
			continue;
		}
		if (S_ISDIR(st.st_mode))
			scan_path(base, buf, fn);
		free(buf);
	}
	closedir(dir);
}

void scan_tree(const char *path, repo_config_fn fn)
{
	scan_path(path, path, fn);
}