commit 64adeb03d75a920daee7442781ea1b3b1d811ef8
parent de33eb0c24e9b6b9494c882936da539e8a8a2369
Author: Oscar Benedito <oscar@oscarbenedito.com>
Date: Wed, 8 Dec 2021 18:29:57 +0100
Merge tag '1.0'
Diffstat:
7 files changed, 94 insertions(+), 29 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
.POSIX:
NAME = stagit
-VERSION = 0.9.6
+VERSION = 1.0
# paths
PREFIX = /usr/local
diff --git a/README.md b/README.md
@@ -90,7 +90,7 @@ Script:
}'
-Set clone url for a directory of repos
+Set clone URL for a directory of repos
--------------------------------------
#!/bin/sh
diff --git a/example_create.sh b/example_create.sh
@@ -7,7 +7,7 @@
# is included.
# - modify the categories in the for loop with your own.
#
-# - write clone url, for example "git://git.codemadness.org/dir" to the "url"
+# - write clone URL, for example "git://git.codemadness.org/dir" to the "url"
# file for each repo.
# - write owner of repo to the "owner" file.
# - write description in "description" file.
diff --git a/stagit-index.1 b/stagit-index.1
@@ -1,4 +1,4 @@
-.Dd December 26, 2015
+.Dd August 2, 2021
.Dt STAGIT-INDEX 1
.Os
.Sh NAME
@@ -36,6 +36,11 @@ square logo.
.It style.css
CSS stylesheet.
.El
+.Sh EXAMPLES
+.Bd -literal
+cd htmlroot
+stagit-index path/to/gitrepo1 path/to/gitrepo2 > index.html
+.Ed
.Sh SEE ALSO
.Xr stagit 1
.Sh AUTHORS
diff --git a/stagit-index.c b/stagit-index.c
@@ -29,6 +29,28 @@ joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
path, path[0] && path[strlen(path) - 1] != '/' ? "/" : "", path2);
}
+/* Percent-encode, see RFC3986 section 2.1. */
+void
+percentencode(FILE *fp, const char *s, size_t len)
+{
+ static char tab[] = "0123456789ABCDEF";
+ unsigned char uc;
+ size_t i;
+
+ for (i = 0; *s && i < len; s++, i++) {
+ uc = *s;
+ /* NOTE: do not encode '/' for paths */
+ if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') ||
+ uc == '[' || uc == ']') {
+ putc('%', fp);
+ putc(tab[(uc >> 4) & 0x0f], fp);
+ putc(tab[uc & 0x0f], fp);
+ } else {
+ putc(uc, fp);
+ }
+ }
+}
+
/* Escape characters below as HTML 2.0 / XML 1.0. */
void
xmlencode(FILE *fp, const char *s, size_t len)
@@ -122,7 +144,7 @@ writelog(FILE *fp)
*p = '\0';
fputs("<tr class=\"repo\"><td><a href=\"", fp);
- xmlencode(fp, stripped_name, strlen(stripped_name));
+ percentencode(fp, stripped_name, strlen(stripped_name));
fputs("/\">", fp);
xmlencode(fp, stripped_name, strlen(stripped_name));
fputs("</a></td><td>", fp);
diff --git a/stagit.1 b/stagit.1
@@ -1,4 +1,4 @@
-.Dd May 18, 2021
+.Dd August 2, 2021
.Dt STAGIT 1
.Os
.Sh NAME
@@ -92,7 +92,7 @@ description
.It .git/owner or owner (bare repo).
owner of repository
.It .git/url or url (bare repo).
-primary clone url of the repository, for example:
+primary clone URL of the repository, for example:
git://git.codemadness.org/stagit
.El
.Pp
@@ -110,6 +110,15 @@ CSS stylesheet.
.El
.Sh EXIT STATUS
.Ex -std
+.Sh EXAMPLES
+.Bd -literal
+mkdir -p htmlroot/htmlrepo1 && cd htmlroot/htmlrepo1
+stagit path/to/gitrepo1
+# repeat for other repositories.
+.Ed
+.Pp
+To update the HTML files when the repository is changed a git post-receive hook
+can be used, see the file example_post-receive.sh for an example.
.Sh SEE ALSO
.Xr stagit-index 1
.Sh AUTHORS
diff --git a/stagit.c b/stagit.c
@@ -74,7 +74,7 @@ static char *readmefiles[] = { "HEAD:README", "HEAD:README.md" };
static char *readme;
static char *contributefiles[] = { "HEAD:CONTRIBUTING", "HEAD:CONTRIBUTING.md" };
static char *contribute;
-static long long nlogcommits = -1; /* < 0 indicates not used */
+static long long nlogcommits = -1; /* -1 indicates not used */
/* cache */
static git_oid lastoid;
@@ -362,6 +362,28 @@ efopen(const char *filename, const char *flags)
return fp;
}
+/* Percent-encode, see RFC3986 section 2.1. */
+void
+percentencode(FILE *fp, const char *s, size_t len)
+{
+ static char tab[] = "0123456789ABCDEF";
+ unsigned char uc;
+ size_t i;
+
+ for (i = 0; *s && i < len; s++, i++) {
+ uc = *s;
+ /* NOTE: do not encode '/' for paths */
+ if (uc < '/' || uc >= 127 || (uc >= ':' && uc <= '@') ||
+ uc == '[' || uc == ']') {
+ putc('%', fp);
+ putc(tab[(uc >> 4) & 0x0f], fp);
+ putc(tab[uc & 0x0f], fp);
+ } else {
+ putc(uc, fp);
+ }
+ }
+}
+
/* Escape characters below as HTML 2.0 / XML 1.0. */
void
xmlencode(FILE *fp, const char *s, size_t len)
@@ -498,10 +520,11 @@ writeheader(FILE *fp, const char *title)
xmlencode(fp, description, strlen(description));
fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/svg+xml\" href=\"../%slogo.svg\" />\n", relpath);
fprintf(fp, "<link rel=\"alternate icon\" href=\"../%sfavicon.ico\" />\n", relpath);
- fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s Atom Feed\" href=\"%satom.xml\" />\n",
- name, relpath);
- fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s Atom Feed (tags)\" href=\"%stags.xml\" />\n",
- name, relpath);
+ fputs("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"", fp);
+ xmlencode(fp, name, strlen(name));
+ fprintf(fp, " Atom Feed\" href=\"%satom.xml\" />\n", relpath);
+ fputs("<link rel=\"alternate\" type=\"application/atom+xml\" title=\"", fp);
+ fprintf(fp, " Atom Feed (tags)\" href=\"%stags.xml\" />\n", relpath);
fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"../%sstyle.css\" />\n", relpath);
fputs("</head>\n<body>\n<div id=\"head\"><table><tr><td>", fp);
fprintf(fp, "<a class=\"logo\" href=\"../%s\"><img src=\"../%slogo.svg\" alt=\"\" width=\"32\" height=\"32\" /></a>",
@@ -513,7 +536,7 @@ writeheader(FILE *fp, const char *title)
fputs("</span>\n", fp);
if (cloneurl[0]) {
fputs("<p class=\"url\">git clone <a href=\"", fp);
- xmlencode(fp, cloneurl, strlen(cloneurl));
+ xmlencode(fp, cloneurl, strlen(cloneurl)); /* not percent-encoded */
fputs("\">", fp);
xmlencode(fp, cloneurl, strlen(cloneurl));
fputs("</a></p>\n", fp);
@@ -558,14 +581,15 @@ writeblobhtml(FILE *fp, const git_blob *blob)
continue;
n++;
fprintf(fp, nfmt, n, n, n);
- xmlencode(fp, &s[prev], i - prev + 1);
+ xmlencodeline(fp, &s[prev], i - prev + 1);
+ putc('\n', fp);
prev = i + 1;
}
/* trailing data */
if ((len - prev) > 0) {
n++;
fprintf(fp, nfmt, n, n, n);
- xmlencode(fp, &s[prev], len - prev);
+ xmlencodeline(fp, &s[prev], len - prev);
}
}
@@ -588,7 +612,7 @@ printcommit(FILE *fp, struct commitinfo *ci)
fputs("<b>Author:</b> ", fp);
xmlencode(fp, ci->author->name, strlen(ci->author->name));
fputs(" <<a href=\"mailto:", fp);
- xmlencode(fp, ci->author->email, strlen(ci->author->email));
+ xmlencode(fp, ci->author->email, strlen(ci->author->email)); /* not percent-encoded */
fputs("\">", fp);
xmlencode(fp, ci->author->email, strlen(ci->author->email));
fputs("</a>>\n<b>Date:</b> ", fp);
@@ -683,11 +707,11 @@ printshowfile(FILE *fp, struct commitinfo *ci)
patch = ci->deltas[i]->patch;
delta = git_patch_get_delta(patch);
fprintf(fp, "<b>diff --git a/<a id=\"h%zu\" href=\"%sfile/", i, relpath);
- xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
+ percentencode(fp, delta->old_file.path, strlen(delta->old_file.path));
fputs(".html\">", fp);
xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));
fprintf(fp, "</a> b/<a href=\"%sfile/", relpath);
- xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
+ percentencode(fp, delta->new_file.path, strlen(delta->new_file.path));
fprintf(fp, ".html\">");
xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));
fprintf(fp, "</a></b>\n");
@@ -759,6 +783,7 @@ writelog(FILE *fp, const git_oid *oid)
git_oid id;
char path[PATH_MAX], oidstr[GIT_OID_HEXSZ + 1];
FILE *fpfile;
+ size_t remcommits = 0;
int r;
git_revwalk_new(&w, repo);
@@ -778,8 +803,11 @@ writelog(FILE *fp, const git_oid *oid)
/* optimization: if there are no log lines to write and
the commit file already exists: skip the diffstat */
- if (!nlogcommits && !r)
- continue;
+ if (!nlogcommits) {
+ remcommits++;
+ if (!r)
+ continue;
+ }
if (!(ci = commitinfo_getbyoid(&id)))
break;
@@ -787,15 +815,10 @@ writelog(FILE *fp, const git_oid *oid)
if (commitinfo_getstats(ci) == -1)
goto err;
- if (nlogcommits < 0) {
- writelogline(fp, ci);
- } else if (nlogcommits > 0) {
+ if (nlogcommits != 0) {
writelogline(fp, ci);
- nlogcommits--;
- if (!nlogcommits && ci->parentoid[0])
- fputs("<tr><td></td><td colspan=\"5\">"
- "More commits remaining [...]</td>"
- "</tr>\n", fp);
+ if (nlogcommits > 0)
+ nlogcommits--;
}
if (cachefile)
@@ -817,6 +840,12 @@ err:
}
git_revwalk_free(w);
+ if (nlogcommits == 0 && remcommits != 0) {
+ fprintf(fp, "<tr><td></td><td colspan=\"5\">"
+ "%zu more commits remaining, fetch the repository"
+ "</td></tr>\n", remcommits);
+ }
+
relpath = "";
return 0;
@@ -1135,7 +1164,7 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
if (git_object_type(obj) == GIT_OBJ_TREE)
fputs("class=\"dir\" ", fp);
fprintf(fp, "href=\"%s", relpath);
- xmlencode(fp, filepath, strlen(filepath));
+ percentencode(fp, filepath, strlen(filepath));
fputs("\">", fp);
xmlencode(fp, entryname, strlen(entryname));
fputs("</a></td><td class=\"num\" align=\"right\">", fp);