]> git.armaanb.net Git - stagit.git/commitdiff
optimization: read stats once and remember it
authorHiltjo Posthuma <hiltjo@codemadness.org>
Sat, 30 Apr 2016 09:54:33 +0000 (11:54 +0200)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Sat, 30 Apr 2016 10:47:00 +0000 (12:47 +0200)
for an initial run and new commits this speeds stagit up a bit:
on an initial run of sbase goes from about 4 seconds to 2.8 on my machine.

now we can't use statsbuf, so create the stats string ourselves, while at it
color the + and - using a style (can be disabled for the color-haters out
there ;)).

stagit.c
style.css

index 28b2b7e491f91a98b9dee3a4463c8e392d0cd328..aea474718c567af173d5ad654826f64e29007e16 100644 (file)
--- a/stagit.c
+++ b/stagit.c
 #include "compat.h"
 #include "config.h"
 
+struct deltainfo {
+       git_patch *patch;
+
+       size_t addcount;
+       size_t delcount;
+};
+
 struct commitinfo {
        const git_oid *id;
 
@@ -25,16 +32,18 @@ struct commitinfo {
        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;
+       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;
+
+       struct deltainfo **deltas;
+       size_t ndeltas;
 };
 
 static git_repository *repo;
@@ -48,13 +57,96 @@ static char description[255];
 static char cloneurl[1024];
 static int haslicense, hasreadme, hassubmodules;
 
+void
+deltainfo_free(struct deltainfo *di)
+{
+       if (!di)
+               return;
+       git_patch_free(di->patch);
+       di->patch = NULL;
+       free(di);
+}
+
+int
+commitinfo_getstats(struct commitinfo *ci)
+{
+       struct deltainfo *di;
+       const git_diff_delta *delta;
+       const git_diff_hunk *hunk;
+       const git_diff_line *line;
+       git_patch *patch = NULL;
+       size_t ndeltas, nhunks, nhunklines;
+       size_t i, j, k;
+
+       ndeltas = git_diff_num_deltas(ci->diff);
+       if (ndeltas && !(ci->deltas = calloc(ndeltas, sizeof(struct deltainfo *))))
+               err(1, "calloc");
+
+       for (i = 0; i < ndeltas; i++) {
+               if (!(di = calloc(1, sizeof(struct deltainfo))))
+                       err(1, "calloc");
+               if (git_patch_from_diff(&patch, ci->diff, i)) {
+                       git_patch_free(patch);
+                       goto err;
+               }
+               di->patch = patch;
+               ci->deltas[i] = di;
+
+               delta = git_patch_get_delta(patch);
+
+               /* check binary data */
+               if (delta->flags & GIT_DIFF_FLAG_BINARY)
+                       continue;
+
+               nhunks = git_patch_num_hunks(patch);
+               for (j = 0; j < nhunks; j++) {
+                       if (git_patch_get_hunk(&hunk, &nhunklines, patch, j))
+                               break;
+                       for (k = 0; ; k++) {
+                               if (git_patch_get_line_in_hunk(&line, patch, j, k))
+                                       break;
+                               if (line->old_lineno == -1) {
+                                       di->addcount++;
+                                       ci->addcount++;
+                               } else if (line->new_lineno == -1) {
+                                       di->delcount++;
+                                       ci->delcount++;
+                               }
+                       }
+               }
+       }
+       ci->ndeltas = i;
+       ci->filecount = i;
+
+       return 0;
+
+err:
+       if (ci->deltas)
+               for (i = 0; i < ci->ndeltas; i++)
+                       deltainfo_free(ci->deltas[i]);
+       free(ci->deltas);
+       ci->deltas = NULL;
+       ci->ndeltas = 0;
+       ci->addcount = 0;
+       ci->delcount = 0;
+       ci->filecount = 0;
+
+       return -1;
+}
+
 void
 commitinfo_free(struct commitinfo *ci)
 {
+       size_t i;
+
        if (!ci)
                return;
 
-       git_diff_stats_free(ci->stats);
+       if (ci->deltas)
+               for (i = 0; i < ci->ndeltas; i++)
+                       deltainfo_free(ci->deltas[i]);
+       free(ci->deltas);
+       ci->deltas = NULL;
        git_diff_free(ci->diff);
        git_tree_free(ci->commit_tree);
        git_tree_free(ci->parent_tree);
@@ -66,6 +158,7 @@ commitinfo_getbyoid(const git_oid *id)
 {
        struct commitinfo *ci;
        git_diff_options opts;
+       const git_oid *oid;
        int error;
 
        if (!(ci = calloc(1, sizeof(struct commitinfo))))
@@ -82,26 +175,24 @@ commitinfo_getbyoid(const git_oid *id)
        ci->summary = git_commit_summary(ci->commit);
        ci->msg = git_commit_message(ci->commit);
 
-       if ((error = git_commit_tree(&(ci->commit_tree), ci->commit)))
+       oid = git_commit_tree_id(ci->commit);
+       if ((error = git_tree_lookup(&(ci->commit_tree), repo, oid)))
                goto err;
        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;
+               oid = git_commit_tree_id(ci->parent);
+               if ((error = git_tree_lookup(&(ci->parent_tree), repo, oid))) {
+                       ci->parent = NULL;
+                       ci->parent_tree = NULL;
+               }
        }
 
        git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
        opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
        if ((error = git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts)))
                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);
