]> git.armaanb.net Git - stagit.git/blobdiff - stagit.c
stagit-index: pledge after git_libgit2_init
[stagit.git] / stagit.c
index bf027f64dc1c63e8332f01faf08f5d6468e01789..e1c862176cf39db6fc58540752b653debd60bdb5 100644 (file)
--- a/stagit.c
+++ b/stagit.c
@@ -57,6 +57,7 @@ static char *strippedname = "";
 static char description[255];
 static char cloneurl[1024];
 static int haslicense, hasreadme, hassubmodules;
+static long long nlogcommits = -1; /* < 0 indicates not used */
 
 /* cache */
 static git_oid lastoid;
@@ -86,7 +87,7 @@ deltainfo_free(struct deltainfo *di)
        if (!di)
                return;
        git_patch_free(di->patch);
-       di->patch = NULL;
+       memset(di, 0, sizeof(*di));
        free(di);
 }
 
@@ -94,6 +95,7 @@ int
 commitinfo_getstats(struct commitinfo *ci)
 {
        struct deltainfo *di;
+       git_diff_options opts;
        const git_diff_delta *delta;
        const git_diff_hunk *hunk;
        const git_diff_line *line;
@@ -101,6 +103,20 @@ commitinfo_getstats(struct commitinfo *ci)
        size_t ndeltas, nhunks, nhunklines;
        size_t i, j, k;
 
+       if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
+               goto err;
+       if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
+               if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
+                       ci->parent = NULL;
+                       ci->parent_tree = NULL;
+               }
+       }
+
+       git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
+       opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
+       if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
+               goto err;
+
        ndeltas = git_diff_num_deltas(ci->diff);
        if (ndeltas && !(ci->deltas = calloc(ndeltas, sizeof(struct deltainfo *))))
                err(1, "calloc");
@@ -142,6 +158,15 @@ commitinfo_getstats(struct commitinfo *ci)
        return 0;
 
 err:
+       git_diff_free(ci->diff);
+       ci->diff = NULL;
+       git_tree_free(ci->commit_tree);
+       ci->commit_tree = NULL;
+       git_tree_free(ci->parent_tree);
+       ci->parent_tree = NULL;
+       git_commit_free(ci->parent);
+       ci->parent = NULL;
+
        if (ci->deltas)
                for (i = 0; i < ci->ndeltas; i++)
                        deltainfo_free(ci->deltas[i]);
@@ -165,13 +190,14 @@ commitinfo_free(struct commitinfo *ci)
        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);
        git_commit_free(ci->commit);
        git_commit_free(ci->parent);
+       memset(ci, 0, sizeof(*ci));
        free(ci);
 }
 
@@ -179,7 +205,6 @@ struct commitinfo *
 commitinfo_getbyoid(const git_oid *id)
 {
        struct commitinfo *ci;
-       git_diff_options opts;
 
        if (!(ci = calloc(1, sizeof(struct commitinfo))))
                err(1, "calloc");
@@ -196,20 +221,6 @@ commitinfo_getbyoid(const git_oid *id)
        ci->summary = git_commit_summary(ci->commit);
        ci->msg = git_commit_message(ci->commit);
 
-       if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
-               goto err;
-       if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
-               if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
-                       ci->parent = NULL;
-                       ci->parent_tree = NULL;
-               }
-       }
-
-       git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
-       opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
-       if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
-               goto err;
-
        return ci;
 
 err:
@@ -558,7 +569,7 @@ writelog(FILE *fp, const git_oid *oid)
        struct commitinfo *ci;
        git_revwalk *w = NULL;
        git_oid id;
-       char path[PATH_MAX];
+       char path[PATH_MAX], oidstr[GIT_OID_HEXSZ + 1];
        FILE *fpfile;
        int r;
 
@@ -572,24 +583,37 @@ writelog(FILE *fp, const git_oid *oid)
 
                if (cachefile && !memcmp(&id, &lastoid, sizeof(id)))
                        break;
+
+               git_oid_tostr(oidstr, sizeof(oidstr), &id);
+               r = snprintf(path, sizeof(path), "commit/%s.html", oidstr);
+               if (r == -1 || (size_t)r >= sizeof(path))
+                       errx(1, "path truncated: 'commit/%s.html'", oidstr);
+               r = access(path, F_OK);
+
+               /* optimization: if there are no log lines to write and
+                  the commit file already exists: skip the diffstat */
+               if (!nlogcommits && !r)
+                       continue;
+
                if (!(ci = commitinfo_getbyoid(&id)))
                        break;
