rework code, "cache" commit data in struct commitinfo
1 files changed, 175 insertions(+), 178 deletions(-) | |||
---|---|---|---|
M | urmoms.c | +175 | -178 |
1@@ -11,6 +11,28 @@
2
3 #include "git2.h"
4
5+struct commitinfo {
6+ const git_oid *id;
7+
8+ char oid[GIT_OID_HEXSZ + 1];
9+ char parentoid[GIT_OID_HEXSZ + 1];
10+
11+ const git_signature *author;
12+ const char *summary;
13+ const char *msg;
14+
15+ git_diff_stats *stats;
16+ git_diff *diff;
17+ git_commit *commit;
18+ git_commit *parent;
19+ git_tree *commit_tree;
20+ git_tree *parent_tree;
21+
22+ size_t addcount;
23+ size_t delcount;
24+ size_t filecount;
25+};
26+
27 static git_repository *repo;
28
29 static const char *relpath = "";
30@@ -20,6 +42,69 @@ static char name[255];
31 static char description[255];
32 static int hasreadme, haslicense;
33
34+void
35+commitinfo_free(struct commitinfo *ci)
36+{
37+ if (!ci)
38+ return;
39+
40+ /* TODO: print error ? */
41+ git_diff_stats_free(ci->stats);
42+ git_diff_free(ci->diff);
43+ git_commit_free(ci->commit);
44+}
45+
46+struct commitinfo *
47+commitinfo_getbyoid(const git_oid *id)
48+{
49+ struct commitinfo *ci;
50+ int error;
51+
52+ if (!(ci = calloc(1, sizeof(struct commitinfo))))
53+ err(1, "calloc");
54+
55+ ci->id = id;
56+ if (git_commit_lookup(&(ci->commit), repo, id))
57+ goto err;
58+
59+ /* TODO: show tags when commit has it */
60+ git_oid_tostr(ci->oid, sizeof(ci->oid), git_commit_id(ci->commit));
61+ git_oid_tostr(ci->parentoid, sizeof(ci->parentoid), git_commit_parent_id(ci->commit, 0));
62+
63+ ci->author = git_commit_author(ci->commit);
64+ ci->summary = git_commit_summary(ci->commit);
65+ ci->msg = git_commit_message(ci->commit);
66+
67+ if ((error = git_commit_tree(&(ci->commit_tree), ci->commit)))
68+ goto err; /* TODO: handle error */
69+ if (!(error = git_commit_parent(&(ci->parent), ci->commit, 0))) {
70+ if ((error = git_commit_tree(&(ci->parent_tree), ci->parent)))
71+ goto err;
72+ } else {
73+ ci->parent = NULL;
74+ ci->parent_tree = NULL;
75+ }
76+
77+ if ((error = git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, NULL)))
78+ goto err;
79+ if (git_diff_get_stats(&(ci->stats), ci->diff))
80+ goto err;
81+
82+ ci->addcount = git_diff_stats_insertions(ci->stats);
83+ ci->delcount = git_diff_stats_deletions(ci->stats);
84+ ci->filecount = git_diff_stats_files_changed(ci->stats);
85+
86+ /* TODO: show tag when commit has it */
87+
88+ return ci;
89+
90+err:
91+ commitinfo_free(ci);
92+ free(ci);
93+
94+ return NULL;
95+}
96+
97 int
98 writeheader(FILE *fp)
99 {
100@@ -156,22 +241,23 @@ printtime(FILE *fp, const git_time *intime)
101 }
102
103 void
104-printcommit(FILE *fp, git_commit *commit)
105+writeblobhtml(FILE *fp, const git_blob *blob)
106 {
107- const git_signature *sig;
108- char buf[GIT_OID_HEXSZ + 1];
109- int i, count;
110- const char *msg;
111+ xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob));
112+}
113
114+void
115+printcommit(FILE *fp, struct commitinfo *ci)
116+{
117 /* TODO: show tag when commit has it */
118- git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
119 fprintf(fp, "<b>commit</b> <a href=\"%scommit/%s.html\">%s</a>\n",
120- relpath, buf, buf);
121+ relpath, ci->oid, ci->oid);
122
123- if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0)) && buf[0])
124+ if (ci->parentoid[0])
125 fprintf(fp, "<b>parent</b> <a href=\"%scommit/%s.html\">%s</a>\n",
126- relpath, buf, buf);
127+ relpath, ci->parentoid, ci->parentoid);
128
129+#if 0
130 if ((count = (int)git_commit_parentcount(commit)) > 1) {
131 fprintf(fp, "<b>Merge:</b>");
132 for (i = 0; i < count; i++) {
133@@ -181,81 +267,66 @@ printcommit(FILE *fp, git_commit *commit)
134 }
135 fputc('\n', fp);
136 }
137- if ((sig = git_commit_author(commit)) != NULL) {
138+#endif
139+ if (ci->author) {
140 fprintf(fp, "<b>Author:</b> ");
141- xmlencode(fp, sig->name, strlen(sig->name));
142+ xmlencode(fp, ci->author->name, strlen(ci->author->name));
143 fprintf(fp, " <<a href=\"mailto:");
144- xmlencode(fp, sig->email, strlen(sig->email));
145+ xmlencode(fp, ci->author->email, strlen(ci->author->email));
146 fputs("\">", fp);
147- xmlencode(fp, sig->email, strlen(sig->email));
148+ xmlencode(fp, ci->author->email, strlen(ci->author->email));
149 fputs("</a>>\n<b>Date:</b> ", fp);
150- printtime(fp, &sig->when);
151+ printtime(fp, &(ci->author->when));
152 fputc('\n', fp);
153 }
154 fputc('\n', fp);
155
156- if ((msg = git_commit_message(commit)))
157- xmlencode(fp, msg, strlen(msg));
158+ if (ci->msg)
159+ xmlencode(fp, ci->msg, strlen(ci->msg));
160+
161 fputc('\n', fp);
162 }
163
164 void
165-printshowfile(git_commit *commit)
166+printshowfile(struct commitinfo *ci)
167 {
168- const git_diff_delta *delta = NULL;
169- const git_diff_hunk *hunk = NULL;
170- const git_diff_line *line = NULL;
171- git_commit *parent = NULL;
172- git_tree *commit_tree = NULL, *parent_tree = NULL;
173- git_patch *patch = NULL;
174- git_diff *diff = NULL;
175- git_diff_stats *diffstats = NULL;
176- git_buf diffstatsbuf;
177+ const git_diff_delta *delta;
178+ const git_diff_hunk *hunk;
179+ const git_diff_line *line;
180+ git_patch *patch;
181+ git_buf statsbuf;
182+ size_t ndeltas, nhunks, nhunklines;
183 FILE *fp;
184- size_t i, j, k, ndeltas, nhunks = 0, nhunklines = 0;
185- char buf[GIT_OID_HEXSZ + 1], path[PATH_MAX];
186- int error;
187+ size_t i, j, k;
188+ char path[PATH_MAX];
189
190- git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
191- if (!buf[0])
192- return;
193- snprintf(path, sizeof(path), "commit/%s.html", buf);
194+ snprintf(path, sizeof(path), "commit/%s.html", ci->oid);
195 /* check if file exists if so skip it */
196 if (!access(path, F_OK))
197 return;
198
199- memset(&diffstatsbuf, 0, sizeof(diffstatsbuf));
200-
201 fp = efopen(path, "w+b");
202 writeheader(fp);
203- printcommit(fp, commit);
204+ printcommit(fp, ci);
205
206- if ((error = git_commit_tree(&commit_tree, commit)))
207- goto err;
208- if (!(error = git_commit_parent(&parent, commit, 0))) {
209- if ((error = git_commit_tree(&parent_tree, parent)))
210- goto err; /* TODO: handle error */
211- } else {
212- parent = NULL;
213- parent_tree = NULL;
214- }
215- if ((error = git_diff_tree_to_tree(&diff, repo, parent_tree, commit_tree, NULL)))
216- goto err;
217+ memset(&statsbuf, 0, sizeof(statsbuf));
218
219 /* diff stat */
220- if (!git_diff_get_stats(&diffstats, diff)) {
221- if (!git_diff_stats_to_buf(&diffstatsbuf, diffstats,
222+ if (ci->stats) {
223+ if (!git_diff_stats_to_buf(&statsbuf, ci->stats,
224 GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_SHORT, 80)) {
225- fprintf(fp, "<b>Diffstat:</b>\n");
226- fputs(diffstatsbuf.ptr, fp);
227+ if (statsbuf.ptr && statsbuf.ptr[0]) {
228+ fprintf(fp, "<b>Diffstat:</b>\n");
229+ fputs(statsbuf.ptr, fp);
230+ }
231 }
232- git_diff_stats_free(diffstats);
233 }
234+
235 fputs("<hr/>", fp);
236
237- ndeltas = git_diff_num_deltas(diff);
238+ ndeltas = git_diff_num_deltas(ci->diff);
239 for (i = 0; i < ndeltas; i++) {
240- if (git_patch_from_diff(&patch, diff, i)) {
241+ if (git_patch_from_diff(&patch, ci->diff, i)) {
242 git_patch_free(patch);
243 break; /* TODO: handle error */
244 }
245@@ -265,26 +336,6 @@ printshowfile(git_commit *commit)
246 relpath, delta->old_file.path, delta->old_file.path,
247 relpath, delta->new_file.path, delta->new_file.path);
248
249- /* TODO: "new file mode <mode>". */
250- /* TODO: add indexfrom...indexto + flags */
251-
252-#if 0
253- fputs("<b>--- ", fp);
254- if (delta->status & GIT_DELTA_ADDED)
255- fputs("/dev/null", fp);
256- else
257- fprintf(fp, "a/<a href=\"%sfile/%s\">%s</a>",
258- relpath, delta->old_file.path, delta->old_file.path);
259-
260- fputs("\n+++ ", fp);
261- if (delta->status & GIT_DELTA_DELETED)
262- fputs("/dev/null", fp);
263- else
264- fprintf(fp, "b/<a href=\"%sfile/%s\">%s</a>",
265- relpath, delta->new_file.path, delta->new_file.path);
266- fputs("</b>\n", fp);
267-#endif
268-
269 /* check binary data */
270 if (delta->flags & GIT_DIFF_FLAG_BINARY) {
271 fputs("Binary files differ\n", fp);
272@@ -317,32 +368,20 @@ printshowfile(git_commit *commit)
273 }
274 git_patch_free(patch);
275 }
276- git_diff_free(diff);
277+ git_buf_free(&statsbuf);
278
279 writefooter(fp);
280 fclose(fp);
281 return;
282-
283-err:
284- git_buf_free(&diffstatsbuf);
285- fclose(fp);
286 }
287
288 int
289 writelog(FILE *fp)
290 {
291+ struct commitinfo *ci;
292 git_revwalk *w = NULL;
293 git_oid id;
294- git_commit *commit = NULL;
295- const git_signature *author;
296- git_diff_stats *stats = NULL;
297- git_tree *commit_tree = NULL, *parent_tree = NULL;
298- git_commit *parent = NULL;
299- git_diff *diff = NULL;
300- size_t nfiles, ndel, nadd;
301- const char *summary;
302- char buf[GIT_OID_HEXSZ + 1];
303- int error, ret = 0;
304+ int ret = 0;
305
306 mkdir("commit", 0755);
307
308@@ -355,67 +394,37 @@ writelog(FILE *fp)
309 while (!git_revwalk_next(&id, w)) {
310 relpath = "";
311
312- if (git_commit_lookup(&commit, repo, &id)) {
313- ret = 1;
314- goto err;
315- }
316- if ((error = git_commit_tree(&commit_tree, commit)))
317- goto errdiff; /* TODO: handle error */
318- if (!(error = git_commit_parent(&parent, commit, 0))) {
319- if ((error = git_commit_tree(&parent_tree, parent)))
320- goto errdiff;
321- } else {
322- parent = NULL;
323- parent_tree = NULL;
324- }
325-
326- if ((error = git_diff_tree_to_tree(&diff, repo, parent_tree, commit_tree, NULL)))
327- goto errdiff;
328- if (git_diff_get_stats(&stats, diff))
329- goto errdiff;
330-
331- git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
332-
333- ndel = git_diff_stats_deletions(stats);
334- nadd = git_diff_stats_insertions(stats);
335- nfiles = git_diff_stats_files_changed(stats);
336-
337- /* TODO: show tag when commit has it */
338-
339- /* TODO: collect stats per author and make stats.html page */
340- author = git_commit_author(commit);
341- summary = git_commit_summary(commit);
342+ if (!(ci = commitinfo_getbyoid(&id)))
343+ break;
344
345 fputs("<tr><td>", fp);
346- if (summary) {
347- fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, buf);
348- xmlencode(fp, summary, strlen(summary));
349+ if (ci->summary) {
350+ fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
351+ xmlencode(fp, ci->summary, strlen(ci->summary));
352 fputs("</a>", fp);
353 }
354 fputs("</td><td>", fp);
355- if (author)
356- xmlencode(fp, author->name, strlen(author->name));
357+ if (ci->author)
358+ xmlencode(fp, ci->author->name, strlen(ci->author->name));
359+
360 fputs("</td><td align=\"right\">", fp);
361- printtime(fp, &author->when);
362+ if (ci->author)
363+ printtime(fp, &(ci->author->when));
364 fputs("</td><td align=\"right\">", fp);
365- fprintf(fp, "%zu", nfiles);
366+ fprintf(fp, "%zu", ci->filecount);
367 fputs("</td><td align=\"right\">", fp);
368- fprintf(fp, "+%zu", nadd);
369+ fprintf(fp, "+%zu", ci->addcount);
370 fputs("</td><td align=\"right\">", fp);
371- fprintf(fp, "-%zu", ndel);
372+ fprintf(fp, "-%zu", ci->delcount);
373 fputs("</td></tr>\n", fp);
374
375 relpath = "../";
376- printshowfile(commit);
377+ printshowfile(ci);
378
379-errdiff:
380- /* TODO: print error ? */
381- git_diff_stats_free(stats);
382- git_diff_free(diff);
383- git_commit_free(commit);
384+ commitinfo_free(ci);
385 }
386 fprintf(fp, "</tbody></table>");
387-err:
388+
389 git_revwalk_free(w);
390 relpath = "";
391
392@@ -423,38 +432,28 @@ err:
393 }
394
395 void
396-printcommitatom(FILE *fp, git_commit *commit)
397+printcommitatom(FILE *fp, struct commitinfo *ci)
398 {
399- const git_signature *sig;
400- char buf[GIT_OID_HEXSZ + 1];
401- int i, count;
402- const char *msg, *summary;
403-
404 fputs("<entry>\n", fp);
405
406- /* TODO: show tag when commit has it */
407- git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
408- fprintf(fp, "<id>%s</id>\n", buf);
409-
410- sig = git_commit_author(commit);
411-
412- if (sig) {
413+ fprintf(fp, "<id>%s</id>\n", ci->oid);
414+ if (ci->author) {
415 fputs("<updated>", fp);
416- printtimez(fp, &sig->when);
417+ printtimez(fp, &(ci->author->when));
418 fputs("</updated>\n", fp);
419 }
420-
421- if ((summary = git_commit_summary(commit))) {
422+ if (ci->summary) {
423 fputs("<title type=\"text\">", fp);
424- xmlencode(fp, summary, strlen(summary));
425+ xmlencode(fp, ci->summary, strlen(ci->summary));
426 fputs("</title>\n", fp);
427 }
428
429 fputs("<content type=\"text\">", fp);
430- fprintf(fp, "commit %s\n", buf);
431- if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0)) && buf[0])
432- fprintf(fp, "parent %s\n", buf);
433+ fprintf(fp, "commit %s\n", ci->oid);
434+ if (ci->parentoid[0])
435+ fprintf(fp, "parent %s\n", ci->parentoid);
436
437+#if 0
438 if ((count = (int)git_commit_parentcount(commit)) > 1) {
439 fprintf(fp, "Merge:");
440 for (i = 0; i < count; i++) {
441@@ -463,25 +462,26 @@ printcommitatom(FILE *fp, git_commit *commit)
442 }
443 fputc('\n', fp);
444 }
445+#endif
446
447- if (sig) {
448+ if (ci->author) {
449 fprintf(fp, "Author: ");
450- xmlencode(fp, sig->name, strlen(sig->name));
451+ xmlencode(fp, ci->author->name, strlen(ci->author->name));
452 fprintf(fp, " <");
453- xmlencode(fp, sig->email, strlen(sig->email));
454+ xmlencode(fp, ci->author->email, strlen(ci->author->email));
455 fprintf(fp, ">\nDate: ");
456- printtime(fp, &sig->when);
457+ printtime(fp, &(ci->author->when));
458 }
459 fputc('\n', fp);
460
461- if ((msg = git_commit_message(commit)))
462- xmlencode(fp, msg, strlen(msg));
463+ if (ci->msg)
464+ xmlencode(fp, ci->msg, strlen(ci->msg));
465 fputs("\n</content>\n", fp);
466- if (sig) {
467+ if (ci->author) {
468 fputs("<author><name>", fp);
469- xmlencode(fp, sig->name, strlen(sig->name));
470+ xmlencode(fp, ci->author->name, strlen(ci->author->name));
471 fputs("</name>\n<email>", fp);
472- xmlencode(fp, sig->email, strlen(sig->email));
473+ xmlencode(fp, ci->author->email, strlen(ci->author->email));
474 fputs("</email>\n</author>\n", fp);
475 }
476 fputs("</entry>\n", fp);
477@@ -490,9 +490,9 @@ printcommitatom(FILE *fp, git_commit *commit)
478 int
479 writeatom(FILE *fp)
480 {
481+ struct commitinfo *ci;
482 git_revwalk *w = NULL;
483 git_oid id;
484- git_commit *c = NULL;
485 size_t i, m = 100; /* max */
486
487 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp);
488@@ -507,10 +507,10 @@ writeatom(FILE *fp)
489 git_revwalk_push_head(w);
490
491 for (i = 0; i < m && !git_revwalk_next(&id, w); i++) {
492- if (git_commit_lookup(&c, repo, &id))
493- return 1; /* TODO: error */
494- printcommitatom(fp, c);
495- git_commit_free(c);
496+ if (!(ci = commitinfo_getbyoid(&id)))
497+ break;
498+ printcommitatom(fp, ci);
499+ commitinfo_free(ci);
500 }
501 git_revwalk_free(w);
502
503@@ -522,14 +522,16 @@ writeatom(FILE *fp)
504 int
505 writefiles(FILE *fp)
506 {
507- git_index *index;
508 const git_index_entry *entry;
509+ git_index *index;
510 size_t count, i;
511
512- git_repository_index(&index, repo);
513+ fputs("<table><thead>\n"
514+ "<tr><td>Mode</td><td>Name</td><td align=\"right\">Size</td></tr>\n"
515+ "</thead><tbody>\n", fp);
516
517+ git_repository_index(&index, repo);
518 count = git_index_entrycount(index);
519- fputs("<table><thead>\n<tr><td>Mode</td><td>Name</td><td align=\"right\">Size</td></tr>\n</thead><tbody>\n", fp);
520
521 for (i = 0; i < count; i++) {
522 entry = git_index_get_byindex(index, i);
523@@ -543,17 +545,12 @@ writefiles(FILE *fp)
524 fprintf(fp, "%" PRIu64, entry->file_size);
525 fputs("</td></tr>\n", fp);
526 }
527+
528 fputs("</tbody></table>", fp);
529
530 return 0;
531 }
532
533-void
534-writeblobhtml(FILE *fp, const git_blob *blob)
535-{
536- xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob));
537-}
538-
539 int
540 main(int argc, char *argv[])
541 {