ui-stats: replace 'enable-stats' setting with 'max-stats'
The new 'max-stats' and 'repo.max-stats' settings makes it possible to define the maximum statistics period, both globally and per repo. Hence, it is now feasible to allow statistics on repositories with a high commit frequency, like linux-2.6, by setting repo.max-stats to e.g. 'month'. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
This commit is contained in:
		
							
								
								
									
										10
									
								
								cgit.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cgit.c
									
									
									
									
									
								
							| @@ -12,6 +12,7 @@ | ||||
| #include "configfile.h" | ||||
| #include "html.h" | ||||
| #include "ui-shared.h" | ||||
| #include "ui-stats.h" | ||||
| #include "scan-tree.h" | ||||
|  | ||||
| const char *cgit_version = CGIT_VERSION; | ||||
| @@ -54,8 +55,8 @@ void config_cb(const char *name, const char *value) | ||||
| 		ctx.cfg.enable_log_filecount = atoi(value); | ||||
| 	else if (!strcmp(name, "enable-log-linecount")) | ||||
| 		ctx.cfg.enable_log_linecount = atoi(value); | ||||
| 	else if (!strcmp(name, "enable-stats")) | ||||
| 		ctx.cfg.enable_stats = atoi(value); | ||||
| 	else if (!strcmp(name, "max-stats")) | ||||
| 		ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); | ||||
| 	else if (!strcmp(name, "cache-size")) | ||||
| 		ctx.cfg.cache_size = atoi(value); | ||||
| 	else if (!strcmp(name, "cache-root")) | ||||
| @@ -114,8 +115,8 @@ void config_cb(const char *name, const char *value) | ||||
| 		ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); | ||||
| 	else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) | ||||
| 		ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); | ||||
| 	else if (ctx.repo && !strcmp(name, "repo.enable-stats")) | ||||
| 		ctx.repo->enable_stats = ctx.cfg.enable_stats && atoi(value); | ||||
| 	else if (ctx.repo && !strcmp(name, "repo.max-stats")) | ||||
| 		ctx.repo->max_stats = cgit_find_stats_period(value, NULL); | ||||
| 	else if (ctx.repo && !strcmp(name, "repo.module-link")) | ||||
| 		ctx.repo->module_link= xstrdup(value); | ||||
| 	else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { | ||||
| @@ -183,6 +184,7 @@ static void prepare_context(struct cgit_context *ctx) | ||||
| 	ctx->cfg.max_lock_attempts = 5; | ||||
| 	ctx->cfg.max_msg_len = 80; | ||||
| 	ctx->cfg.max_repodesc_len = 80; | ||||
| 	ctx->cfg.max_stats = 0; | ||||
| 	ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; | ||||
| 	ctx->cfg.renamelimit = -1; | ||||
| 	ctx->cfg.robots = "index, nofollow"; | ||||
|   | ||||
							
								
								
									
										4
									
								
								cgit.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								cgit.h
									
									
									
									
									
								
							| @@ -61,7 +61,7 @@ struct cgit_repo { | ||||
| 	int snapshots; | ||||
| 	int enable_log_filecount; | ||||
| 	int enable_log_linecount; | ||||
| 	int enable_stats; | ||||
| 	int max_stats; | ||||
| }; | ||||
|  | ||||
| struct cgit_repolist { | ||||
| @@ -153,13 +153,13 @@ struct cgit_config { | ||||
| 	int enable_index_links; | ||||
| 	int enable_log_filecount; | ||||
| 	int enable_log_linecount; | ||||
| 	int enable_stats; | ||||
| 	int local_time; | ||||
| 	int max_repo_count; | ||||
| 	int max_commit_count; | ||||
| 	int max_lock_attempts; | ||||
| 	int max_msg_len; | ||||
| 	int max_repodesc_len; | ||||
| 	int max_stats; | ||||
| 	int nocache; | ||||
| 	int renamelimit; | ||||
| 	int snapshots; | ||||
|   | ||||
							
								
								
									
										23
									
								
								cgitrc.5.txt
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								cgitrc.5.txt
									
									
									
									
									
								
							| @@ -74,10 +74,6 @@ enable-log-linecount | ||||
| 	and removed lines for each commit on the repository log page. Default | ||||
| 	value: "0". | ||||
|  | ||||
| enable-stats | ||||
| 	Globally enable/disable statistics for each repository. Default | ||||
| 	value: "0". | ||||
|  | ||||
| favicon | ||||
| 	Url used as link to a shortcut icon for cgit. If specified, it is | ||||
| 	suggested to use the value "/favicon.ico" since certain browsers will | ||||
| @@ -133,6 +129,11 @@ max-repodesc-length | ||||
| 	Specifies the maximum number of repo description characters to display | ||||
| 	on the repository index page. Default value: "80". | ||||
|  | ||||
| max-stats | ||||
| 	Set the default maximum statistics period. Valid values are "week", | ||||
| 	"month", "quarter" and "year". If unspecified, statistics are | ||||
| 	disabled. Default value: none. See also: "repo.max-stats". | ||||
|  | ||||
| module-link | ||||
| 	Text which will be used as the formatstring for a hyperlink when a | ||||
| 	submodule is printed in a directory listing. The arguments for the | ||||
| @@ -222,9 +223,10 @@ repo.enable-log-linecount | ||||
| 	A flag which can be used to disable the global setting | ||||
| 	`enable-log-linecount'. Default value: none. | ||||
|  | ||||
| repo.enable-stats | ||||
| 	A flag which can be used to disable the global setting | ||||
| 	`enable-stats'. 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 | ||||
| 	value: none. | ||||
|  | ||||
| repo.name | ||||
| 	The value to show as repository name. Default value: <repo.url>. | ||||
| @@ -284,6 +286,10 @@ favicon=/favicon.ico | ||||
| logo=/img/mylogo.png | ||||
|  | ||||
|  | ||||
| # Enable statistics per week, month and quarter | ||||
| max-stats=quarter | ||||
|  | ||||
|  | ||||
| # Set the title and heading of the repository index page | ||||
| root-title=foobar.com git repositories | ||||
|  | ||||
| @@ -356,6 +362,9 @@ repo.snapshots=0 | ||||
| # Disable line-counts for this repo | ||||
| repo.enable-log-linecount=0 | ||||
|  | ||||
| # Restrict the max statistics period for this repo | ||||
| repo.max-stats=month | ||||
|  | ||||
|  | ||||
| BUGS | ||||
| ---- | ||||
|   | ||||
							
								
								
									
										5
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -112,10 +112,7 @@ static void snapshot_fn(struct cgit_context *ctx) | ||||
|  | ||||
| static void stats_fn(struct cgit_context *ctx) | ||||
| { | ||||
| 	if (ctx->repo->enable_stats) | ||||
| 		cgit_show_stats(ctx); | ||||
| 	else | ||||
| 		cgit_print_error("Stats disabled for this repo"); | ||||
| 	cgit_show_stats(ctx); | ||||
| } | ||||
|  | ||||
| static void summary_fn(struct cgit_context *ctx) | ||||
|   | ||||
							
								
								
									
										2
									
								
								shared.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								shared.c
									
									
									
									
									
								
							| @@ -58,7 +58,7 @@ struct cgit_repo *cgit_add_repo(const char *url) | ||||
| 	ret->snapshots = ctx.cfg.snapshots; | ||||
| 	ret->enable_log_filecount = ctx.cfg.enable_log_filecount; | ||||
| 	ret->enable_log_linecount = ctx.cfg.enable_log_linecount; | ||||
| 	ret->enable_stats = ctx.cfg.enable_stats; | ||||
| 	ret->max_stats = ctx.cfg.max_stats; | ||||
| 	ret->module_link = ctx.cfg.module_link; | ||||
| 	ret->readme = NULL; | ||||
| 	return ret; | ||||
|   | ||||
| @@ -641,7 +641,7 @@ void cgit_print_pageheader(struct cgit_context *ctx) | ||||
| 				 ctx->qry.head, ctx->qry.sha1); | ||||
| 		cgit_diff_link("diff", NULL, hc(cmd, "diff"), ctx->qry.head, | ||||
| 			       ctx->qry.sha1, ctx->qry.sha2, NULL); | ||||
| 		if (ctx->repo->enable_stats) | ||||
| 		if (ctx->repo->max_stats) | ||||
| 			reporevlink("stats", "stats", NULL, hc(cmd, "stats"), | ||||
| 				    ctx->qry.head, NULL, NULL); | ||||
| 		if (ctx->repo->readme) | ||||
|   | ||||
							
								
								
									
										99
									
								
								ui-stats.c
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								ui-stats.c
									
									
									
									
									
								
							| @@ -1,26 +1,12 @@ | ||||
| #include "cgit.h" | ||||
| #include "html.h" | ||||
| #include <string-list.h> | ||||
|  | ||||
| #include "cgit.h" | ||||
| #include "html.h" | ||||
| #include "ui-shared.h" | ||||
| #include "ui-stats.h" | ||||
|  | ||||
| #define MONTHS 6 | ||||
|  | ||||
| struct Period { | ||||
| 	const char code; | ||||
| 	const char *name; | ||||
| 	int max_periods; | ||||
| 	int count; | ||||
|  | ||||
| 	/* Convert a tm value to the first day in the period */ | ||||
| 	void (*trunc)(struct tm *tm); | ||||
|  | ||||
| 	/* Update tm value to start of next/previous period */ | ||||
| 	void (*dec)(struct tm *tm); | ||||
| 	void (*inc)(struct tm *tm); | ||||
|  | ||||
| 	/* Pretty-print a tm value */ | ||||
| 	char *(*pretty)(struct tm *tm); | ||||
| }; | ||||
|  | ||||
| struct authorstat { | ||||
| 	long total; | ||||
| 	struct string_list list; | ||||
| @@ -137,15 +123,39 @@ static char *pretty_year(struct tm *tm) | ||||
| 	return fmt("%d", tm->tm_year + 1900); | ||||
| } | ||||
|  | ||||
| struct Period periods[] = { | ||||
| struct cgit_period periods[] = { | ||||
| 	{'w', "week", 12, 4, trunc_week, dec_week, inc_week, pretty_week}, | ||||
| 	{'m', "month", 12, 4, trunc_month, dec_month, inc_month, pretty_month}, | ||||
| 	{'q', "quarter", 12, 4, trunc_quarter, dec_quarter, inc_quarter, pretty_quarter}, | ||||
| 	{'y', "year", 12, 4, trunc_year, dec_year, inc_year, pretty_year}, | ||||
| }; | ||||
|  | ||||
| /* Given a period code or name, return a period index (1, 2, 3 or 4) | ||||
|  * and update the period pointer to the correcsponding struct. | ||||
|  * If no matching code is found, return 0. | ||||
|  */ | ||||
| int cgit_find_stats_period(const char *expr, struct cgit_period **period) | ||||
| { | ||||
| 	int i; | ||||
| 	char code = '\0'; | ||||
|  | ||||
| 	if (!expr) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (strlen(expr) == 1) | ||||
| 		code = expr[0]; | ||||
|  | ||||
| 	for (i = 0; i < sizeof(periods) / sizeof(periods[0]); i++) | ||||
| 		if (periods[i].code == code || !strcmp(periods[i].name, expr)) { | ||||
| 			if (period) | ||||
| 				*period = &periods[i]; | ||||
| 			return i+1; | ||||
| 		} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void add_commit(struct string_list *authors, struct commit *commit, | ||||
| 	struct Period *period) | ||||
| 	struct cgit_period *period) | ||||
| { | ||||
| 	struct commitinfo *info; | ||||
| 	struct string_list_item *author, *item; | ||||
| @@ -190,7 +200,7 @@ static int cmp_total_commits(const void *a1, const void *a2) | ||||
|  * timeperiod into a nested string_list collection. | ||||
|  */ | ||||
| struct string_list collect_stats(struct cgit_context *ctx, | ||||
| 	struct Period *period) | ||||
| 	struct cgit_period *period) | ||||
| { | ||||
| 	struct string_list authors; | ||||
| 	struct rev_info rev; | ||||
| @@ -233,7 +243,7 @@ struct string_list collect_stats(struct cgit_context *ctx, | ||||
|  | ||||
| void print_combined_authorrow(struct string_list *authors, int from, int to, | ||||
| 	const char *name, const char *leftclass, const char *centerclass, | ||||
| 	const char *rightclass, struct Period *period) | ||||
| 	const char *rightclass, struct cgit_period *period) | ||||
| { | ||||
| 	struct string_list_item *author; | ||||
| 	struct authorstat *authorstat; | ||||
| @@ -271,7 +281,8 @@ void print_combined_authorrow(struct string_list *authors, int from, int to, | ||||
| 	htmlf("<td class='%s'>%d</td></tr>", rightclass, total); | ||||
| } | ||||
|  | ||||
| void print_authors(struct string_list *authors, int top, struct Period *period) | ||||
| void print_authors(struct string_list *authors, int top, | ||||
| 		   struct cgit_period *period) | ||||
| { | ||||
| 	struct string_list_item *author; | ||||
| 	struct authorstat *authorstat; | ||||
| @@ -339,16 +350,22 @@ void print_authors(struct string_list *authors, int top, struct Period *period) | ||||
| void cgit_show_stats(struct cgit_context *ctx) | ||||
| { | ||||
| 	struct string_list authors; | ||||
| 	struct Period *period; | ||||
| 	struct cgit_period *period; | ||||
| 	int top, i; | ||||
| 	const char *code = "w"; | ||||
|  | ||||
| 	period = &periods[0]; | ||||
| 	if (ctx->qry.period) { | ||||
| 		for (i = 0; i < sizeof(periods) / sizeof(periods[0]); i++) | ||||
| 			if (periods[i].code == ctx->qry.period[0]) { | ||||
| 				period = &periods[i]; | ||||
| 				break; | ||||
| 			} | ||||
| 	if (ctx->qry.period) | ||||
| 		code = ctx->qry.period; | ||||
|  | ||||
| 	i = cgit_find_stats_period(code, &period); | ||||
| 	if (!i) { | ||||
| 		cgit_print_error(fmt("Unknown statistics type: %c", code)); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (i > ctx->repo->max_stats) { | ||||
| 		cgit_print_error(fmt("Statistics type disabled: %s", | ||||
| 				     period->name)); | ||||
| 		return; | ||||
| 	} | ||||
| 	authors = collect_stats(ctx, period); | ||||
| 	qsort(authors.items, authors.nr, sizeof(struct string_list_item), | ||||
| @@ -368,14 +385,16 @@ void cgit_show_stats(struct cgit_context *ctx) | ||||
| 	html("<form method='get' action='.' style='float: right; text-align: right;'>"); | ||||
| 	if (strcmp(ctx->qry.head, ctx->repo->defbranch)) | ||||
| 		htmlf("<input type='hidden' name='h' value='%s'/>", ctx->qry.head); | ||||
| 	html("Period: "); | ||||
| 	html("<select name='period' onchange='this.form.submit();'>"); | ||||
| 	for (i = 0; i < sizeof(periods) / sizeof(periods[0]); i++) | ||||
| 		htmlf("<option value='%c'%s>%s</option>", | ||||
| 			periods[i].code, | ||||
| 			period == &periods[i] ? " selected" : "", | ||||
| 			periods[i].name); | ||||
| 	html("</select><br/><br/>"); | ||||
| 	if (ctx->repo->max_stats > 1) { | ||||
| 		html("Period: "); | ||||
| 		html("<select name='period' onchange='this.form.submit();'>"); | ||||
| 		for (i = 0; i < ctx->repo->max_stats; i++) | ||||
| 			htmlf("<option value='%c'%s>%s</option>", | ||||
| 				periods[i].code, | ||||
| 				period == &periods[i] ? " selected" : "", | ||||
| 				periods[i].name); | ||||
| 		html("</select><br/><br/>"); | ||||
| 	} | ||||
| 	html("Authors: "); | ||||
| 	html(""); | ||||
| 	html("<select name='ofs' onchange='this.form.submit();'>"); | ||||
|   | ||||
							
								
								
									
										19
									
								
								ui-stats.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								ui-stats.h
									
									
									
									
									
								
							| @@ -3,6 +3,25 @@ | ||||
|  | ||||
| #include "cgit.h" | ||||
|  | ||||
| struct cgit_period { | ||||
| 	const char code; | ||||
| 	const char *name; | ||||
| 	int max_periods; | ||||
| 	int count; | ||||
|  | ||||
| 	/* Convert a tm value to the first day in the period */ | ||||
| 	void (*trunc)(struct tm *tm); | ||||
|  | ||||
| 	/* Update tm value to start of next/previous period */ | ||||
| 	void (*dec)(struct tm *tm); | ||||
| 	void (*inc)(struct tm *tm); | ||||
|  | ||||
| 	/* Pretty-print a tm value */ | ||||
| 	char *(*pretty)(struct tm *tm); | ||||
| }; | ||||
|  | ||||
| extern int cgit_find_stats_period(const char *expr, struct cgit_period **period); | ||||
|  | ||||
| extern void cgit_show_stats(struct cgit_context *ctx); | ||||
|  | ||||
| #endif /* UI_STATS_H */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Lars Hjemli
					Lars Hjemli