aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--cgit.c50
-rw-r--r--cgit.css100
-rw-r--r--cgit.h3
-rw-r--r--cgitrc.5.txt21
-rw-r--r--cmd.c7
-rw-r--r--shared.c1
-rwxr-xr-xtests/t0107-snapshot.sh22
-rw-r--r--ui-log.c38
-rw-r--r--ui-refs.c4
-rw-r--r--ui-shared.c22
-rw-r--r--ui-shared.h5
-rw-r--r--ui-snapshot.c12
-rw-r--r--ui-stats.c410
-rw-r--r--ui-stats.h27
-rw-r--r--ui-tag.c16
-rw-r--r--ui-tree.c3
17 files changed, 703 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index 3c7ec07..a52285e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,13 @@
1CGIT_VERSION = v0.8.1 1CGIT_VERSION = v0.8.1
2CGIT_SCRIPT_NAME = cgit.cgi 2CGIT_SCRIPT_NAME = cgit.cgi
3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit 3CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
4CGIT_CONFIG = /etc/cgitrc 5CGIT_CONFIG = /etc/cgitrc
5CACHE_ROOT = /var/cache/cgit 6CACHE_ROOT = /var/cache/cgit
6SHA1_HEADER = <openssl/sha.h> 7SHA1_HEADER = <openssl/sha.h>
7GIT_VER = 1.6.1 8GIT_VER = 1.6.1
8GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 9GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
10INSTALL = install
9 11
10# Define NO_STRCASESTR if you don't have strcasestr. 12# Define NO_STRCASESTR if you don't have strcasestr.
11# 13#
@@ -88,6 +90,7 @@ OBJECTS += ui-refs.o
88OBJECTS += ui-repolist.o 90OBJECTS += ui-repolist.o
89OBJECTS += ui-shared.o 91OBJECTS += ui-shared.o
90OBJECTS += ui-snapshot.o 92OBJECTS += ui-snapshot.o
93OBJECTS += ui-stats.o
91OBJECTS += ui-summary.o 94OBJECTS += ui-summary.o
92OBJECTS += ui-tag.o 95OBJECTS += ui-tag.o
93OBJECTS += ui-tree.o 96OBJECTS += ui-tree.o
@@ -128,22 +131,23 @@ cgit.o: VERSION
128-include $(OBJECTS:.o=.d) 131-include $(OBJECTS:.o=.d)
129 132
130libgit: 133libgit:
131 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) libgit.a 134 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 libgit.a
132 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) xdiff/lib.a 135 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 xdiff/lib.a
133 136
134test: all 137test: all
135 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all 138 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all
136 139
137install: all 140install: all
138 mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH) 141 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH)
139 install cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 142 $(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
140 install -m 0644 cgit.css $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.css 143 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
141 install -m 0644 cgit.png $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.png 144 $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
145 $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
142 146
143uninstall: 147uninstall:
144 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 148 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
145 rm -f $(CGIT_SCRIPT_PATH)/cgit.css 149 rm -f $(CGIT_DATA_PATH)/cgit.css
146 rm -f $(CGIT_SCRIPT_PATH)/cgit.png 150 rm -f $(CGIT_DATA_PATH)/cgit.png
147 151
148clean: 152clean:
149 rm -f cgit VERSION *.o *.d 153 rm -f cgit VERSION *.o *.d
diff --git a/cgit.c b/cgit.c
index 166fbc6..608cab6 100644
--- a/cgit.c
+++ b/cgit.c
@@ -12,6 +12,7 @@
12#include "configfile.h" 12#include "configfile.h"
13#include "html.h" 13#include "html.h"
14#include "ui-shared.h" 14#include "ui-shared.h"
15#include "ui-stats.h"
15#include "scan-tree.h" 16#include "scan-tree.h"
16 17
17const char *cgit_version = CGIT_VERSION; 18const char *cgit_version = CGIT_VERSION;
@@ -54,6 +55,8 @@ void config_cb(const char *name, const char *value)
54 ctx.cfg.enable_log_filecount = atoi(value); 55 ctx.cfg.enable_log_filecount = atoi(value);
55 else if (!strcmp(name, "enable-log-linecount")) 56 else if (!strcmp(name, "enable-log-linecount"))
56 ctx.cfg.enable_log_linecount = atoi(value); 57 ctx.cfg.enable_log_linecount = atoi(value);
58 else if (!strcmp(name, "max-stats"))
59 ctx.cfg.max_stats = cgit_find_stats_period(value, NULL);
57 else if (!strcmp(name, "cache-size")) 60 else if (!strcmp(name, "cache-size"))
58 ctx.cfg.cache_size = atoi(value); 61 ctx.cfg.cache_size = atoi(value);
59 else if (!strcmp(name, "cache-root")) 62 else if (!strcmp(name, "cache-root"))
@@ -112,6 +115,8 @@ void config_cb(const char *name, const char *value)
112 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 115 ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
113 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) 116 else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount"))
114 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 117 ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
118 else if (ctx.repo && !strcmp(name, "repo.max-stats"))
119 ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
115 else if (ctx.repo && !strcmp(name, "repo.module-link")) 120 else if (ctx.repo && !strcmp(name, "repo.module-link"))
116 ctx.repo->module_link= xstrdup(value); 121 ctx.repo->module_link= xstrdup(value);
117 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 122 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
@@ -158,6 +163,8 @@ static void querystring_cb(const char *name, const char *value)
158 ctx.qry.sort = xstrdup(value); 163 ctx.qry.sort = xstrdup(value);
159 } else if (!strcmp(name, "showmsg")) { 164 } else if (!strcmp(name, "showmsg")) {
160 ctx.qry.showmsg = atoi(value); 165 ctx.qry.showmsg = atoi(value);
166 } else if (!strcmp(name, "period")) {
167 ctx.qry.period = xstrdup(value);
161 } 168 }
162} 169}
163 170
@@ -181,6 +188,7 @@ static void prepare_context(struct cgit_context *ctx)
181 ctx->cfg.max_lock_attempts = 5; 188 ctx->cfg.max_lock_attempts = 5;
182 ctx->cfg.max_msg_len = 80; 189 ctx->cfg.max_msg_len = 80;
183 ctx->cfg.max_repodesc_len = 80; 190 ctx->cfg.max_repodesc_len = 80;
191 ctx->cfg.max_stats = 0;
184 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 192 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
185 ctx->cfg.renamelimit = -1; 193 ctx->cfg.renamelimit = -1;
186 ctx->cfg.robots = "index, nofollow"; 194 ctx->cfg.robots = "index, nofollow";
@@ -293,7 +301,6 @@ static void process_request(void *cbdata)
293 cmd = cgit_get_cmd(ctx); 301 cmd = cgit_get_cmd(ctx);
294 if (!cmd) { 302 if (!cmd) {
295 ctx->page.title = "cgit error"; 303 ctx->page.title = "cgit error";
296 ctx->repo = NULL;
297 cgit_print_http_headers(ctx); 304 cgit_print_http_headers(ctx);
298 cgit_print_docstart(ctx); 305 cgit_print_docstart(ctx);
299 cgit_print_pageheader(ctx); 306 cgit_print_pageheader(ctx);
@@ -439,28 +446,29 @@ int main(int argc, const char **argv)
439 ctx.repo = NULL; 446 ctx.repo = NULL;
440 http_parse_querystring(ctx.qry.raw, querystring_cb); 447 http_parse_querystring(ctx.qry.raw, querystring_cb);
441 448
442 /* If virtual-root isn't specified in cgitrc and no url 449 /* If virtual-root isn't specified in cgitrc, lets pretend
443 * parameter is specified on the querystring, lets pretend 450 * that virtual-root equals SCRIPT_NAME.
444 * that virtualroot equals SCRIPT_NAME and use PATH_INFO as
445 * url. This allows cgit to work with virtual urls without
446 * the need for rewriterules in the webserver (as long as
447 * PATH_INFO is included in the cache lookup key).
448 */ 451 */
449 if (!ctx.cfg.virtual_root && !ctx.qry.url) { 452 if (!ctx.cfg.virtual_root)
450 ctx.cfg.virtual_root = ctx.cfg.script_name; 453 ctx.cfg.virtual_root = ctx.cfg.script_name;
451 path = getenv("PATH_INFO"); 454
452 if (path) { 455 /* If no url parameter is specified on the querystring, lets
453 if (path[0] == '/') 456 * use PATH_INFO as url. This allows cgit to work with virtual
454 path++; 457 * urls without the need for rewriterules in the webserver (as
455 ctx.qry.url = xstrdup(path); 458 * long as PATH_INFO is included in the cache lookup key).
456 if (ctx.qry.raw) { 459 */
457 qry = ctx.qry.raw; 460 path = getenv("PATH_INFO");
458 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 461 if (!ctx.qry.url && path) {
459 free(qry); 462 if (path[0] == '/')
460 } else 463 path++;
461 ctx.qry.raw = ctx.qry.url; 464 ctx.qry.url = xstrdup(path);
462 cgit_parse_url(ctx.qry.url); 465 if (ctx.qry.raw) {
463 } 466 qry = ctx.qry.raw;
467 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
468 free(qry);
469 } else
470 ctx.qry.raw = ctx.qry.url;
471 cgit_parse_url(ctx.qry.url);
464 } 472 }
465 473
466 ttl = calc_ttl(); 474 ttl = calc_ttl();
diff --git a/cgit.css b/cgit.css
index 068c37b..f844efa 100644
--- a/cgit.css
+++ b/cgit.css
@@ -476,3 +476,103 @@ div.footer {
476 font-size: 80%; 476 font-size: 80%;
477 color: #ccc; 477 color: #ccc;
478} 478}
479a.branch-deco {
480 margin: 0px 0.5em;
481 padding: 0px 0.25em;
482 background-color: #88ff88;
483 border: solid 1px #007700;
484}
485a.tag-deco {
486 margin: 0px 0.5em;
487 padding: 0px 0.25em;
488 background-color: #ffff88;
489 border: solid 1px #777700;
490}
491a.remote-deco {
492 margin: 0px 0.5em;
493 padding: 0px 0.25em;
494 background-color: #ccccff;
495 border: solid 1px #000077;
496}
497a.deco {
498 margin: 0px 0.5em;
499 padding: 0px 0.25em;
500 background-color: #ff8888;
501 border: solid 1px #770000;
502}
503table.stats {
504 border: solid 1px black;
505 border-collapse: collapse;
506}
507
508table.stats th {
509 text-align: left;
510 padding: 1px 0.5em;
511 background-color: #eee;
512 border: solid 1px black;
513}
514
515table.stats td {
516 text-align: right;
517 padding: 1px 0.5em;
518 border: solid 1px black;
519}
520
521table.stats td.total {
522 font-weight: bold;
523 text-align: left;
524}
525
526table.stats td.sum {
527 color: #c00;
528 font-weight: bold;
529/* background-color: #eee; */
530}
531
532table.stats td.left {
533 text-align: left;
534}
535
536table.vgraph {
537 border-collapse: separate;
538 border: solid 1px black;
539 height: 200px;
540}
541
542table.vgraph th {
543 background-color: #eee;
544 font-weight: bold;
545 border: solid 1px white;
546 padding: 1px 0.5em;
547}
548
549table.vgraph td {
550 vertical-align: bottom;
551 padding: 0px 10px;
552}
553
554table.vgraph div.bar {
555 background-color: #eee;
556}
557
558table.hgraph {
559 border: solid 1px black;
560 width: 800px;
561}
562
563table.hgraph th {
564 background-color: #eee;
565 font-weight: bold;
566 border: solid 1px black;
567 padding: 1px 0.5em;
568}
569
570table.hgraph td {
571 vertical-align: center;
572 padding: 2px 2px;
573}
574
575table.hgraph div.bar {
576 background-color: #eee;
577 height: 1em;
578}
diff --git a/cgit.h b/cgit.h
index cb2f176..4fe94c6 100644
--- a/cgit.h
+++ b/cgit.h
@@ -61,6 +61,7 @@ struct cgit_repo {
61 int snapshots; 61 int snapshots;
62 int enable_log_filecount; 62 int enable_log_filecount;
63 int enable_log_linecount; 63 int enable_log_linecount;
64 int max_stats;
64 time_t mtime; 65 time_t mtime;
65}; 66};
66 67
@@ -120,6 +121,7 @@ struct cgit_query {
120 char *name; 121 char *name;
121 char *mimetype; 122 char *mimetype;
122 char *url; 123 char *url;
124 char *period;
123 int ofs; 125 int ofs;
124 int nohead; 126 int nohead;
125 char *sort; 127 char *sort;
@@ -160,6 +162,7 @@ struct cgit_config {
160 int max_lock_attempts; 162 int max_lock_attempts;
161 int max_msg_len; 163 int max_msg_len;
162 int max_repodesc_len; 164 int max_repodesc_len;
165 int max_stats;
163 int nocache; 166 int nocache;
164 int renamelimit; 167 int renamelimit;
165 int snapshots; 168 int snapshots;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 7887b02..09f56a6 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -129,6 +129,11 @@ max-repodesc-length
129 Specifies the maximum number of repo description characters to display 129 Specifies the maximum number of repo description characters to display
130 on the repository index page. Default value: "80". 130 on the repository index page. Default value: "80".
131 131
132max-stats
133 Set the default maximum statistics period. Valid values are "week",
134 "month", "quarter" and "year". If unspecified, statistics are
135 disabled. Default value: none. See also: "repo.max-stats".
136
132module-link 137module-link
133 Text which will be used as the formatstring for a hyperlink when a 138 Text which will be used as the formatstring for a hyperlink when a
134 submodule is printed in a directory listing. The arguments for the 139 submodule is printed in a directory listing. The arguments for the
@@ -218,6 +223,11 @@ repo.enable-log-linecount
218 A flag which can be used to disable the global setting 223 A flag which can be used to disable the global setting
219 `enable-log-linecount'. Default value: none. 224 `enable-log-linecount'. Default value: none.
220 225
226repo.max-stats
227 Override the default maximum statistics period. Valid values are equal
228 to the values specified for the global "max-stats" setting. Default
229 value: none.
230
221repo.name 231repo.name
222 The value to show as repository name. Default value: <repo.url>. 232 The value to show as repository name. Default value: <repo.url>.
223 233
@@ -276,6 +286,10 @@ favicon=/favicon.ico
276logo=/img/mylogo.png 286logo=/img/mylogo.png
277 287
278 288
289# Enable statistics per week, month and quarter
290max-stats=quarter
291
292
279# Set the title and heading of the repository index page 293# Set the title and heading of the repository index page
280root-title=foobar.com git repositories 294root-title=foobar.com git repositories
281 295
@@ -288,8 +302,8 @@ root-desc=tracking the foobar development
288root-readme=/var/www/htdocs/about.html 302root-readme=/var/www/htdocs/about.html
289 303
290 304
291# Allow download of tar.gz, tar.bz and zip-files 305# Allow download of tar.gz, tar.bz2 and zip-files
292snapshots=tar.gz tar.bz zip 306snapshots=tar.gz tar.bz2 zip
293 307
294 308
295## 309##
@@ -348,6 +362,9 @@ repo.snapshots=0
348# Disable line-counts for this repo 362# Disable line-counts for this repo
349repo.enable-log-linecount=0 363repo.enable-log-linecount=0
350 364
365# Restrict the max statistics period for this repo
366repo.max-stats=month
367
351 368
352BUGS 369BUGS
353---- 370----
diff --git a/cmd.c b/cmd.c
index 8914fa5..cf97da7 100644
--- a/cmd.c
+++ b/cmd.c
@@ -21,6 +21,7 @@
21#include "ui-refs.h" 21#include "ui-refs.h"
22#include "ui-repolist.h" 22#include "ui-repolist.h"
23#include "ui-snapshot.h" 23#include "ui-snapshot.h"
24#include "ui-stats.h"
24#include "ui-summary.h" 25#include "ui-summary.h"
25#include "ui-tag.h" 26#include "ui-tag.h"
26#include "ui-tree.h" 27#include "ui-tree.h"
@@ -108,6 +109,11 @@ static void snapshot_fn(struct cgit_context *ctx)
108 ctx->repo->snapshots, ctx->qry.nohead); 109 ctx->repo->snapshots, ctx->qry.nohead);
109} 110}
110 111
112static void stats_fn(struct cgit_context *ctx)
113{
114 cgit_show_stats(ctx);
115}
116
111static void summary_fn(struct cgit_context *ctx) 117static void summary_fn(struct cgit_context *ctx)
112{ 118{
113 cgit_print_summary(); 119 cgit_print_summary();
@@ -144,6 +150,7 @@ struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
144 def_cmd(refs, 1, 1), 150 def_cmd(refs, 1, 1),
145 def_cmd(repolist, 0, 0), 151 def_cmd(repolist, 0, 0),
146 def_cmd(snapshot, 1, 0), 152 def_cmd(snapshot, 1, 0),
153 def_cmd(stats, 1, 1),
147 def_cmd(summary, 1, 1), 154 def_cmd(summary, 1, 1),
148 def_cmd(tag, 1, 1), 155 def_cmd(tag, 1, 1),
149 def_cmd(tree, 1, 1), 156 def_cmd(tree, 1, 1),
diff --git a/shared.c b/shared.c
index a764c4d..578a544 100644
--- a/shared.c
+++ b/shared.c
@@ -58,6 +58,7 @@ struct cgit_repo *cgit_add_repo(const char *url)
58 ret->snapshots = ctx.cfg.snapshots; 58 ret->snapshots = ctx.cfg.snapshots;
59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount; 59 ret->enable_log_filecount = ctx.cfg.enable_log_filecount;
60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount; 60 ret->enable_log_linecount = ctx.cfg.enable_log_linecount;
61 ret->max_stats = ctx.cfg.max_stats;
61 ret->module_link = ctx.cfg.module_link; 62 ret->module_link = ctx.cfg.module_link;
62 ret->readme = NULL; 63 ret->readme = NULL;
63 ret->mtime = -1; 64 ret->mtime = -1;
diff --git a/tests/t0107-snapshot.sh b/tests/t0107-snapshot.sh
index d97c465..8ab4912 100755
--- a/tests/t0107-snapshot.sh
+++ b/tests/t0107-snapshot.sh
@@ -4,36 +4,36 @@
4 4
5prepare_tests "Verify snapshot" 5prepare_tests "Verify snapshot"
6 6
7run_test 'get foo/snapshot/test.tar.gz' ' 7run_test 'get foo/snapshot/master.tar.gz' '
8 cgit_url "foo/snapshot/test.tar.gz" >trash/tmp 8 cgit_url "foo/snapshot/master.tar.gz" >trash/tmp
9' 9'
10 10
11run_test 'check html headers' ' 11run_test 'check html headers' '
12 head -n 1 trash/tmp | 12 head -n 1 trash/tmp |
13 grep -e "Content-Type: application/x-tar" && 13 grep -e "Content-Type: application/x-gzip" &&
14 14
15 head -n 2 trash/tmp | 15 head -n 2 trash/tmp |
16 grep -e "Content-Disposition: inline; filename=.test.tar.gz." 16 grep -e "Content-Disposition: inline; filename=.master.tar.gz."
17' 17'
18 18
19run_test 'strip off the header lines' ' 19run_test 'strip off the header lines' '
20 tail -n +6 trash/tmp > trash/test.tar.gz 20 tail -n +6 trash/tmp > trash/master.tar.gz
21' 21'
22 22
23run_test 'verify gzip format' 'gunzip --test trash/test.tar.gz' 23run_test 'verify gzip format' 'gunzip --test trash/master.tar.gz'
24run_test 'untar' ' 24run_test 'untar' '
25 rm -rf trash/foo && 25 rm -rf trash/master &&
26 tar -xf trash/test.tar.gz -C trash 26 tar -xf trash/master.tar.gz -C trash
27' 27'
28 28
29run_test 'count files' ' 29run_test 'count files' '
30 c=$(ls -1 trash/foo/ | wc -l) && 30 c=$(ls -1 trash/master/ | wc -l) &&
31 test $c = 5 31 test $c = 5
32' 32'
33 33
34run_test 'verify untarred file-5' ' 34run_test 'verify untarred file-5' '
35 grep -e "^5$" trash/foo/file-5 &&