-               /* lookup stats: only required here */
+               /* diffstat: for stagit HTML required for the log.html line */
                if (commitinfo_getstats(ci) == -1)
                        goto err;
 
-               writelogline(fp, ci);
+               if (nlogcommits < 0) {
+                       writelogline(fp, ci);
+               } else if (nlogcommits > 0) {
+                       writelogline(fp, ci);
+                       nlogcommits--;
+               }
+
                if (cachefile)
                        writelogline(wcachefp, ci);
 
-               relpath = "../";
-
-               r = snprintf(path, sizeof(path), "commit/%s.html", ci->oid);
-               if (r == -1 || (size_t)r >= sizeof(path))
-                       errx(1, "path truncated: 'commit/%s.html'", ci->oid);
-
                /* check if file exists if so skip it */
-               if (access(path, F_OK)) {
+               if (r) {
+                       relpath = "../";
                        fpfile = efopen(path, "w");
                        writeheader(fpfile, ci->summary);
                        fputs("<pre>", fpfile);
@@ -986,7 +1010,7 @@ err:
 void
 usage(char *argv0)
 {
-       fprintf(stderr, "%s [-c cachefile] repodir\n", argv0);
+       fprintf(stderr, "%s [-c cachefile] [-l commits] repodir\n", argv0);
        exit(1);
 }
 
@@ -1003,18 +1027,26 @@ main(int argc, char *argv[])
        size_t n;
        int i, fd;
 
-       if (pledge("stdio rpath wpath cpath", NULL) == -1)
-               err(1, "pledge");
-
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-') {
                        if (repodir)
                                usage(argv[0]);
                        repodir = argv[i];
                } else if (argv[i][1] == 'c') {
-                       if (i + 1 >= argc)
+                       if (nlogcommits > 0 || i + 1 >= argc)
                                usage(argv[0]);
                        cachefile = argv[++i];
+               } else if (argv[i][1] == 'l') {
+                       if (cachefile || i + 1 >= argc)
+                               usage(argv[0]);
+                       errno = 0;
+                       nlogcommits = strtoll(argv[++i], &p, 10);
+                       if (argv[i][0] == '\0' || *p != '\0' ||
+                           nlogcommits <= 0)
+                               usage(argv[0]);
+                       if (errno == ERANGE && (nlogcommits == LLONG_MAX ||
+                           nlogcommits == LLONG_MIN))
+                               usage(argv[0]);
                }
        }
        if (!repodir)
@@ -1025,6 +1057,14 @@ main(int argc, char *argv[])
 
        git_libgit2_init();
 
+       if (cachefile) {
+               if (pledge("stdio rpath wpath cpath fattr", NULL) == -1)
+                       err(1, "pledge");
+       } else {
+               if (pledge("stdio rpath wpath cpath", NULL) == -1)
+                       err(1, "pledge");
+       }
+
        if (git_repository_open_ext(&repo, repodir,
                GIT_REPOSITORY_OPEN_NO_SEARCH, NULL) < 0) {
                e = giterr_last();
@@ -1037,10 +1077,6 @@ main(int argc, char *argv[])
                head = git_object_id(obj);
        git_object_free(obj);
 
-       /* don't cache if there is no HEAD */
-       if (!head)
-               cachefile = NULL;
-
        /* use directory name as name */
        if ((name = strrchr(repodirabs, '/')))
                name++;
@@ -1104,7 +1140,7 @@ main(int argc, char *argv[])
              "<td class=\"num\" align=\"right\"><b>+</b></td>"
              "<td class=\"num\" align=\"right\"><b>-</b></td></tr>\n</thead><tbody>\n", fp);
 
-       if (cachefile) {
+       if (cachefile && head) {
                /* read from cache file (does not need to exist) */
                if ((rcachefp = fopen(cachefile, "r"))) {
                        if (!fgets(lastoidstr, sizeof(lastoidstr), rcachefp))
@@ -1167,7 +1203,7 @@ main(int argc, char *argv[])
        fclose(fp);
 
        /* rename new cache file on success */
-       if (cachefile) {
+       if (cachefile && head) {
                if (rename(tmppath, cachefile))
                        err(1, "rename: '%s' to '%s'", tmppath, cachefile);
                umask((mask = umask(0)));