+       if (commitinfo_getstats(ci) == -1)
+               goto err;
 
        return ci;
 
@@ -332,33 +423,55 @@ printshowfile(FILE *fp, struct commitinfo *ci)
        const git_diff_hunk *hunk;
        const git_diff_line *line;
        git_patch *patch;
-       git_buf statsbuf;
-       size_t ndeltas, nhunks, nhunklines;
+       size_t nhunks, nhunklines, changed, add, del, total;
        size_t i, j, k;
+       char linestr[80];
 
        printcommit(fp, ci);
 
-       memset(&statsbuf, 0, sizeof(statsbuf));
+       if (!ci->deltas)
+               return;
 
        /* diff stat */
-       if (ci->stats &&
-           !git_diff_stats_to_buf(&statsbuf, ci->stats,
-                                   GIT_DIFF_STATS_FULL | GIT_DIFF_STATS_SHORT, 80)) {
-               if (statsbuf.ptr && statsbuf.ptr[0]) {
-                       fputs("<b>Diffstat:</b>\n", fp);
-                       xmlencode(fp, statsbuf.ptr, strlen(statsbuf.ptr));
+       fputs("<b>Diffstat:</b>\n<table>", fp);
+       for (i = 0; i < ci->ndeltas; i++) {
+               delta = git_patch_get_delta(ci->deltas[i]->patch);
+               fputs("<tr><td>", fp);
+               xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
+               if (strcmp(delta->old_file.path, delta->new_file.path)) {
+                       fputs(" -&gt; ", fp);
+                       xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
+               }
+
+               add = ci->deltas[i]->addcount;
+               del = ci->deltas[i]->delcount;
+               changed = add + del;
+               total = sizeof(linestr) - 2;
+               if (changed > total) {
+                       if (add)
+                               add = ((float)total / changed * add) + 1;
+                       if (del)
+                               del = ((float)total / changed * del) + 1;
                }
+               memset(&linestr, '+', add);
+               memset(&linestr[add], '-', del);
+
+               fprintf(fp, "</td><td> | %zu <span class=\"i\">",
+                       ci->deltas[i]->addcount + ci->deltas[i]->delcount);
+               fwrite(&linestr, 1, add, fp);
+               fputs("</span><span class=\"d\">", fp);
+               fwrite(&linestr[add], 1, del, fp);
+               fputs("</span></td></tr>\n", fp);
        }
+       fprintf(fp, "</table>%zu file%s changed, %zu insertion%s(+), %zu deletion%s(-)\n",
+               ci->filecount, ci->filecount == 1 ? "" : "s",
+               ci->addcount,  ci->addcount  == 1 ? "" : "s",
+               ci->delcount,  ci->delcount  == 1 ? "" : "s");
 
        fputs("<hr/>", fp);
 
-       ndeltas = git_diff_num_deltas(ci->diff);
-       for (i = 0; i < ndeltas; i++) {
-               if (git_patch_from_diff(&patch, ci->diff, i)) {
-                       git_patch_free(patch);
-                       break;
-               }
-
+       for (i = 0; i < ci->ndeltas; i++) {
+               patch = ci->deltas[i]->patch;
                delta = git_patch_get_delta(patch);
                fprintf(fp, "<b>diff --git a/<a href=\"%sfile/%s.html\">%s</a> b/<a href=\"%sfile/%s.html\">%s</a></b>\n",
                        relpath, delta->old_file.path, delta->old_file.path,
@@ -367,7 +480,6 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                /* check binary data */
                if (delta->flags & GIT_DIFF_FLAG_BINARY) {
                        fputs("Binary files differ\n", fp);
-                       git_patch_free(patch);
                        continue;
                }
 
@@ -396,11 +508,7 @@ printshowfile(FILE *fp, struct commitinfo *ci)
                                        fputs("</a>", fp);
                        }
                }
-               git_patch_free(patch);
        }
-       git_buf_free(&statsbuf);
-
-       return;
 }
 
 int
index 8cf93d065132bd687f397180a461db4369d048b6..e7188934137bb9b09a2a10665e77f73038874d78 100644 (file)
--- a/style.css
+++ b/style.css
@@ -79,10 +79,12 @@ pre a.h {
        color: #00a;
 }
 
+span.i,
 pre a.i {
        color: #070;
 }
 
+span.d,
 pre a.d {
        color: #e00;
 }