stagit

rework code, "cache" commit data in struct commitinfo

Hiltjo Posthuma contact@arjunchoudhary.com

commit: 64d5e62 parent: 454b415
1 files changed, 175 insertions(+), 178 deletions(-)
Murmoms.c+175-178
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, " &lt;<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>&gt;\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, " &lt;");
453-		xmlencode(fp, sig->email, strlen(sig->email));
454+		xmlencode(fp, ci->author->email, strlen(ci->author->email));
455 		fprintf(fp, "&gt;\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 {