diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | cgit.c | 19 | ||||
| -rw-r--r-- | cgit.css | 5 | ||||
| -rw-r--r-- | cgit.h | 6 | ||||
| -rw-r--r-- | cgitrc.5.txt | 14 | ||||
| -rw-r--r-- | cmd.c | 2 | ||||
| -rw-r--r-- | parsing.c | 4 | ||||
| -rw-r--r-- | scan-tree.c | 2 | ||||
| -rw-r--r-- | shared.c | 80 | ||||
| -rw-r--r-- | ui-atom.c | 4 | ||||
| -rw-r--r-- | ui-commit.c | 13 | ||||
| -rw-r--r-- | ui-log.c | 11 | ||||
| -rw-r--r-- | ui-plain.c | 68 | ||||
| -rw-r--r-- | ui-shared.c | 1 | 
14 files changed, 205 insertions, 26 deletions
| @@ -1,4 +1,4 @@ -CGIT_VERSION = v0.8.3.1 +CGIT_VERSION = v0.8.3.2  CGIT_SCRIPT_NAME = cgit.cgi  CGIT_SCRIPT_PATH = /var/www/htdocs/cgit  CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) @@ -62,6 +62,8 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)  		repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);  	else if (!strcmp(name, "enable-remote-branches"))  		repo->enable_remote_branches = atoi(value); +	else if (!strcmp(name, "enable-subject-links")) +		repo->enable_subject_links = atoi(value);  	else if (!strcmp(name, "max-stats"))  		repo->max_stats = cgit_find_stats_period(value, NULL);  	else if (!strcmp(name, "module-link")) @@ -141,6 +143,8 @@ void config_cb(const char *name, const char *value)  		ctx.cfg.enable_log_linecount = atoi(value);  	else if (!strcmp(name, "enable-remote-branches"))  		ctx.cfg.enable_remote_branches = atoi(value); +	else if (!strcmp(name, "enable-subject-links")) +		ctx.cfg.enable_subject_links = atoi(value);  	else if (!strcmp(name, "enable-tree-linenumbers"))  		ctx.cfg.enable_tree_linenumbers = atoi(value);  	else if (!strcmp(name, "max-stats")) @@ -148,7 +152,7 @@ void config_cb(const char *name, const char *value)  	else if (!strcmp(name, "cache-size"))  		ctx.cfg.cache_size = atoi(value);  	else if (!strcmp(name, "cache-root")) -		ctx.cfg.cache_root = xstrdup(value); +		ctx.cfg.cache_root = xstrdup(expand_macros(value));  	else if (!strcmp(name, "cache-root-ttl"))  		ctx.cfg.cache_root_ttl = atoi(value);  	else if (!strcmp(name, "cache-repo-ttl")) @@ -165,6 +169,8 @@ void config_cb(const char *name, const char *value)  		ctx.cfg.commit_filter = new_filter(value, 0);  	else if (!strcmp(name, "embedded"))  		ctx.cfg.embedded = atoi(value); +	else if (!strcmp(name, "max-atom-items")) +		ctx.cfg.max_atom_items = atoi(value);  	else if (!strcmp(name, "max-message-length"))  		ctx.cfg.max_msg_len = atoi(value);  	else if (!strcmp(name, "max-repodesc-length")) @@ -177,9 +183,9 @@ void config_cb(const char *name, const char *value)  		ctx.cfg.max_commit_count = atoi(value);  	else if (!strcmp(name, "scan-path"))  		if (!ctx.cfg.nocache && ctx.cfg.cache_size) -			process_cached_repolist(value); +			process_cached_repolist(expand_macros(value));  		else -			scan_tree(value, repo_config); +			scan_tree(expand_macros(value), repo_config);  	else if (!strcmp(name, "source-filter"))  		ctx.cfg.source_filter = new_filter(value, 1);  	else if (!strcmp(name, "summary-log")) @@ -203,7 +209,7 @@ void config_cb(const char *name, const char *value)  	else if (!prefixcmp(name, "mimetype."))  		add_mimetype(name + 9, value);  	else if (!strcmp(name, "include")) -		parse_configfile(value, config_cb); +		parse_configfile(expand_macros(value), config_cb);  }  static void querystring_cb(const char *name, const char *value) @@ -250,6 +256,8 @@ static void querystring_cb(const char *name, const char *value)  		ctx.qry.period = xstrdup(value);  	} else if (!strcmp(name, "ss")) {  		ctx.qry.ssdiff = atoi(value); +	} else if (!strcmp(name, "all")) { +		ctx.qry.show_all = atoi(value);  	} else if (!strcmp(name, "context")) {  		ctx.qry.context = atoi(value);  	} else if (!strcmp(name, "ignorews")) { @@ -296,6 +304,7 @@ static void prepare_context(struct cgit_context *ctx)  	ctx->cfg.summary_branches = 10;  	ctx->cfg.summary_log = 10;  	ctx->cfg.summary_tags = 10; +	ctx->cfg.max_atom_items = 10;  	ctx->cfg.ssdiff = 0;  	ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));  	ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); @@ -698,7 +707,7 @@ int main(int argc, const char **argv)  	cgit_repolist.repos = NULL;  	cgit_parse_args(argc, argv); -	parse_configfile(ctx.env.cgit_config, config_cb); +	parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);  	ctx.repo = NULL;  	http_parse_querystring(ctx.qry.raw, querystring_cb); @@ -531,7 +531,10 @@ a.deco {  	border: solid 1px #770000;  } -div.commit-subject a { +div.commit-subject a.branch-deco, +div.commit-subject a.tag-deco, +div.commit-subject a.remote-deco, +div.commit-subject a.deco {  	margin-left: 1em;  	font-size: 75%;  } @@ -73,6 +73,7 @@ struct cgit_repo {  	int enable_log_filecount;  	int enable_log_linecount;  	int enable_remote_branches; +	int enable_subject_links;  	int max_stats;  	time_t mtime;  	struct cgit_filter *about_filter; @@ -145,6 +146,7 @@ struct cgit_query {  	char *sort;  	int showmsg;  	int ssdiff; +	int show_all;  	int context;  	int ignorews;  	char *vpath; @@ -184,8 +186,10 @@ struct cgit_config {  	int enable_log_filecount;  	int enable_log_linecount;  	int enable_remote_branches; +	int enable_subject_links;  	int enable_tree_linenumbers;  	int local_time; +	int max_atom_items;  	int max_repo_count;  	int max_commit_count;  	int max_lock_attempts; @@ -300,4 +304,6 @@ extern int cgit_close_filter(struct cgit_filter *filter);  extern int readfile(const char *path, char **buf, size_t *size); +extern char *expand_macros(const char *txt); +  #endif /* CGIT_H */ diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 1f7ac1e..a853522 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -115,6 +115,12 @@ enable-remote-branches::  	in the summary and refs views. Default value: "0". See also:  	"repo.enable-remote-branches". +enable-subject-links:: +	Flag which, when set to "1", will make cgit use the subject of the +	parent commit as link text when generating links to parent commits +	in commit view. Default value: "0". See also: +	"repo.enable-subject-links". +  enable-tree-linenumbers::  	Flag which, when set to "1", will make cgit generate linenumber links  	for plaintext blobs printed in the tree view. Default value: "1". @@ -166,6 +172,10 @@ logo-link::  	calculated url of the repository index page will be used. Default  	value: none. +max-atom-items:: +	Specifies the number of items to display in atom feeds view. Default +	value: "10". +  max-commit-count::  	Specifies the number of entries to list per page in "log" view. Default  	value: "50". @@ -321,6 +331,10 @@ repo.enable-remote-branches::  	Flag which, when set to "1", will make cgit display remote branches  	in the summary and refs views. Default value: <enable-remote-branches>. +repo.enable-subject-links:: +	A flag which can be used to override the global setting +	`enable-subject-links'. Default value: none. +  repo.max-stats::  	Override the default maximum statistics period. Valid values are equal  	to the values specified for the global "max-stats" setting. Default @@ -33,7 +33,7 @@ static void HEAD_fn(struct cgit_context *ctx)  static void atom_fn(struct cgit_context *ctx)  { -	cgit_print_atom(ctx->qry.head, ctx->qry.path, 10); +	cgit_print_atom(ctx->qry.head, ctx->qry.path, ctx->cfg.max_atom_items);  }  static void about_fn(struct cgit_context *ctx) @@ -190,6 +190,10 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)  		ret->subject = xstrdup(p);  	if (ret->msg_encoding) { +		reencode(&ret->author, PAGE_ENCODING, ret->msg_encoding); +		reencode(&ret->author_email, PAGE_ENCODING, ret->msg_encoding); +		reencode(&ret->committer, PAGE_ENCODING, ret->msg_encoding); +		reencode(&ret->committer_email, PAGE_ENCODING, ret->msg_encoding);  		reencode(&ret->subject, PAGE_ENCODING, ret->msg_encoding);  		reencode(&ret->msg, PAGE_ENCODING, ret->msg_encoding);  	} diff --git a/scan-tree.c b/scan-tree.c index dbca797..1e18f3c 100644 --- a/scan-tree.c +++ b/scan-tree.c @@ -56,6 +56,8 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)  			path, strerror(errno), errno);  		return;  	} +	if (!stat(fmt("%s/noweb", path), &st)) +		return;  	if ((pwd = getpwuid(st.st_uid)) == NULL) {  		fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",  			path, strerror(errno), errno); @@ -59,6 +59,7 @@ struct cgit_repo *cgit_add_repo(const char *url)  	ret->enable_log_filecount = ctx.cfg.enable_log_filecount;  	ret->enable_log_linecount = ctx.cfg.enable_log_linecount;  	ret->enable_remote_branches = ctx.cfg.enable_remote_branches; +	ret->enable_subject_links = ctx.cfg.enable_subject_links;  	ret->max_stats = ctx.cfg.max_stats;  	ret->module_link = ctx.cfg.module_link;  	ret->readme = NULL; @@ -279,6 +280,10 @@ int cgit_diff_files(const unsigned char *old_sha1,  	if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) ||  	    (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) {  		*binary = 1; +		if (file1.size) +			free(file1.ptr); +		if (file2.size) +			free(file2.ptr);  		return 0;  	} @@ -293,6 +298,10 @@ int cgit_diff_files(const unsigned char *old_sha1,  	emit_cb.outf = filediff_cb;  	emit_cb.priv = fn;  	xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); +	if (file1.size) +		free(file1.ptr); +	if (file2.size) +		free(file2.ptr);  	return 0;  } @@ -428,3 +437,74 @@ int readfile(const char *path, char **buf, size_t *size)  	close(fd);  	return (*size == st.st_size ? 0 : e);  } + +int is_token_char(char c) +{ +	return isalnum(c) || c == '_'; +} + +/* Replace name with getenv(name), return pointer to zero-terminating char + */ +char *expand_macro(char *name, int maxlength) +{ +	char *value; +	int len; + +	len = 0; +	value = getenv(name); +	if (value) { +		len = strlen(value); +		if (len > maxlength) +			len = maxlength; +		strncpy(name, value, len); +	} +	return name + len; +} + +#define EXPBUFSIZE (1024 * 8) + +/* Replace all tokens prefixed by '$' in the specified text with the + * value of the named environment variable. + * NB: the return value is a static buffer, i.e. it must be strdup'd + * by the caller. + */ +char *expand_macros(const char *txt) +{ +	static char result[EXPBUFSIZE]; +	char *p, *start; +	int len; + +	p = result; +	start = NULL; +	while (p < result + EXPBUFSIZE - 1 && txt && *txt) { +		*p = *txt; +		if (start) { +			if (!is_token_char(*txt)) { +				if (p - start > 0) { +					*p = '\0'; +					len = result + EXPBUFSIZE - start - 1; +					p = expand_macro(start, len) - 1; +				} +				start = NULL; +				txt--; +			} +			p++; +			txt++; +			continue; +		} +		if (*txt == '$') { +			start = p; +			txt++; +			continue; +		} +		p++; +		txt++; +	} +	*p = '\0'; +	if (start && p - start > 0) { +		len = result + EXPBUFSIZE - start - 1; +		p = expand_macro(start, len); +		*p = '\0'; +	} +	return result; +} @@ -85,7 +85,9 @@ void cgit_print_atom(char *tip, char *path, int max_count)  	struct rev_info rev;  	int argc = 2; -	if (!tip) +	if (ctx.qry.show_all) +		argv[1] = "--all"; +	else if (!tip)  		argv[1] = ctx.qry.head;  	if (path) { diff --git a/ui-commit.c b/ui-commit.c index 2d98ed9..a11bc5f 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -15,10 +15,10 @@  void cgit_print_commit(char *hex, const char *prefix)  {  	struct commit *commit, *parent; -	struct commitinfo *info; +	struct commitinfo *info, *parent_info;  	struct commit_list *p;  	unsigned char sha1[20]; -	char *tmp; +	char *tmp, *tmp2;  	int parents = 0;  	if (!hex) @@ -86,9 +86,12 @@ void cgit_print_commit(char *hex, const char *prefix)  		}  		html("<tr><th>parent</th>"  		     "<td colspan='2' class='sha1'>"); -		cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, -				 ctx.qry.head, -				 sha1_to_hex(p->item->object.sha1), prefix, 0); +		tmp = tmp2 = sha1_to_hex(p->item->object.sha1); +		if (ctx.repo->enable_subject_links) { +			parent_info = cgit_parse_commit(parent); +			tmp2 = parent_info->subject; +		} +		cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, prefix, 0);  		html(" (");  		cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex,  			       sha1_to_hex(p->item->object.sha1), prefix, 0); @@ -150,10 +150,13 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern  	argv[1] = disambiguate_ref(tip); -	if (grep && pattern && (!strcmp(grep, "grep") || -				!strcmp(grep, "author") || -				!strcmp(grep, "committer"))) -		argv[argc++] = fmt("--%s=%s", grep, pattern); +	if (grep && pattern) { +		if (!strcmp(grep, "grep") || !strcmp(grep, "author") || +		    !strcmp(grep, "committer")) +			argv[argc++] = fmt("--%s=%s", grep, pattern); +		if (!strcmp(grep, "range")) +			argv[1] = pattern; +	}  	if (path) {  		argv[argc++] = "--"; @@ -10,8 +10,7 @@  #include "html.h"  #include "ui-shared.h" -char *curr_rev; -char *match_path; +int match_baselen;  int match;  static void print_object(const unsigned char *sha1, const char *path) @@ -53,17 +52,63 @@ static void print_object(const unsigned char *sha1, const char *path)  	match = 1;  } +static void print_dir(const unsigned char *sha1, const char *path, +		      const char *base) +{ +	char *fullpath; +	if (path[0] || base[0]) +		fullpath = fmt("/%s%s/", base, path); +	else +		fullpath = "/"; +	ctx.page.etag = sha1_to_hex(sha1); +	cgit_print_http_headers(&ctx); +	htmlf("<html><head><title>%s</title></head>\n<body>\n" +	      " <h2>%s</h2>\n <ul>\n", fullpath, fullpath); +	if (path[0] || base[0]) +	      html("  <li><a href=\"../\">../</a></li>\n"); +	match = 2; +} + +static void print_dir_entry(const unsigned char *sha1, const char *path, +			    unsigned mode) +{ +	const char *sep = ""; +	if (S_ISDIR(mode)) +		sep = "/"; +	htmlf("  <li><a href=\"%s%s\">%s%s</a></li>\n", path, sep, path, sep); +	match = 2; +} + +static void print_dir_tail(void) +{ +	html(" </ul>\n</body></html>\n"); +} +  static int walk_tree(const unsigned char *sha1, const char *base, int baselen,  		     const char *pathname, unsigned mode, int stage,  		     void *cbdata)  { -	if (S_ISDIR(mode)) +	if (baselen == match_baselen) { +		if (S_ISREG(mode)) +			print_object(sha1, pathname); +		else if (S_ISDIR(mode)) { +			print_dir(sha1, pathname, base); +			return READ_TREE_RECURSIVE; +		} +	} +	else if (baselen > match_baselen) +		print_dir_entry(sha1, pathname, mode); +	else if (S_ISDIR(mode))  		return READ_TREE_RECURSIVE; -	if (S_ISREG(mode) && !strncmp(base, match_path, baselen) && -	    !strcmp(pathname, match_path + baselen)) -		print_object(sha1, pathname); +	return 0; +} +static int basedir_len(const char *path) +{ +	char *p = strrchr(path, '/'); +	if (p) +		return p - path + 1;  	return 0;  } @@ -77,7 +122,6 @@ void cgit_print_plain(struct cgit_context *ctx)  	if (!rev)  		rev = ctx->qry.head; -	curr_rev = xstrdup(rev);  	if (get_sha1(rev, sha1)) {  		html_status(404, "Not found", 0);  		return; @@ -87,8 +131,16 @@ void cgit_print_plain(struct cgit_context *ctx)  		html_status(404, "Not found", 0);  		return;  	} -	match_path = ctx->qry.path; +	if (!paths[0]) { +		paths[0] = ""; +		match_baselen = -1; +		print_dir(commit->tree->object.sha1, "", ""); +	} +	else +		match_baselen = basedir_len(paths[0]);  	read_tree_recursive(commit->tree, "", 0, 0, paths, walk_tree, NULL);  	if (!match)  		html_status(404, "Not found", 0); +	else if (match == 2) +		print_dir_tail();  } diff --git a/ui-shared.c b/ui-shared.c index f46c935..ae29615 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -840,6 +840,7 @@ void cgit_print_pageheader(struct cgit_context *ctx)  		html_option("grep", "log msg", ctx->qry.grep);  		html_option("author", "author", ctx->qry.grep);  		html_option("committer", "committer", ctx->qry.grep); +		html_option("range", "range", ctx->qry.grep);  		html("</select>\n");  		html("<input class='txt' type='text' size='10' name='q' value='");  		html_attr(ctx->qry.search); | 
