stagit-gopher

static git page generator for gopher
git clone git://git.2f30.org/stagit-gopher.git
Log | Files | Refs | README | LICENSE

commit 9c1862ccdacddee9b8a324a8d4a67d18c5ab7d93
parent 1b4f30ba2e66133139f225cb536ba2c6ed62ff36
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Mon Dec  7 23:00:07 +0100

rework code, "cache" commit data in struct commitinfo

Diffstat:
urmoms.c | 353+++++++++++++++++++++++++++++++++++++++----------------------------------------
1 file changed, 175 insertions(+), 178 deletions(-)
diff --git a/urmoms.c b/urmoms.c @@ -11,6 +11,28 @@ #include "git2.h" +struct commitinfo { + const git_oid *id; + + char oid[GIT_OID_HEXSZ + 1]; + char parentoid[GIT_OID_HEXSZ + 1]; + + const git_signature *author; + const char *summary; + const char *msg; + + git_diff_stats *stats; + git_diff *diff; + git_commit *commit; + git_commit *parent; + git_tree *commit_tree; + git_tree *parent_tree; + + size_t addcount; + size_t delcount; + size_t filecount; +}; + static git_repository *repo; static const char *relpath = ""; @@ -20,6 +42,69 @@ static char name[255]; static char description[255]; static int hasreadme, haslicense; +void +commitinfo_free(struct commitinfo *ci) +{ + if (!ci) + return; + + /* TODO: print error ? */ + git_diff_stats_free(ci->stats); + git_diff_free(ci->diff); + git_commit_free(ci->commit); +} + +struct commitinfo * +commitinfo_getbyoid(const git_oid *id) +{ + struct commitinfo *ci; + int error; + + if (!(ci = calloc(1, sizeof(struct commitinfo)))) + err(1, "calloc"); + + ci->id = id; + if (git_commit_lookup(&(ci->commit), repo, id)) + goto err; + + /* TODO: show tags when commit has it */ + git_oid_tostr(ci->oid, sizeof(ci->oid), git_commit_id(ci->commit)); + git_oid_tostr(ci->parentoid, sizeof(ci->parentoid), git_commit_parent_id(ci->commit, 0)); + + ci->author = git_commit_author(ci->commit); + ci->summary = git_commit_summary(ci->commit); + ci->msg = git_commit_message(ci->commit); + + if ((error = git_commit_tree(&(ci->commit_tree), ci->commit))) + goto err; /* TODO: handle error */ + if (!(error = git_commit_parent(&(ci->parent), ci->commit, 0))) { + if ((error = git_commit_tree(&(ci->parent_tree), ci->parent))) + goto err; + } else { + ci->parent = NULL; + ci->parent_tree = NULL; + } + + if ((error = git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, NULL))) + goto err; + if (git_diff_get_stats(&(ci->stats), ci->diff)) + goto err; + + ci->addcount = git_diff_stats_insertions(ci->stats); + ci->delcount = git_diff_stats_deletions(ci->stats); + ci->filecount = git_diff_stats_files_changed(ci->stats); + + /* TODO: show tag when commit has it */ + + return ci; + +err: + commitinfo_free(ci); + free(ci); + + return NULL; +} + int writeheader(FILE *fp) { @@ -156,22 +241,23 @@ printtime(FILE *fp, const git_time *intime) } void -printcommit(FILE *fp, git_commit *commit) +writeblobhtml(FILE *fp, const git_blob *blob) { - const git_signature *sig; - char buf[GIT_OID_HEXSZ + 1]; - int i, count; - const char *msg; + xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob)); +} +void +printcommit(FILE *fp, struct commitinfo *ci) +{ /* TODO: show tag when commit has it */ - git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); fprintf(fp, "<b>commit</b> <a href=\"%scommit/%s.html\">%s</a>\n", - relpath, buf, buf); + relpath, ci->oid, ci->oid); - if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0)) && buf[0]) + if (ci->parentoid[0]) fprintf(fp, "<b>parent</b> <a href=\"%scommit/%s.html\">%s</a>\n", - relpath, buf, buf); + relpath, ci->parentoid, ci->parentoid); +#if 0 if ((count = (int)git_commit_parentcount(commit)) > 1) { fprintf(fp, "<b>Merge:</b>"); for (i = 0; i < count; i++) { @@ -181,81 +267,66 @@ printcommit(FILE *fp, git_commit *commit) } fputc('\n', fp); } - if ((sig = git_commit_author(commit)) != NULL) { +#endif + if (ci->author) { fprintf(fp, "<b>Author:</b> "); - xmlencode(fp, sig->name, strlen(sig->name)); + xmlencode(fp, ci->author->name, strlen(ci->author->name)); fprintf(fp, " &lt;<a href=\"mailto:"); - xmlencode(fp, sig->email, strlen(sig->email)); + xmlencode(fp, ci->author->email, strlen(ci->author->email)); fputs("\">", fp); - xmlencode(fp, sig->email, strlen(sig->email)); + xmlencode(fp, ci->author->email, strlen(ci->author->email)); fputs("</a>&gt;\n<b>Date:</b> ", fp); - printtime(fp, &sig->when); + printtime(fp, &(ci->author->when)); fputc('\n', fp); } fputc('\n', fp); - if ((msg = git_commit_message(commit))) - xmlencode(fp, msg, strlen(msg)); + if (ci->msg) + xmlencode(fp, ci->msg, strlen(ci->msg)); + fputc('\n', fp); } void -printshowfile(git_commit *commit) +printshowfile(struct commitinfo *ci) { - const git_diff_delta *delta = NULL; - const git_diff_hunk *hunk = NULL; - const git_diff_line *line = NULL; - git_commit *parent = NULL; - git_tree *commit_tree = NULL, *parent_tree = NULL; - git_patch *patch = NULL; - git_diff *diff = NULL; - git_diff_stats *diffstats = NULL; - git_buf diffstatsbuf; + const git_diff_delta *delta; + const git_diff_hunk *hunk; + const git_diff_line *line; + git_patch *patch; + git_buf statsbuf; + size_t ndeltas, nhunks, nhunklines; FILE *fp; - size_t i, j, k, ndeltas, nhunks = 0, nhunklines = 0; - char buf[GIT_OID_HEXSZ + 1], path[PATH_MAX]; - int error; + size_t i, j, k; + char path[PATH_MAX]; - git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - if (!buf[0]) - return; - snprintf(path, sizeof(path), "commit/%s.html", buf); + snprintf(path, sizeof(path), "commit/%s.html", ci->oid); /* check if file exists if so skip it */ if (!access(path, F_OK)) return; - memset(&diffstatsbuf, 0, sizeof(diffstatsbuf)); - fp = efopen(path, "w+b"); writeheader(fp); - printcommit(fp, commit); + printcommit(fp, ci); - if ((error = git_commit_tree(&commit_tree, commit))) - goto err; - if (!(error = git_commit_parent(&parent, commit, 0))) { - if ((error = git_commit_tree(&parent_tree, parent))) - goto err; /* TODO: handle error */ - } else { - parent = NULL; - parent_tree = NULL; - } - if ((error = git_diff_tree_to_tree(&diff, repo, parent_tree, commit_tree, NULL))) - goto err; + memset(&statsbuf, 0, sizeof(statsbuf)); /* diff stat */ - if (!git_diff_get_stats(&diffstats, diff)) { - if (!git_diff_stats_to_buf(&diffstatsbuf, diffstats, + if (ci->stats) { + if (!git_diff_stats_to_buf(&statsbuf, ci->stats, GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_SHORT, 80)) { - fprintf(fp, "<b>Diffstat:</b>\n"); - fputs(diffstatsbuf.ptr, fp); + if (statsbuf.ptr && statsbuf.ptr[0]) { + fprintf(fp, "<b>Diffstat:</b>\n"); + fputs(statsbuf.ptr, fp); + } } - git_diff_stats_free(diffstats); } + fputs("<hr/>", fp); - ndeltas = git_diff_num_deltas(diff); + ndeltas = git_diff_num_deltas(ci->diff); for (i = 0; i < ndeltas; i++) { - if (git_patch_from_diff(&patch, diff, i)) { + if (git_patch_from_diff(&patch, ci->diff, i)) { git_patch_free(patch); break; /* TODO: handle error */ } @@ -265,26 +336,6 @@ printshowfile(git_commit *commit) relpath, delta->old_file.path, delta->old_file.path, relpath, delta->new_file.path, delta->new_file.path); - /* TODO: "new file mode <mode>". */ - /* TODO: add indexfrom...indexto + flags */ - -#if 0 - fputs("<b>--- ", fp); - if (delta->status & GIT_DELTA_ADDED) - fputs("/dev/null", fp); - else - fprintf(fp, "a/<a href=\"%sfile/%s\">%s</a>", - relpath, delta->old_file.path, delta->old_file.path); - - fputs("\n+++ ", fp); - if (delta->status & GIT_DELTA_DELETED) - fputs("/dev/null", fp); - else - fprintf(fp, "b/<a href=\"%sfile/%s\">%s</a>", - relpath, delta->new_file.path, delta->new_file.path); - fputs("</b>\n", fp); -#endif - /* check binary data */ if (delta->flags & GIT_DIFF_FLAG_BINARY) { fputs("Binary files differ\n", fp); @@ -317,32 +368,20 @@ printshowfile(git_commit *commit) } git_patch_free(patch); } - git_diff_free(diff); + git_buf_free(&statsbuf); writefooter(fp); fclose(fp); return; - -err: - git_buf_free(&diffstatsbuf); - fclose(fp); } int writelog(FILE *fp) { + struct commitinfo *ci; git_revwalk *w = NULL; git_oid id; - git_commit *commit = NULL; - const git_signature *author; - git_diff_stats *stats = NULL; - git_tree *commit_tree = NULL, *parent_tree = NULL; - git_commit *parent = NULL; - git_diff *diff = NULL; - size_t nfiles, ndel, nadd; - const char *summary; - char buf[GIT_OID_HEXSZ + 1]; - int error, ret = 0; + int ret = 0; mkdir("commit", 0755); @@ -355,67 +394,37 @@ writelog(FILE *fp) while (!git_revwalk_next(&id, w)) { relpath = ""; - if (git_commit_lookup(&commit, repo, &id)) { - ret = 1; - goto err; - } - if ((error = git_commit_tree(&commit_tree, commit))) - goto errdiff; /* TODO: handle error */ - if (!(error = git_commit_parent(&parent, commit, 0))) { - if ((error = git_commit_tree(&parent_tree, parent))) - goto errdiff; - } else { - parent = NULL; - parent_tree = NULL; - } - - if ((error = git_diff_tree_to_tree(&diff, repo, parent_tree, commit_tree, NULL))) - goto errdiff; - if (git_diff_get_stats(&stats, diff)) - goto errdiff; - - git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - - ndel = git_diff_stats_deletions(stats); - nadd = git_diff_stats_insertions(stats); - nfiles = git_diff_stats_files_changed(stats); - - /* TODO: show tag when commit has it */ - - /* TODO: collect stats per author and make stats.html page */ - author = git_commit_author(commit); - summary = git_commit_summary(commit); + if (!(ci = commitinfo_getbyoid(&id))) + break; fputs("<tr><td>", fp); - if (summary) { - fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, buf); - xmlencode(fp, summary, strlen(summary)); + if (ci->summary) { + fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid); + xmlencode(fp, ci->summary, strlen(ci->summary)); fputs("</a>", fp); } fputs("</td><td>", fp); - if (author) - xmlencode(fp, author->name, strlen(author->name)); + if (ci->author) + xmlencode(fp, ci->author->name, strlen(ci->author->name)); + fputs("</td><td align=\"right\">", fp); - printtime(fp, &author->when); + if (ci->author) + printtime(fp, &(ci->author->when)); fputs("</td><td align=\"right\">", fp); - fprintf(fp, "%zu", nfiles); + fprintf(fp, "%zu", ci->filecount); fputs("</td><td align=\"right\">", fp); - fprintf(fp, "+%zu", nadd); + fprintf(fp, "+%zu", ci->addcount); fputs("</td><td align=\"right\">", fp); - fprintf(fp, "-%zu", ndel); + fprintf(fp, "-%zu", ci->delcount); fputs("</td></tr>\n", fp); relpath = "../"; - printshowfile(commit); + printshowfile(ci); -errdiff: - /* TODO: print error ? */ - git_diff_stats_free(stats); - git_diff_free(diff); - git_commit_free(commit); + commitinfo_free(ci); } fprintf(fp, "</tbody></table>"); -err: + git_revwalk_free(w); relpath = ""; @@ -423,38 +432,28 @@ err: } void -printcommitatom(FILE *fp, git_commit *commit) +printcommitatom(FILE *fp, struct commitinfo *ci) { - const git_signature *sig; - char buf[GIT_OID_HEXSZ + 1]; - int i, count; - const char *msg, *summary; - fputs("<entry>\n", fp); - /* TODO: show tag when commit has it */ - git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - fprintf(fp, "<id>%s</id>\n", buf); - - sig = git_commit_author(commit); - - if (sig) { + fprintf(fp, "<id>%s</id>\n", ci->oid); + if (ci->author) { fputs("<updated>", fp); - printtimez(fp, &sig->when); + printtimez(fp, &(ci->author->when)); fputs("</updated>\n", fp); } - - if ((summary = git_commit_summary(commit))) { + if (ci->summary) { fputs("<title type=\"text\">", fp); - xmlencode(fp, summary, strlen(summary)); + xmlencode(fp, ci->summary, strlen(ci->summary)); fputs("</title>\n", fp); } fputs("<content type=\"text\">", fp); - fprintf(fp, "commit %s\n", buf); - if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0)) && buf[0]) - fprintf(fp, "parent %s\n", buf); + fprintf(fp, "commit %s\n", ci->oid); + if (ci->parentoid[0]) + fprintf(fp, "parent %s\n", ci->parentoid); +#if 0 if ((count = (int)git_commit_parentcount(commit)) > 1) { fprintf(fp, "Merge:"); for (i = 0; i < count; i++) { @@ -463,25 +462,26 @@ printcommitatom(FILE *fp, git_commit *commit) } fputc('\n', fp); } +#endif - if (sig) { + if (ci->author) { fprintf(fp, "Author: "); - xmlencode(fp, sig->name, strlen(sig->name)); + xmlencode(fp, ci->author->name, strlen(ci->author->name)); fprintf(fp, " &lt;"); - xmlencode(fp, sig->email, strlen(sig->email)); + xmlencode(fp, ci->author->email, strlen(ci->author->email)); fprintf(fp, "&gt;\nDate: "); - printtime(fp, &sig->when); + printtime(fp, &(ci->author->when)); } fputc('\n', fp); - if ((msg = git_commit_message(commit))) - xmlencode(fp, msg, strlen(msg)); + if (ci->msg) + xmlencode(fp, ci->msg, strlen(ci->msg)); fputs("\n</content>\n", fp); - if (sig) { + if (ci->author) { fputs("<author><name>", fp); - xmlencode(fp, sig->name, strlen(sig->name)); + xmlencode(fp, ci->author->name, strlen(ci->author->name)); fputs("</name>\n<email>", fp); - xmlencode(fp, sig->email, strlen(sig->email)); + xmlencode(fp, ci->author->email, strlen(ci->author->email)); fputs("</email>\n</author>\n", fp); } fputs("</entry>\n", fp); @@ -490,9 +490,9 @@ printcommitatom(FILE *fp, git_commit *commit) int writeatom(FILE *fp) { + struct commitinfo *ci; git_revwalk *w = NULL; git_oid id; - git_commit *c = NULL; size_t i, m = 100; /* max */ fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp); @@ -507,10 +507,10 @@ writeatom(FILE *fp) git_revwalk_push_head(w); for (i = 0; i < m && !git_revwalk_next(&id, w); i++) { - if (git_commit_lookup(&c, repo, &id)) - return 1; /* TODO: error */ - printcommitatom(fp, c); - git_commit_free(c); + if (!(ci = commitinfo_getbyoid(&id))) + break; + printcommitatom(fp, ci); + commitinfo_free(ci); } git_revwalk_free(w); @@ -522,14 +522,16 @@ writeatom(FILE *fp) int writefiles(FILE *fp) { - git_index *index; const git_index_entry *entry; + git_index *index; size_t count, i; - git_repository_index(&index, repo); + fputs("<table><thead>\n" + "<tr><td>Mode</td><td>Name</td><td align=\"right\">Size</td></tr>\n" + "</thead><tbody>\n", fp); + git_repository_index(&index, repo); count = git_index_entrycount(index); - fputs("<table><thead>\n<tr><td>Mode</td><td>Name</td><td align=\"right\">Size</td></tr>\n</thead><tbody>\n", fp); for (i = 0; i < count; i++) { entry = git_index_get_byindex(index, i); @@ -543,17 +545,12 @@ writefiles(FILE *fp) fprintf(fp, "%" PRIu64, entry->file_size); fputs("</td></tr>\n", fp); } + fputs("</tbody></table>", fp); return 0; } -void -writeblobhtml(FILE *fp, const git_blob *blob) -{ - xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob)); -} - int main(int argc, char *argv[]) {