initial diff support, fix log link - stagit-gopher - A git gopher frontend. (mi… | |
git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2h… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit a95a439aaa7d048c25e988b0d9770f5040f0a17f | |
parent 04eeb7f000b14af31b9923ea7216edcaf0915586 | |
Author: Hiltjo Posthuma <[email protected]> | |
Date: Mon, 7 Dec 2015 14:07:58 +0100 | |
initial diff support, fix log link | |
Diffstat: | |
M urmoms.c | 244 ++++++++++++++++++++++-------… | |
1 file changed, 176 insertions(+), 68 deletions(-) | |
--- | |
diff --git a/urmoms.c b/urmoms.c | |
@@ -1,3 +1,5 @@ | |
+#include <sys/stat.h> | |
+ | |
#include <err.h> | |
#include <libgen.h> | |
#include <limits.h> | |
@@ -9,13 +11,48 @@ | |
static git_repository *repo; | |
-static const char *relpath; | |
-static const char *repodir = "."; | |
+static const char *relpath = ""; | |
+static const char *repodir; | |
static char name[255]; | |
static char description[255]; | |
static int hasreadme, haslicense; | |
+int | |
+writeheader(FILE *fp) | |
+{ | |
+ fprintf(fp, "<!DOCTYPE HTML>" | |
+ "<html dir=\"ltr\" lang=\"en\"><head>" | |
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; charse… | |
+ "<meta http-equiv=\"Content-Language\" content=\"en\" />"); | |
+ fprintf(fp, "<title>%s%s%s</title>", name, description[0] ? " - " : ""… | |
+ fprintf(fp, "<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.pn… | |
+ fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" tit… | |
+ name, relpath); | |
+ fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.c… | |
+ "</head><body><center>"); | |
+ fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath… | |
+ fprintf(fp, "<span class=\"desc\">%s</span><br/>", description); | |
+ fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath); | |
+ fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath); | |
+ fprintf(fp, "<a href=\"%sstats.html\">Stats</a>", relpath); | |
+ if (hasreadme) | |
+ fprintf(fp, " | <a href=\"%sreadme.html\">README</a>", relpath… | |
+ if (haslicense) | |
+ fprintf(fp, " | <a href=\"%slicense.html\">LICENSE</a>", relpa… | |
+ fprintf(fp, "</center><hr/><pre>"); | |
+ | |
+ return 0; | |
+} | |
+ | |
+int | |
+writefooter(FILE *fp) | |
+{ | |
+ fprintf(fp, "</pre></body></html>"); | |
+ | |
+ return 0; | |
+} | |
+ | |
FILE * | |
efopen(const char *name, const char *flags) | |
{ | |
@@ -67,8 +104,8 @@ xbasename(const char *path) | |
return b; | |
} | |
-static void | |
-printtime(FILE *fp, const git_time *intime, const char *prefix) | |
+void | |
+printtime(FILE *fp, const git_time *intime) | |
{ | |
struct tm *intm; | |
time_t t; | |
@@ -91,10 +128,10 @@ printtime(FILE *fp, const git_time *intime, const char *pr… | |
intm = gmtime(&t); | |
strftime(out, sizeof(out), "%a %b %e %T %Y", intm); | |
- fprintf(fp, "%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes); | |
+ fprintf(fp, "%s %c%02d%02d\n", out, sign, hours, minutes); | |
} | |
-static void | |
+void | |
printcommit(FILE *fp, git_commit *commit) | |
{ | |
const git_signature *sig; | |
@@ -103,22 +140,31 @@ printcommit(FILE *fp, git_commit *commit) | |
const char *scan, *eol; | |
git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); | |
- fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf); | |
+ fprintf(fp, "commit <a href=\"%scommit/%s.html\">%s</a>\n", | |
+ relpath, buf, buf); | |
+ | |
+ if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0))) | |
+ fprintf(fp, "parent <a href=\"%scommit/%s.html\">%s</a>\n", | |
+ relpath, buf, buf); | |
if ((count = (int)git_commit_parentcount(commit)) > 1) { | |
fprintf(fp, "Merge:"); | |
for (i = 0; i < count; ++i) { | |
git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); | |
- fprintf(fp, " %s", buf); | |
+ fprintf(fp, " <a href=\"%scommit/%s.html\">%s</a>", | |
+ relpath, buf, buf); | |
} | |
- fprintf(fp, "\n"); | |
+ fputc('\n', fp); | |
} | |
if ((sig = git_commit_author(commit)) != NULL) { | |
- fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n", | |
- sig->name, sig->name, sig->email); | |
- printtime(fp, &sig->when, "Date: "); | |
+ fprintf(fp, "Author: "); | |
+ xmlencode(fp, sig->name, strlen(sig->name)); | |
+ fprintf(fp, " <"); | |
+ xmlencode(fp, sig->email, strlen(sig->email)); | |
+ fprintf(fp, ">\nDate: "); | |
+ printtime(fp, &sig->when); | |
} | |
- fprintf(fp, "\n"); | |
+ fputc('\n', fp); | |
for (scan = git_commit_message(commit); scan && *scan;) { | |
for (eol = scan; *eol && *eol != '\n'; ++eol) /* find e… | |
@@ -127,79 +173,131 @@ printcommit(FILE *fp, git_commit *commit) | |
fprintf(fp, " %.*s\n", (int) (eol - scan), scan); | |
scan = *eol ? eol + 1 : NULL; | |
} | |
- fprintf(fp, "\n"); | |
+ fputc('\n', fp); | |
} | |
-static void | |
-printcommitdiff(FILE *fp, git_commit *commit) | |
+void | |
+printshowfile(git_commit *commit) | |
{ | |
- const git_signature *sig; | |
- char buf[GIT_OID_HEXSZ + 1]; | |
- int i, count; | |
- const char *scan, *eol; | |
+ 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; | |
+ size_t i, j, k, ndeltas, nhunks = 0, nhunklines = 0; | |
+ char buf[GIT_OID_HEXSZ + 1], path[PATH_MAX]; | |
+ FILE *fp; | |
+ int error; | |
git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); | |
- fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf); | |
- if ((count = (int)git_commit_parentcount(commit)) > 1) { | |
- fprintf(fp, "Merge:"); | |
- for (i = 0; i < count; ++i) { | |
- git_oid_tostr(buf, 8, git_commit_parent_id(commit, i)); | |
- fprintf(fp, " %s", buf); | |
+ snprintf(path, sizeof(path), "commit/%s.html", buf); | |
+ fp = efopen(path, "w+b"); | |
+ | |
+ writeheader(fp); | |
+ printcommit(fp, commit); | |
+ | |
+ error = git_commit_parent(&parent, commit, 0); | |
+ if (error) | |
+ return; | |
+ | |
+ error = git_commit_tree(&commit_tree, commit); | |
+ if (error) | |
+ return; | |
+ error = git_commit_tree(&parent_tree, parent); | |
+ if (error) | |
+ return; | |
+ | |
+ error = git_diff_tree_to_tree(&diff, repo, commit_tree, parent_tree, N… | |
+ if (error) | |
+ return; | |
+ | |
+ /* TODO: diff stat (files list and insertions/deletions) */ | |
+ | |
+ ndeltas = git_diff_num_deltas(diff); | |
+ for (i = 0; i < ndeltas; i++) { | |
+ if (git_patch_from_diff(&patch, diff, i)) { | |
+ git_patch_free(patch); | |
+ break; /* TODO: handle error */ | |
} | |
- fprintf(fp, "\n"); | |
- } | |
- if ((sig = git_commit_author(commit)) != NULL) { | |
- fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n", | |
- sig->name, sig->name, sig->email); | |
- printtime(fp, &sig->when, "Date: "); | |
- } | |
- fprintf(fp, "\n"); | |
- for (scan = git_commit_message(commit); scan && *scan;) { | |
- for (eol = scan; *eol && *eol != '\n'; ++eol) /* find e… | |
- ; | |
+ delta = git_patch_get_delta(patch); | |
+ fprintf(fp, "diff --git a/<a href=\"%s%s\">%s</a> b/<a href=\"… | |
+ relpath, delta->old_file.path, delta->old_file.path, | |
+ relpath, delta->new_file.path, delta->new_file.path); | |
- fprintf(fp, " %.*s\n", (int) (eol - scan), scan); | |
- scan = *eol ? eol + 1 : NULL; | |
+#if 0 | |
+ switch (delta->flags) { | |
+ case GIT_DIFF_FLAG_BINARY: continue; /* TODO: binary dat… | |
+ case GIT_DIFF_FLAG_NOT_BINARY: break; | |
+ case GIT_DIFF_FLAG_VALID_ID: break; /* TODO: check */ | |
+ case GIT_DIFF_FLAG_EXISTS: break; /* TODO: check */ | |
+ } | |
+#endif | |
+ | |
+ nhunks = git_patch_num_hunks(patch); | |
+ for (j = 0; j < nhunks; j++) { | |
+ if (git_patch_get_hunk(&hunk, &nhunklines, patch, j)) | |
+ break; /* TODO: handle error ? */ | |
+ | |
+ fprintf(fp, "%s\n", hunk->header); | |
+ | |
+ for (k = 0; ; k++) { | |
+ if (git_patch_get_line_in_hunk(&line, patch, j… | |
+ break; | |
+ if (line->old_lineno == -1) | |
+ fputc('+', fp); | |
+ else if (line->new_lineno == -1) | |
+ fputc('-', fp); | |
+ else | |
+ fputc(' ', fp); | |
+ xmlencode(fp, line->content, line->content_len… | |
+ } | |
+ } | |
+ git_patch_free(patch); | |
} | |
- fprintf(fp, "\n"); | |
+ git_diff_free(diff); | |
+ | |
+ writefooter(fp); | |
+ fclose(fp); | |
} | |
int | |
-writeheader(FILE *fp) | |
+writelog(FILE *fp) | |
{ | |
- fprintf(fp, "<!DOCTYPE HTML>" | |
- "<html dir=\"ltr\" lang=\"en\"><head>" | |
- "<meta http-equiv=\"Content-Type\" content=\"text/html; charse… | |
- "<meta http-equiv=\"Content-Language\" content=\"en\" />"); | |
- fprintf(fp, "<title>%s%s%s</title>", name, description[0] ? " - " : ""… | |
- fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.c… | |
- "</head><body><center>"); | |
- fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath… | |
- fprintf(fp, "<span class=\"desc\">%s</span><br/>", description); | |
- fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath); | |
- fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath); | |
- fprintf(fp, "<a href=\"%sstats.html\">Stats</a>", relpath); | |
- if (hasreadme) | |
- fprintf(fp, " | <a href=\"%sreadme.html\">README</a>", relpath… | |
- if (haslicense) | |
- fprintf(fp, " | <a href=\"%slicense.html\">LICENSE</a>", relpa… | |
- fprintf(fp, "</center><hr/><pre>"); | |
+ git_revwalk *w = NULL; | |
+ git_oid id; | |
+ git_commit *c = NULL; | |
+ size_t i; | |
- return 0; | |
-} | |
+ mkdir("commit", 0755); | |
-int | |
-writefooter(FILE *fp) | |
-{ | |
- fprintf(fp, "</pre></body></html>"); | |
+ git_revwalk_new(&w, repo); | |
+ git_revwalk_push_head(w); | |
+ | |
+ i = 0; | |
+ while (!git_revwalk_next(&id, w)) { | |
+ if (git_commit_lookup(&c, repo, &id)) | |
+ return 1; /* TODO: error */ | |
+ printcommit(fp, c); | |
+ printshowfile(c); | |
+ git_commit_free(c); | |
+ | |
+ /* DEBUG */ | |
+ i++; | |
+ if (i > 100) | |
+ break; | |
+ } | |
+ git_revwalk_free(w); | |
return 0; | |
} | |
+#if 0 | |
int | |
-writelog(FILE *fp) | |
+writeatom(FILE *fp) | |
{ | |
git_revwalk *w = NULL; | |
git_oid id; | |
@@ -210,14 +308,16 @@ writelog(FILE *fp) | |
while (!git_revwalk_next(&id, w)) { | |
if (git_commit_lookup(&c, repo, &id)) | |
- return 1; | |
+ return 1; /* TODO: error */ | |
printcommit(fp, c); | |
+ printshowfile(c); | |
git_commit_free(c); | |
} | |
git_revwalk_free(w); | |
return 0; | |
} | |
+#endif | |
int | |
writefiles(FILE *fp) | |
@@ -251,7 +351,9 @@ writebranches(FILE *fp) | |
git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL); | |
while ((status = git_branch_next(&branchref, &branchtype, branchit)) =… | |
- git_reference_normalize_name(branchbuf, sizeof(branchbuf), git… | |
+ git_reference_normalize_name(branchbuf, sizeof(branchbuf), | |
+ git_reference_name(branchref), | |
+ GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC… | |
/* fprintf(fp, "branch: |%s|\n", branchbuf); */ | |
} | |
@@ -337,12 +439,18 @@ main(int argc, char *argv[]) | |
hasreadme = 1; | |
} | |
- fp = efopen("logs.html", "w+b"); | |
+ fp = efopen("log.html", "w+b"); | |
writeheader(fp); | |
writelog(fp); | |
writefooter(fp); | |
fclose(fp); | |
+#if 0 | |
+ fp = efopen("atom.xml", "w+b"); | |
+ writeatom(fp); | |
+ fclose(fp); | |
+#endif | |
+ | |
fp = efopen("files.html", "w+b"); | |
writeheader(fp); | |
writefiles(fp); |