author | Lars Hjemli <hjemli@gmail.com> | 2008-12-06 16:38:19 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2008-12-06 16:38:19 (UTC) |
commit | f86a23ff537258d36bf8f1876fa7a4bede6673d8 (patch) (unidiff) | |
tree | 8328d415416058cdc5b0fd2c6564ddcab5766c7a /cgit.c | |
parent | 140012d7a8e51df5a9f9c556696778b86ade4fc9 (diff) | |
download | cgit-f86a23ff537258d36bf8f1876fa7a4bede6673d8.zip cgit-f86a23ff537258d36bf8f1876fa7a4bede6673d8.tar.gz cgit-f86a23ff537258d36bf8f1876fa7a4bede6673d8.tar.bz2 |
Add a 'stats' page to each repo
This new page, which is disabled by default, can be used to print some
statistics about the number of commits per period in the repository,
where period can be either weeks, months, quarters or years.
The function can be activated globally by setting 'enable-stats=1' in
cgitrc and disabled for individual repos by setting 'repo.enable-stats=0'.
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 6 |
1 files changed, 6 insertions, 0 deletions
@@ -9,196 +9,202 @@ | |||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | #include "cache.h" | 10 | #include "cache.h" |
11 | #include "cmd.h" | 11 | #include "cmd.h" |
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 "scan-tree.h" | 15 | #include "scan-tree.h" |
16 | 16 | ||
17 | const char *cgit_version = CGIT_VERSION; | 17 | const char *cgit_version = CGIT_VERSION; |
18 | 18 | ||
19 | void config_cb(const char *name, const char *value) | 19 | void config_cb(const char *name, const char *value) |
20 | { | 20 | { |
21 | if (!strcmp(name, "root-title")) | 21 | if (!strcmp(name, "root-title")) |
22 | ctx.cfg.root_title = xstrdup(value); | 22 | ctx.cfg.root_title = xstrdup(value); |
23 | else if (!strcmp(name, "root-desc")) | 23 | else if (!strcmp(name, "root-desc")) |
24 | ctx.cfg.root_desc = xstrdup(value); | 24 | ctx.cfg.root_desc = xstrdup(value); |
25 | else if (!strcmp(name, "root-readme")) | 25 | else if (!strcmp(name, "root-readme")) |
26 | ctx.cfg.root_readme = xstrdup(value); | 26 | ctx.cfg.root_readme = xstrdup(value); |
27 | else if (!strcmp(name, "css")) | 27 | else if (!strcmp(name, "css")) |
28 | ctx.cfg.css = xstrdup(value); | 28 | ctx.cfg.css = xstrdup(value); |
29 | else if (!strcmp(name, "favicon")) | 29 | else if (!strcmp(name, "favicon")) |
30 | ctx.cfg.favicon = xstrdup(value); | 30 | ctx.cfg.favicon = xstrdup(value); |
31 | else if (!strcmp(name, "footer")) | 31 | else if (!strcmp(name, "footer")) |
32 | ctx.cfg.footer = xstrdup(value); | 32 | ctx.cfg.footer = xstrdup(value); |
33 | else if (!strcmp(name, "logo")) | 33 | else if (!strcmp(name, "logo")) |
34 | ctx.cfg.logo = xstrdup(value); | 34 | ctx.cfg.logo = xstrdup(value); |
35 | else if (!strcmp(name, "index-header")) | 35 | else if (!strcmp(name, "index-header")) |
36 | ctx.cfg.index_header = xstrdup(value); | 36 | ctx.cfg.index_header = xstrdup(value); |
37 | else if (!strcmp(name, "index-info")) | 37 | else if (!strcmp(name, "index-info")) |
38 | ctx.cfg.index_info = xstrdup(value); | 38 | ctx.cfg.index_info = xstrdup(value); |
39 | else if (!strcmp(name, "logo-link")) | 39 | else if (!strcmp(name, "logo-link")) |
40 | ctx.cfg.logo_link = xstrdup(value); | 40 | ctx.cfg.logo_link = xstrdup(value); |
41 | else if (!strcmp(name, "module-link")) | 41 | else if (!strcmp(name, "module-link")) |
42 | ctx.cfg.module_link = xstrdup(value); | 42 | ctx.cfg.module_link = xstrdup(value); |
43 | else if (!strcmp(name, "virtual-root")) { | 43 | else if (!strcmp(name, "virtual-root")) { |
44 | ctx.cfg.virtual_root = trim_end(value, '/'); | 44 | ctx.cfg.virtual_root = trim_end(value, '/'); |
45 | if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) | 45 | if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) |
46 | ctx.cfg.virtual_root = ""; | 46 | ctx.cfg.virtual_root = ""; |
47 | } else if (!strcmp(name, "nocache")) | 47 | } else if (!strcmp(name, "nocache")) |
48 | ctx.cfg.nocache = atoi(value); | 48 | ctx.cfg.nocache = atoi(value); |
49 | else if (!strcmp(name, "snapshots")) | 49 | else if (!strcmp(name, "snapshots")) |
50 | ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); | 50 | ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); |
51 | else if (!strcmp(name, "enable-index-links")) | 51 | else if (!strcmp(name, "enable-index-links")) |
52 | ctx.cfg.enable_index_links = atoi(value); | 52 | ctx.cfg.enable_index_links = atoi(value); |
53 | else if (!strcmp(name, "enable-log-filecount")) | 53 | else if (!strcmp(name, "enable-log-filecount")) |
54 | ctx.cfg.enable_log_filecount = atoi(value); | 54 | ctx.cfg.enable_log_filecount = atoi(value); |
55 | else if (!strcmp(name, "enable-log-linecount")) | 55 | else if (!strcmp(name, "enable-log-linecount")) |
56 | ctx.cfg.enable_log_linecount = atoi(value); | 56 | ctx.cfg.enable_log_linecount = atoi(value); |
57 | else if (!strcmp(name, "enable-stats")) | ||
58 | ctx.cfg.enable_stats = atoi(value); | ||
57 | else if (!strcmp(name, "cache-size")) | 59 | else if (!strcmp(name, "cache-size")) |
58 | ctx.cfg.cache_size = atoi(value); | 60 | ctx.cfg.cache_size = atoi(value); |
59 | else if (!strcmp(name, "cache-root")) | 61 | else if (!strcmp(name, "cache-root")) |
60 | ctx.cfg.cache_root = xstrdup(value); | 62 | ctx.cfg.cache_root = xstrdup(value); |
61 | else if (!strcmp(name, "cache-root-ttl")) | 63 | else if (!strcmp(name, "cache-root-ttl")) |
62 | ctx.cfg.cache_root_ttl = atoi(value); | 64 | ctx.cfg.cache_root_ttl = atoi(value); |
63 | else if (!strcmp(name, "cache-repo-ttl")) | 65 | else if (!strcmp(name, "cache-repo-ttl")) |
64 | ctx.cfg.cache_repo_ttl = atoi(value); | 66 | ctx.cfg.cache_repo_ttl = atoi(value); |
65 | else if (!strcmp(name, "cache-static-ttl")) | 67 | else if (!strcmp(name, "cache-static-ttl")) |
66 | ctx.cfg.cache_static_ttl = atoi(value); | 68 | ctx.cfg.cache_static_ttl = atoi(value); |
67 | else if (!strcmp(name, "cache-dynamic-ttl")) | 69 | else if (!strcmp(name, "cache-dynamic-ttl")) |
68 | ctx.cfg.cache_dynamic_ttl = atoi(value); | 70 | ctx.cfg.cache_dynamic_ttl = atoi(value); |
69 | else if (!strcmp(name, "max-message-length")) | 71 | else if (!strcmp(name, "max-message-length")) |
70 | ctx.cfg.max_msg_len = atoi(value); | 72 | ctx.cfg.max_msg_len = atoi(value); |
71 | else if (!strcmp(name, "max-repodesc-length")) | 73 | else if (!strcmp(name, "max-repodesc-length")) |
72 | ctx.cfg.max_repodesc_len = atoi(value); | 74 | ctx.cfg.max_repodesc_len = atoi(value); |
73 | else if (!strcmp(name, "max-repo-count")) | 75 | else if (!strcmp(name, "max-repo-count")) |
74 | ctx.cfg.max_repo_count = atoi(value); | 76 | ctx.cfg.max_repo_count = atoi(value); |
75 | else if (!strcmp(name, "max-commit-count")) | 77 | else if (!strcmp(name, "max-commit-count")) |
76 | ctx.cfg.max_commit_count = atoi(value); | 78 | ctx.cfg.max_commit_count = atoi(value); |
77 | else if (!strcmp(name, "summary-log")) | 79 | else if (!strcmp(name, "summary-log")) |
78 | ctx.cfg.summary_log = atoi(value); | 80 | ctx.cfg.summary_log = atoi(value); |
79 | else if (!strcmp(name, "summary-branches")) | 81 | else if (!strcmp(name, "summary-branches")) |
80 | ctx.cfg.summary_branches = atoi(value); | 82 | ctx.cfg.summary_branches = atoi(value); |
81 | else if (!strcmp(name, "summary-tags")) | 83 | else if (!strcmp(name, "summary-tags")) |
82 | ctx.cfg.summary_tags = atoi(value); | 84 | ctx.cfg.summary_tags = atoi(value); |
83 | else if (!strcmp(name, "agefile")) | 85 | else if (!strcmp(name, "agefile")) |
84 | ctx.cfg.agefile = xstrdup(value); | 86 | ctx.cfg.agefile = xstrdup(value); |
85 | else if (!strcmp(name, "renamelimit")) | 87 | else if (!strcmp(name, "renamelimit")) |
86 | ctx.cfg.renamelimit = atoi(value); | 88 | ctx.cfg.renamelimit = atoi(value); |
87 | else if (!strcmp(name, "robots")) | 89 | else if (!strcmp(name, "robots")) |
88 | ctx.cfg.robots = xstrdup(value); | 90 | ctx.cfg.robots = xstrdup(value); |
89 | else if (!strcmp(name, "clone-prefix")) | 91 | else if (!strcmp(name, "clone-prefix")) |
90 | ctx.cfg.clone_prefix = xstrdup(value); | 92 | ctx.cfg.clone_prefix = xstrdup(value); |
91 | else if (!strcmp(name, "local-time")) | 93 | else if (!strcmp(name, "local-time")) |
92 | ctx.cfg.local_time = atoi(value); | 94 | ctx.cfg.local_time = atoi(value); |
93 | else if (!strcmp(name, "repo.group")) | 95 | else if (!strcmp(name, "repo.group")) |
94 | ctx.cfg.repo_group = xstrdup(value); | 96 | ctx.cfg.repo_group = xstrdup(value); |
95 | else if (!strcmp(name, "repo.url")) | 97 | else if (!strcmp(name, "repo.url")) |
96 | ctx.repo = cgit_add_repo(value); | 98 | ctx.repo = cgit_add_repo(value); |
97 | else if (!strcmp(name, "repo.name")) | 99 | else if (!strcmp(name, "repo.name")) |
98 | ctx.repo->name = xstrdup(value); | 100 | ctx.repo->name = xstrdup(value); |
99 | else if (ctx.repo && !strcmp(name, "repo.path")) | 101 | else if (ctx.repo && !strcmp(name, "repo.path")) |
100 | ctx.repo->path = trim_end(value, '/'); | 102 | ctx.repo->path = trim_end(value, '/'); |
101 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) | 103 | else if (ctx.repo && !strcmp(name, "repo.clone-url")) |
102 | ctx.repo->clone_url = xstrdup(value); | 104 | ctx.repo->clone_url = xstrdup(value); |
103 | else if (ctx.repo && !strcmp(name, "repo.desc")) | 105 | else if (ctx.repo && !strcmp(name, "repo.desc")) |
104 | ctx.repo->desc = xstrdup(value); | 106 | ctx.repo->desc = xstrdup(value); |
105 | else if (ctx.repo && !strcmp(name, "repo.owner")) | 107 | else if (ctx.repo && !strcmp(name, "repo.owner")) |
106 | ctx.repo->owner = xstrdup(value); | 108 | ctx.repo->owner = xstrdup(value); |
107 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) | 109 | else if (ctx.repo && !strcmp(name, "repo.defbranch")) |
108 | ctx.repo->defbranch = xstrdup(value); | 110 | ctx.repo->defbranch = xstrdup(value); |
109 | else if (ctx.repo && !strcmp(name, "repo.snapshots")) | 111 | else if (ctx.repo && !strcmp(name, "repo.snapshots")) |
110 | ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ | 112 | ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ |
111 | else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) | 113 | else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) |
112 | ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); | 114 | ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); |
113 | else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) | 115 | else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) |
114 | ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); | 116 | ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); |
117 | else if (ctx.repo && !strcmp(name, "repo.enable-stats")) | ||
118 | ctx.repo->enable_stats = ctx.cfg.enable_stats && atoi(value); | ||
115 | else if (ctx.repo && !strcmp(name, "repo.module-link")) | 119 | else if (ctx.repo && !strcmp(name, "repo.module-link")) |
116 | ctx.repo->module_link= xstrdup(value); | 120 | ctx.repo->module_link= xstrdup(value); |
117 | else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { | 121 | else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { |
118 | if (*value == '/') | 122 | if (*value == '/') |
119 | ctx.repo->readme = xstrdup(value); | 123 | ctx.repo->readme = xstrdup(value); |
120 | else | 124 | else |
121 | ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); | 125 | ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); |
122 | } else if (!strcmp(name, "include")) | 126 | } else if (!strcmp(name, "include")) |
123 | parse_configfile(value, config_cb); | 127 | parse_configfile(value, config_cb); |
124 | } | 128 | } |
125 | 129 | ||
126 | static void querystring_cb(const char *name, const char *value) | 130 | static void querystring_cb(const char *name, const char *value) |
127 | { | 131 | { |
128 | if (!strcmp(name,"r")) { | 132 | if (!strcmp(name,"r")) { |
129 | ctx.qry.repo = xstrdup(value); | 133 | ctx.qry.repo = xstrdup(value); |
130 | ctx.repo = cgit_get_repoinfo(value); | 134 | ctx.repo = cgit_get_repoinfo(value); |
131 | } else if (!strcmp(name, "p")) { | 135 | } else if (!strcmp(name, "p")) { |
132 | ctx.qry.page = xstrdup(value); | 136 | ctx.qry.page = xstrdup(value); |
133 | } else if (!strcmp(name, "url")) { | 137 | } else if (!strcmp(name, "url")) { |
134 | ctx.qry.url = xstrdup(value); | 138 | ctx.qry.url = xstrdup(value); |
135 | cgit_parse_url(value); | 139 | cgit_parse_url(value); |
136 | } else if (!strcmp(name, "qt")) { | 140 | } else if (!strcmp(name, "qt")) { |
137 | ctx.qry.grep = xstrdup(value); | 141 | ctx.qry.grep = xstrdup(value); |
138 | } else if (!strcmp(name, "q")) { | 142 | } else if (!strcmp(name, "q")) { |
139 | ctx.qry.search = xstrdup(value); | 143 | ctx.qry.search = xstrdup(value); |
140 | } else if (!strcmp(name, "h")) { | 144 | } else if (!strcmp(name, "h")) { |
141 | ctx.qry.head = xstrdup(value); | 145 | ctx.qry.head = xstrdup(value); |
142 | ctx.qry.has_symref = 1; | 146 | ctx.qry.has_symref = 1; |
143 | } else if (!strcmp(name, "id")) { | 147 | } else if (!strcmp(name, "id")) { |
144 | ctx.qry.sha1 = xstrdup(value); | 148 | ctx.qry.sha1 = xstrdup(value); |
145 | ctx.qry.has_sha1 = 1; | 149 | ctx.qry.has_sha1 = 1; |
146 | } else if (!strcmp(name, "id2")) { | 150 | } else if (!strcmp(name, "id2")) { |
147 | ctx.qry.sha2 = xstrdup(value); | 151 | ctx.qry.sha2 = xstrdup(value); |
148 | ctx.qry.has_sha1 = 1; | 152 | ctx.qry.has_sha1 = 1; |
149 | } else if (!strcmp(name, "ofs")) { | 153 | } else if (!strcmp(name, "ofs")) { |
150 | ctx.qry.ofs = atoi(value); | 154 | ctx.qry.ofs = atoi(value); |
151 | } else if (!strcmp(name, "path")) { | 155 | } else if (!strcmp(name, "path")) { |
152 | ctx.qry.path = trim_end(value, '/'); | 156 | ctx.qry.path = trim_end(value, '/'); |
153 | } else if (!strcmp(name, "name")) { | 157 | } else if (!strcmp(name, "name")) { |
154 | ctx.qry.name = xstrdup(value); | 158 | ctx.qry.name = xstrdup(value); |
155 | } else if (!strcmp(name, "mimetype")) { | 159 | } else if (!strcmp(name, "mimetype")) { |
156 | ctx.qry.mimetype = xstrdup(value); | 160 | ctx.qry.mimetype = xstrdup(value); |
161 | } else if (!strcmp(name, "period")) { | ||
162 | ctx.qry.period = xstrdup(value); | ||
157 | } | 163 | } |
158 | } | 164 | } |
159 | 165 | ||
160 | static void prepare_context(struct cgit_context *ctx) | 166 | static void prepare_context(struct cgit_context *ctx) |
161 | { | 167 | { |
162 | memset(ctx, 0, sizeof(ctx)); | 168 | memset(ctx, 0, sizeof(ctx)); |
163 | ctx->cfg.agefile = "info/web/last-modified"; | 169 | ctx->cfg.agefile = "info/web/last-modified"; |
164 | ctx->cfg.nocache = 0; | 170 | ctx->cfg.nocache = 0; |
165 | ctx->cfg.cache_size = 0; | 171 | ctx->cfg.cache_size = 0; |
166 | ctx->cfg.cache_dynamic_ttl = 5; | 172 | ctx->cfg.cache_dynamic_ttl = 5; |
167 | ctx->cfg.cache_max_create_time = 5; | 173 | ctx->cfg.cache_max_create_time = 5; |
168 | ctx->cfg.cache_repo_ttl = 5; | 174 | ctx->cfg.cache_repo_ttl = 5; |
169 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; | 175 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; |
170 | ctx->cfg.cache_root_ttl = 5; | 176 | ctx->cfg.cache_root_ttl = 5; |
171 | ctx->cfg.cache_static_ttl = -1; | 177 | ctx->cfg.cache_static_ttl = -1; |
172 | ctx->cfg.css = "/cgit.css"; | 178 | ctx->cfg.css = "/cgit.css"; |
173 | ctx->cfg.logo = "/git-logo.png"; | 179 | ctx->cfg.logo = "/git-logo.png"; |
174 | ctx->cfg.local_time = 0; | 180 | ctx->cfg.local_time = 0; |
175 | ctx->cfg.max_repo_count = 50; | 181 | ctx->cfg.max_repo_count = 50; |
176 | ctx->cfg.max_commit_count = 50; | 182 | ctx->cfg.max_commit_count = 50; |
177 | ctx->cfg.max_lock_attempts = 5; | 183 | ctx->cfg.max_lock_attempts = 5; |
178 | ctx->cfg.max_msg_len = 80; | 184 | ctx->cfg.max_msg_len = 80; |
179 | ctx->cfg.max_repodesc_len = 80; | 185 | ctx->cfg.max_repodesc_len = 80; |
180 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; | 186 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; |
181 | ctx->cfg.renamelimit = -1; | 187 | ctx->cfg.renamelimit = -1; |
182 | ctx->cfg.robots = "index, nofollow"; | 188 | ctx->cfg.robots = "index, nofollow"; |
183 | ctx->cfg.root_title = "Git repository browser"; | 189 | ctx->cfg.root_title = "Git repository browser"; |
184 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; | 190 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; |
185 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; | 191 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; |
186 | ctx->cfg.summary_branches = 10; | 192 | ctx->cfg.summary_branches = 10; |
187 | ctx->cfg.summary_log = 10; | 193 | ctx->cfg.summary_log = 10; |
188 | ctx->cfg.summary_tags = 10; | 194 | ctx->cfg.summary_tags = 10; |
189 | ctx->page.mimetype = "text/html"; | 195 | ctx->page.mimetype = "text/html"; |
190 | ctx->page.charset = PAGE_ENCODING; | 196 | ctx->page.charset = PAGE_ENCODING; |
191 | ctx->page.filename = NULL; | 197 | ctx->page.filename = NULL; |
192 | ctx->page.size = 0; | 198 | ctx->page.size = 0; |
193 | ctx->page.modified = time(NULL); | 199 | ctx->page.modified = time(NULL); |
194 | ctx->page.expires = ctx->page.modified; | 200 | ctx->page.expires = ctx->page.modified; |
195 | } | 201 | } |
196 | 202 | ||
197 | struct refmatch { | 203 | struct refmatch { |
198 | char *req_ref; | 204 | char *req_ref; |
199 | char *first_ref; | 205 | char *first_ref; |
200 | int match; | 206 | int match; |
201 | }; | 207 | }; |
202 | 208 | ||
203 | int find_current_ref(const char *refname, const unsigned char *sha1, | 209 | int find_current_ref(const char *refname, const unsigned char *sha1, |
204 | int flags, void *cb_data) | 210 | int flags, void *cb_data) |