summaryrefslogtreecommitdiffabout
path: root/shared.c
authorLars Hjemli <hjemli@gmail.com>2008-12-06 16:38:19 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2008-12-06 16:38:19 (UTC)
commitf86a23ff537258d36bf8f1876fa7a4bede6673d8 (patch) (unidiff)
tree8328d415416058cdc5b0fd2c6564ddcab5766c7a /shared.c
parent140012d7a8e51df5a9f9c556696778b86ade4fc9 (diff)
downloadcgit-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>
Diffstat (limited to 'shared.c') (more/less context) (ignore whitespace changes)
-rw-r--r--shared.c1
1 files changed, 1 insertions, 0 deletions
diff --git a/shared.c b/shared.c
index f5875e4..37333f0 100644
--- a/shared.c
+++ b/shared.c
@@ -1,344 +1,345 @@
1/* shared.c: global vars + some callback functions 1/* shared.c: global vars + some callback functions
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10 10
11struct cgit_repolist cgit_repolist; 11struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 12struct cgit_context ctx;
13int cgit_cmd; 13int cgit_cmd;
14 14
15int chk_zero(int result, char *msg) 15int chk_zero(int result, char *msg)
16{ 16{
17 if (result != 0) 17 if (result != 0)
18 die("%s: %s", msg, strerror(errno)); 18 die("%s: %s", msg, strerror(errno));
19 return result; 19 return result;
20} 20}
21 21
22int chk_positive(int result, char *msg) 22int chk_positive(int result, char *msg)
23{ 23{
24 if (result <= 0) 24 if (result <= 0)
25 die("%s: %s", msg, strerror(errno)); 25 die("%s: %s", msg, strerror(errno));
26 return result; 26 return result;
27} 27}
28 28
29int chk_non_negative(int result, char *msg) 29int chk_non_negative(int result, char *msg)
30{ 30{
31 if (result < 0) 31 if (result < 0)
32 die("%s: %s",msg, strerror(errno)); 32 die("%s: %s",msg, strerror(errno));
33 return result; 33 return result;
34} 34}
35 35
36struct cgit_repo *cgit_add_repo(const char *url) 36struct cgit_repo *cgit_add_repo(const char *url)
37{ 37{
38 struct cgit_repo *ret; 38 struct cgit_repo *ret;
39 39
40 if (++cgit_repolist.count > cgit_repolist.length) { 40 if (++cgit_repolist.count > cgit_repolist.length) {
41 if (cgit_repolist.length == 0) 41 if (cgit_repolist.length == 0)
42 cgit_repolist.length = 8; 42 cgit_repolist.length = 8;
43 else 43 else
44 cgit_repolist.length *= 2; 44 cgit_repolist.length *= 2;
45 cgit_repolist.repos = xrealloc(cgit_repolist.repos, 45 cgit_repolist.repos = xrealloc(cgit_repolist.repos,
46 cgit_repolist.length * 46 cgit_repolist.length *
47 sizeof(struct cgit_repo)); 47 sizeof(struct cgit_repo));
48 } 48 }
49 49
50 ret = &cgit_repolist.repos[cgit_repolist.count-1]; 50 ret = &cgit_repolist.repos[cgit_repolist.count-1];
51 ret->url = trim_end(url, '/'); 51 ret->url = trim_end(url, '/');
52 ret->name = ret->url; 52 ret->name = ret->url;
53 ret->path = NULL; 53 ret->path = NULL;
54 ret->desc = "[no description]"; 54 ret->desc = "[no description]";
55 ret->owner = NULL; 55 ret->owner = NULL;
56 ret->group = ctx.cfg.repo_group; 56 ret->group = ctx.cfg.repo_group;
57 ret->defbranch = "master"; 57 ret->defbranch = "master";
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->enable_stats = ctx.cfg.enable_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 return ret; 64 return ret;
64} 65}
65 66
66struct cgit_repo *cgit_get_repoinfo(const char *url) 67struct cgit_repo *cgit_get_repoinfo(const char *url)
67{ 68{
68 int i; 69 int i;
69 struct cgit_repo *repo; 70 struct cgit_repo *repo;
70 71
71 for (i=0; i<cgit_repolist.count; i++) { 72 for (i=0; i<cgit_repolist.count; i++) {
72 repo = &cgit_repolist.repos[i]; 73 repo = &cgit_repolist.repos[i];
73 if (!strcmp(repo->url, url)) 74 if (!strcmp(repo->url, url))
74 return repo; 75 return repo;
75 } 76 }
76 return NULL; 77 return NULL;
77} 78}
78 79
79void *cgit_free_commitinfo(struct commitinfo *info) 80void *cgit_free_commitinfo(struct commitinfo *info)
80{ 81{
81 free(info->author); 82 free(info->author);
82 free(info->author_email); 83 free(info->author_email);
83 free(info->committer); 84 free(info->committer);
84 free(info->committer_email); 85 free(info->committer_email);
85 free(info->subject); 86 free(info->subject);
86 free(info->msg); 87 free(info->msg);
87 free(info->msg_encoding); 88 free(info->msg_encoding);
88 free(info); 89 free(info);
89 return NULL; 90 return NULL;
90} 91}
91 92
92char *trim_end(const char *str, char c) 93char *trim_end(const char *str, char c)
93{ 94{
94 int len; 95 int len;
95 char *s, *t; 96 char *s, *t;
96 97
97 if (str == NULL) 98 if (str == NULL)
98 return NULL; 99 return NULL;
99 t = (char *)str; 100 t = (char *)str;
100 len = strlen(t); 101 len = strlen(t);
101 while(len > 0 && t[len - 1] == c) 102 while(len > 0 && t[len - 1] == c)
102 len--; 103 len--;
103 104
104 if (len == 0) 105 if (len == 0)
105 return NULL; 106 return NULL;
106 107
107 c = t[len]; 108 c = t[len];
108 t[len] = '\0'; 109 t[len] = '\0';
109 s = xstrdup(t); 110 s = xstrdup(t);
110 t[len] = c; 111 t[len] = c;
111 return s; 112 return s;
112} 113}
113 114
114char *strlpart(char *txt, int maxlen) 115char *strlpart(char *txt, int maxlen)
115{ 116{
116 char *result; 117 char *result;
117 118
118 if (!txt) 119 if (!txt)
119 return txt; 120 return txt;
120 121
121 if (strlen(txt) <= maxlen) 122 if (strlen(txt) <= maxlen)
122 return txt; 123 return txt;
123 result = xmalloc(maxlen + 1); 124 result = xmalloc(maxlen + 1);
124 memcpy(result, txt, maxlen - 3); 125 memcpy(result, txt, maxlen - 3);
125 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.'; 126 result[maxlen-1] = result[maxlen-2] = result[maxlen-3] = '.';
126 result[maxlen] = '\0'; 127 result[maxlen] = '\0';
127 return result; 128 return result;
128} 129}
129 130
130char *strrpart(char *txt, int maxlen) 131char *strrpart(char *txt, int maxlen)
131{ 132{
132 char *result; 133 char *result;
133 134
134 if (!txt) 135 if (!txt)
135 return txt; 136 return txt;
136 137
137 if (strlen(txt) <= maxlen) 138 if (strlen(txt) <= maxlen)
138 return txt; 139 return txt;
139 result = xmalloc(maxlen + 1); 140 result = xmalloc(maxlen + 1);
140 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3); 141 memcpy(result + 3, txt + strlen(txt) - maxlen + 4, maxlen - 3);
141 result[0] = result[1] = result[2] = '.'; 142 result[0] = result[1] = result[2] = '.';
142 return result; 143 return result;
143} 144}
144 145
145void cgit_add_ref(struct reflist *list, struct refinfo *ref) 146void cgit_add_ref(struct reflist *list, struct refinfo *ref)
146{ 147{
147 size_t size; 148 size_t size;
148 149
149 if (list->count >= list->alloc) { 150 if (list->count >= list->alloc) {
150 list->alloc += (list->alloc ? list->alloc : 4); 151 list->alloc += (list->alloc ? list->alloc : 4);
151 size = list->alloc * sizeof(struct refinfo *); 152 size = list->alloc * sizeof(struct refinfo *);
152 list->refs = xrealloc(list->refs, size); 153 list->refs = xrealloc(list->refs, size);
153 } 154 }
154 list->refs[list->count++] = ref; 155 list->refs[list->count++] = ref;
155} 156}
156 157
157struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1) 158struct refinfo *cgit_mk_refinfo(const char *refname, const unsigned char *sha1)
158{ 159{
159 struct refinfo *ref; 160 struct refinfo *ref;
160 161
161 ref = xmalloc(sizeof (struct refinfo)); 162 ref = xmalloc(sizeof (struct refinfo));
162 ref->refname = xstrdup(refname); 163 ref->refname = xstrdup(refname);
163 ref->object = parse_object(sha1); 164 ref->object = parse_object(sha1);
164 switch (ref->object->type) { 165 switch (ref->object->type) {
165 case OBJ_TAG: 166 case OBJ_TAG:
166 ref->tag = cgit_parse_tag((struct tag *)ref->object); 167 ref->tag = cgit_parse_tag((struct tag *)ref->object);
167 break; 168 break;
168 case OBJ_COMMIT: 169 case OBJ_COMMIT:
169 ref->commit = cgit_parse_commit((struct commit *)ref->object); 170 ref->commit = cgit_parse_commit((struct commit *)ref->object);
170 break; 171 break;
171 } 172 }
172 return ref; 173 return ref;
173} 174}
174 175
175int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags, 176int cgit_refs_cb(const char *refname, const unsigned char *sha1, int flags,
176 void *cb_data) 177 void *cb_data)
177{ 178{
178 struct reflist *list = (struct reflist *)cb_data; 179 struct reflist *list = (struct reflist *)cb_data;
179 struct refinfo *info = cgit_mk_refinfo(refname, sha1); 180 struct refinfo *info = cgit_mk_refinfo(refname, sha1);
180 181
181 if (info) 182 if (info)
182 cgit_add_ref(list, info); 183 cgit_add_ref(list, info);
183 return 0; 184 return 0;
184} 185}
185 186
186void cgit_diff_tree_cb(struct diff_queue_struct *q, 187void cgit_diff_tree_cb(struct diff_queue_struct *q,
187 struct diff_options *options, void *data) 188 struct diff_options *options, void *data)
188{ 189{
189 int i; 190 int i;
190 191
191 for (i = 0; i < q->nr; i++) { 192 for (i = 0; i < q->nr; i++) {
192 if (q->queue[i]->status == 'U') 193 if (q->queue[i]->status == 'U')
193 continue; 194 continue;
194 ((filepair_fn)data)(q->queue[i]); 195 ((filepair_fn)data)(q->queue[i]);
195 } 196 }
196} 197}
197 198
198static int load_mmfile(mmfile_t *file, const unsigned char *sha1) 199static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
199{ 200{
200 enum object_type type; 201 enum object_type type;
201 202
202 if (is_null_sha1(sha1)) { 203 if (is_null_sha1(sha1)) {
203 file->ptr = (char *)""; 204 file->ptr = (char *)"";
204 file->size = 0; 205 file->size = 0;
205 } else { 206 } else {
206 file->ptr = read_sha1_file(sha1, &type, 207 file->ptr = read_sha1_file(sha1, &type,
207 (unsigned long *)&file->size); 208 (unsigned long *)&file->size);
208 } 209 }
209 return 1; 210 return 1;
210} 211}
211 212
212/* 213/*
213 * Receive diff-buffers from xdiff and concatenate them as 214 * Receive diff-buffers from xdiff and concatenate them as
214 * needed across multiple callbacks. 215 * needed across multiple callbacks.
215 * 216 *
216 * This is basically a copy of xdiff-interface.c/xdiff_outf(), 217 * This is basically a copy of xdiff-interface.c/xdiff_outf(),
217 * ripped from git and modified to use globals instead of 218 * ripped from git and modified to use globals instead of
218 * a special callback-struct. 219 * a special callback-struct.
219 */ 220 */
220char *diffbuf = NULL; 221char *diffbuf = NULL;
221int buflen = 0; 222int buflen = 0;
222 223
223int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) 224int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf)
224{ 225{
225 int i; 226 int i;
226 227
227 for (i = 0; i < nbuf; i++) { 228 for (i = 0; i < nbuf; i++) {
228 if (mb[i].ptr[mb[i].size-1] != '\n') { 229 if (mb[i].ptr[mb[i].size-1] != '\n') {
229 /* Incomplete line */ 230 /* Incomplete line */
230 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 231 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
231 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 232 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
232 buflen += mb[i].size; 233 buflen += mb[i].size;
233 continue; 234 continue;
234 } 235 }
235 236
236 /* we have a complete line */ 237 /* we have a complete line */
237 if (!diffbuf) { 238 if (!diffbuf) {
238 ((linediff_fn)priv)(mb[i].ptr, mb[i].size); 239 ((linediff_fn)priv)(mb[i].ptr, mb[i].size);
239 continue; 240 continue;
240 } 241 }
241 diffbuf = xrealloc(diffbuf, buflen + mb[i].size); 242 diffbuf = xrealloc(diffbuf, buflen + mb[i].size);
242 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); 243 memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size);
243 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); 244 ((linediff_fn)priv)(diffbuf, buflen + mb[i].size);
244 free(diffbuf); 245 free(diffbuf);
245 diffbuf = NULL; 246 diffbuf = NULL;
246 buflen = 0; 247 buflen = 0;
247 } 248 }
248 if (diffbuf) { 249 if (diffbuf) {
249 ((linediff_fn)priv)(diffbuf, buflen); 250 ((linediff_fn)priv)(diffbuf, buflen);
250 free(diffbuf); 251 free(diffbuf);
251 diffbuf = NULL; 252 diffbuf = NULL;
252 buflen = 0; 253 buflen = 0;
253 } 254 }
254 return 0; 255 return 0;
255} 256}
256 257
257int cgit_diff_files(const unsigned char *old_sha1, 258int cgit_diff_files(const unsigned char *old_sha1,
258 const unsigned char *new_sha1, 259 const unsigned char *new_sha1,
259 linediff_fn fn) 260 linediff_fn fn)
260{ 261{
261 mmfile_t file1, file2; 262 mmfile_t file1, file2;
262 xpparam_t diff_params; 263 xpparam_t diff_params;
263 xdemitconf_t emit_params; 264 xdemitconf_t emit_params;
264 xdemitcb_t emit_cb; 265 xdemitcb_t emit_cb;
265 266
266 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1)) 267 if (!load_mmfile(&file1, old_sha1) || !load_mmfile(&file2, new_sha1))
267 return 1; 268 return 1;
268 269
269 diff_params.flags = XDF_NEED_MINIMAL; 270 diff_params.flags = XDF_NEED_MINIMAL;
270 emit_params.ctxlen = 3; 271 emit_params.ctxlen = 3;
271 emit_params.flags = XDL_EMIT_FUNCNAMES; 272 emit_params.flags = XDL_EMIT_FUNCNAMES;
272 emit_params.find_func = NULL; 273 emit_params.find_func = NULL;
273 emit_cb.outf = filediff_cb; 274 emit_cb.outf = filediff_cb;
274 emit_cb.priv = fn; 275 emit_cb.priv = fn;
275 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); 276 xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
276 return 0; 277 return 0;
277} 278}
278 279
279void cgit_diff_tree(const unsigned char *old_sha1, 280void cgit_diff_tree(const unsigned char *old_sha1,
280 const unsigned char *new_sha1, 281 const unsigned char *new_sha1,
281 filepair_fn fn, const char *prefix) 282 filepair_fn fn, const char *prefix)
282{ 283{
283 struct diff_options opt; 284 struct diff_options opt;
284 int ret; 285 int ret;
285 int prefixlen; 286 int prefixlen;
286 287
287 diff_setup(&opt); 288 diff_setup(&opt);
288 opt.output_format = DIFF_FORMAT_CALLBACK; 289 opt.output_format = DIFF_FORMAT_CALLBACK;
289 opt.detect_rename = 1; 290 opt.detect_rename = 1;
290 opt.rename_limit = ctx.cfg.renamelimit; 291 opt.rename_limit = ctx.cfg.renamelimit;
291 DIFF_OPT_SET(&opt, RECURSIVE); 292 DIFF_OPT_SET(&opt, RECURSIVE);
292 opt.format_callback = cgit_diff_tree_cb; 293 opt.format_callback = cgit_diff_tree_cb;
293 opt.format_callback_data = fn; 294 opt.format_callback_data = fn;
294 if (prefix) { 295 if (prefix) {
295 opt.nr_paths = 1; 296 opt.nr_paths = 1;
296 opt.paths = &prefix; 297 opt.paths = &prefix;
297 prefixlen = strlen(prefix); 298 prefixlen = strlen(prefix);
298 opt.pathlens = &prefixlen; 299 opt.pathlens = &prefixlen;
299 } 300 }
300 diff_setup_done(&opt); 301 diff_setup_done(&opt);
301 302
302 if (old_sha1 && !is_null_sha1(old_sha1)) 303 if (old_sha1 && !is_null_sha1(old_sha1))
303 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); 304 ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt);
304 else 305 else
305 ret = diff_root_tree_sha1(new_sha1, "", &opt); 306 ret = diff_root_tree_sha1(new_sha1, "", &opt);
306 diffcore_std(&opt); 307 diffcore_std(&opt);
307 diff_flush(&opt); 308 diff_flush(&opt);
308} 309}
309 310
310void cgit_diff_commit(struct commit *commit, filepair_fn fn) 311void cgit_diff_commit(struct commit *commit, filepair_fn fn)
311{ 312{
312 unsigned char *old_sha1 = NULL; 313 unsigned char *old_sha1 = NULL;
313 314
314 if (commit->parents) 315 if (commit->parents)
315 old_sha1 = commit->parents->item->object.sha1; 316 old_sha1 = commit->parents->item->object.sha1;
316 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL); 317 cgit_diff_tree(old_sha1, commit->object.sha1, fn, NULL);
317} 318}
318 319
319int cgit_parse_snapshots_mask(const char *str) 320int cgit_parse_snapshots_mask(const char *str)
320{ 321{
321 const struct cgit_snapshot_format *f; 322 const struct cgit_snapshot_format *f;
322 static const char *delim = " \t,:/|;"; 323 static const char *delim = " \t,:/|;";
323 int tl, sl, rv = 0; 324 int tl, sl, rv = 0;
324 325
325 /* favor legacy setting */ 326 /* favor legacy setting */
326 if(atoi(str)) 327 if(atoi(str))
327 return 1; 328 return 1;
328 for(;;) { 329 for(;;) {
329 str += strspn(str,delim); 330 str += strspn(str,delim);
330 tl = strcspn(str,delim); 331 tl = strcspn(str,delim);
331 if (!tl) 332 if (!tl)
332 break; 333 break;
333 for (f = cgit_snapshot_formats; f->suffix; f++) { 334 for (f = cgit_snapshot_formats; f->suffix; f++) {
334 sl = strlen(f->suffix); 335 sl = strlen(f->suffix);
335 if((tl == sl && !strncmp(f->suffix, str, tl)) || 336 if((tl == sl && !strncmp(f->suffix, str, tl)) ||
336 (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) { 337 (tl == sl-1 && !strncmp(f->suffix+1, str, tl-1))) {
337 rv |= f->bit; 338 rv |= f->bit;
338 break; 339 break;
339 } 340 }
340 } 341 }
341 str += tl; 342 str += tl;
342 } 343 }
343 return rv; 344 return rv;
344} 345}