| tcache support (-c option) - stagit - static git page generator | |
| git clone git://src.adamsgaard.dk/stagit | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| commit 1a3584e2d0689aece46d9832c91f57723296807f | |
| parent ede93fa7ee0af8e6e858981e1a7e5057646487ce | |
| Author: Hiltjo Posthuma <[email protected]> | |
| Date: Sun, 1 May 2016 17:54:14 +0200 | |
| cache support (-c option) | |
| "Optionally the -c cachefile option can be used to cache the entries of | |
| tthe log page up to the point of the last commit. The cachefile will store | |
| tthe last commit id and the entries in the HTML table." | |
| tthis caches the diffstat and commits, it is an expensive operation (twss). | |
| Diffstat: | |
| M stagit.1 | 20 +++++++++++++++++--- | |
| M stagit.c | 151 +++++++++++++++++++++++------… | |
| 2 files changed, 130 insertions(+), 41 deletions(-) | |
| --- | |
| diff --git a/stagit.1 b/stagit.1 | |
| t@@ -1,4 +1,4 @@ | |
| -.Dd December 26, 2015 | |
| +.Dd May 1, 2016 | |
| .Dt STAGIT 1 | |
| .Os | |
| .Sh NAME | |
| t@@ -6,12 +6,26 @@ | |
| .Nd static git page generator | |
| .Sh SYNOPSIS | |
| .Nm | |
| -.Op Ar repodir | |
| +.Op Fl c Ar cachefile | |
| +.Ar repodir | |
| .Sh DESCRIPTION | |
| .Nm | |
| writes HTML pages for the repository | |
| .Ar repodir | |
| -to the current directory. The following files will be written: | |
| +to the current directory. | |
| +.Pp | |
| +Optionally the | |
| +.Fl c Ar cachefile | |
| +option can be used to cache the entries of the log page up to the point of | |
| +the last commit. The | |
| +.Ar cachefile | |
| +will store the last commit id and the entries in the HTML table. It is up | |
| +to the user to make sure the state of the | |
| +.Ar cachefile | |
| +is in sync with the history of the repository, for example a | |
| +git push \-\-force can screw this up. | |
| +.Pp | |
| +The following files will be written: | |
| .Bl -tag -width Ds | |
| .It atom.xml | |
| Atom XML feed | |
| diff --git a/stagit.c b/stagit.c | |
| t@@ -58,6 +58,12 @@ static char description[255]; | |
| static char cloneurl[1024]; | |
| static int haslicense, hasreadme, hassubmodules; | |
| +/* cache */ | |
| +static git_oid lastoid; | |
| +static char lastoidstr[GIT_OID_HEXSZ + 2]; /* id + newline + nul byte */ | |
| +static FILE *rcachefp, *wcachefp; | |
| +static const char *cachefile; | |
| + | |
| void | |
| deltainfo_free(struct deltainfo *di) | |
| { | |
| t@@ -530,13 +536,43 @@ printshowfile(FILE *fp, struct commitinfo *ci) | |
| } | |
| } | |
| +void | |
| +writelogline(FILE *fp, struct commitinfo *ci) | |
| +{ | |
| + size_t len; | |
| + | |
| + fputs("<tr><td>", fp); | |
| + if (ci->author) | |
| + printtimeshort(fp, &(ci->author->when)); | |
| + fputs("</td><td>", fp); | |
| + if (ci->summary) { | |
| + fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid); | |
| + if ((len = strlen(ci->summary)) > summarylen) { | |
| + xmlencode(fp, ci->summary, summarylen - 1); | |
| + fputs("…", fp); | |
| + } else { | |
| + xmlencode(fp, ci->summary, len); | |
| + } | |
| + fputs("</a>", fp); | |
| + } | |
| + fputs("</td><td>", fp); | |
| + if (ci->author) | |
| + xmlencode(fp, ci->author->name, strlen(ci->author->name)); | |
| + fputs("</td><td class=\"num\">", fp); | |
| + fprintf(fp, "%zu", ci->filecount); | |
| + fputs("</td><td class=\"num\">", fp); | |
| + fprintf(fp, "+%zu", ci->addcount); | |
| + fputs("</td><td class=\"num\">", fp); | |
| + fprintf(fp, "-%zu", ci->delcount); | |
| + fputs("</td></tr>\n", fp); | |
| +} | |
| + | |
| int | |
| writelog(FILE *fp, const git_oid *oid) | |
| { | |
| struct commitinfo *ci; | |
| git_revwalk *w = NULL; | |
| git_oid id; | |
| - size_t len; | |
| char path[PATH_MAX]; | |
| FILE *fpfile; | |
| int r; | |
| t@@ -546,40 +582,17 @@ writelog(FILE *fp, const git_oid *oid) | |
| git_revwalk_sorting(w, GIT_SORT_TIME); | |
| git_revwalk_simplify_first_parent(w); | |
| - fputs("<table id=\"log\"><thead>\n<tr><td>Date</td><td>Commit message<… | |
| - "<td>Author</td><td class=\"num\">Files</td><td class=\"num\… | |
| - "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp); | |
| - | |
| while (!git_revwalk_next(&id, w)) { | |
| relpath = ""; | |
| + if (cachefile && !memcmp(&id, &lastoid, sizeof(id))) | |
| + break; | |
| if (!(ci = commitinfo_getbyoid(&id))) | |
| break; | |
| - fputs("<tr><td>", fp); | |
| - if (ci->author) | |
| - printtimeshort(fp, &(ci->author->when)); | |
| - fputs("</td><td>", fp); | |
| - if (ci->summary) { | |
| - fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, … | |
| - if ((len = strlen(ci->summary)) > summarylen) { | |
| - xmlencode(fp, ci->summary, summarylen - 1); | |
| - fputs("…", fp); | |
| - } else { | |
| - xmlencode(fp, ci->summary, len); | |
| - } | |
| - fputs("</a>", fp); | |
| - } | |
| - fputs("</td><td>", fp); | |
| - if (ci->author) | |
| - xmlencode(fp, ci->author->name, strlen(ci->author->nam… | |
| - fputs("</td><td class=\"num\">", fp); | |
| - fprintf(fp, "%zu", ci->filecount); | |
| - fputs("</td><td class=\"num\">", fp); | |
| - fprintf(fp, "+%zu", ci->addcount); | |
| - fputs("</td><td class=\"num\">", fp); | |
| - fprintf(fp, "-%zu", ci->delcount); | |
| - fputs("</td></tr>\n", fp); | |
| + writelogline(fp, ci); | |
| + if (cachefile) | |
| + writelogline(wcachefp, ci); | |
| relpath = "../"; | |
| t@@ -599,8 +612,6 @@ writelog(FILE *fp, const git_oid *oid) | |
| } | |
| commitinfo_free(ci); | |
| } | |
| - fputs("</tbody></table>", fp); | |
| - | |
| git_revwalk_free(w); | |
| relpath = ""; | |
| t@@ -1005,6 +1016,13 @@ joinpath(char *buf, size_t bufsiz, const char *path, co… | |
| path, path[0] && path[strlen(path) - 1] != '/' ? "/" :… | |
| } | |
| +void | |
| +usage(char *argv0) | |
| +{ | |
| + fprintf(stderr, "%s [-c cachefile] repodir\n", argv0); | |
| + exit(1); | |
| +} | |
| + | |
| int | |
| main(int argc, char *argv[]) | |
| { | |
| t@@ -1013,12 +1031,23 @@ main(int argc, char *argv[]) | |
| const git_error *e = NULL; | |
| FILE *fp, *fpread; | |
| char path[PATH_MAX], repodirabs[PATH_MAX + 1], *p; | |
| - | |
| - if (argc != 2) { | |
| - fprintf(stderr, "%s <repodir>\n", argv[0]); | |
| - return 1; | |
| + char tmppath[64] = "cache.XXXXXXXXXXXX", buf[BUFSIZ]; | |
| + size_t n; | |
| + int i, fd; | |
| + | |
| + 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) | |
| + usage(argv[0]); | |
| + cachefile = argv[++i]; | |
| + } | |
| } | |
| - repodir = argv[1]; | |
| + if (!repodir) | |
| + usage(argv[0]); | |
| if (!realpath(repodir, repodirabs)) | |
| err(1, "realpath"); | |
| t@@ -1088,9 +1117,51 @@ main(int argc, char *argv[]) | |
| /* log for HEAD */ | |
| fp = efopen("log.html", "w"); | |
| relpath = ""; | |
| - writeheader(fp, "Log"); | |
| mkdir("commit", 0755); | |
| - writelog(fp, head); | |
| + writeheader(fp, "Log"); | |
| + fputs("<table id=\"log\"><thead>\n<tr><td>Date</td><td>Commit message<… | |
| + "<td>Author</td><td class=\"num\">Files</td><td class=\"num\… | |
| + "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp); | |
| + | |
| + if (cachefile) { | |
| + /* read from cache file (does not need to exist) */ | |
| + if ((rcachefp = fopen(cachefile, "r"))) { | |
| + if (!fgets(lastoidstr, sizeof(lastoidstr), rcachefp)) | |
| + errx(1, "%s: no object id", cachefile); | |
| + if (git_oid_fromstr(&lastoid, lastoidstr)) | |
| + errx(1, "%s: invalid object id", cachefile); | |
| + } | |
| + | |
| + /* write log to (temporary) cache */ | |
| + if ((fd = mkstemp(tmppath)) == -1) | |
| + err(1, "mkstemp"); | |
| + if (!(wcachefp = fdopen(fd, "w"))) | |
| + err(1, "fdopen"); | |
| + /* write last commit id (HEAD) */ | |
| + git_oid_tostr(buf, sizeof(buf), head); | |
| + fprintf(wcachefp, "%s\n", buf); | |
| + | |
| + writelog(fp, head); | |
| + | |
| + if (rcachefp) { | |
| + /* append previous log to log.html and the new cache */ | |
| + while (!feof(rcachefp)) { | |
| + n = fread(buf, 1, sizeof(buf), rcachefp); | |
| + if (ferror(rcachefp)) | |
| + err(1, "fread"); | |
| + if (fwrite(buf, 1, n, fp) != n) | |
| + err(1, "fwrite"); | |
| + if (fwrite(buf, 1, n, wcachefp) != n) | |
| + err(1, "fwrite"); | |
| + } | |
| + fclose(rcachefp); | |
| + } | |
| + fclose(wcachefp); | |
| + } else { | |
| + writelog(fp, head); | |
| + } | |
| + | |
| + fputs("</tbody></table>", fp); | |
| writefooter(fp); | |
| fclose(fp); | |
| t@@ -1113,6 +1184,10 @@ main(int argc, char *argv[]) | |
| writeatom(fp); | |
| fclose(fp); | |
| + /* rename new cache file on success */ | |
| + if (cachefile && rename(tmppath, cachefile)) | |
| + err(1, "rename: '%s' to '%s'", tmppath, cachefile); | |
| + | |
| /* cleanup */ | |
| git_repository_free(repo); | |
| git_libgit2_shutdown(); |