commit d0fd6f19ba2e5a51e9e090f0ac6d4b0d5902b6d1
parent ed29611947530f1a1542a9532710b2145149c799
Author: gearsix <gearsix@tuta.io>
Date: Wed, 7 Apr 2021 10:55:21 +0100
upstream merge
Squashed commit of the following:
commit 295e4b8cb95114bb74b582c7332bc4c171f36dd3
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu Mar 25 18:13:13 2021 +0100
add function to print a single line, ignoring \r and \n
This can happen when there is no newline at end of file in the diff which is
served by libgit2 as:
"\n\ No newline at end of file\n".
commit 995f7d5c5d8e396b06e70b1497ac96df63ffec36
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Mar 19 11:29:53 2021 +0100
add meta viewport on stagit-index too
Patch by Oscar Benedito, thanks!
commit f46405850133e43dcae95e0a41b74bcca7b10027
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Mar 14 16:23:58 2021 +0100
bump version to 0.9.5
commit c4d5fecc40e51ab4667315bd11dabd2023e357f3
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Mar 5 12:47:08 2021 +0100
LICENSE: update
commit 5ced189f1993fc17ae683f0a542218db7be7267b
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Mar 5 12:44:48 2021 +0100
change STAGIT_BASEURL to an -u option and also update the example script
commit 7968c0bc9c0172bd654e1f87d8194aef7fb69865
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Mar 5 11:51:21 2021 +0100
add $STAGIT_BASEURL environment variable to make Atom links absolute
With feedback from adc, thanks!
commit d1c528fb5ad81c876f07a69e1b759764f69cb9de
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Mar 5 11:50:16 2021 +0100
README: mention tags.xml feature
commit 722f8364601d2b6ee2439b42cd75750f6aac90ed
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat Jan 9 14:59:53 2021 +0100
micro-optimization: fputc (function) -> putc (macro/inline function)
commit 5044ddeea3c77fea97daa62d51593d73b0e08413
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Fri Jan 8 14:32:33 2021 +0100
LICENSE: bump year
commit e1c0aebde443979a524a944027b81f84f4323ff3
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat Nov 28 12:28:05 2020 +0100
fix warning with libgit2 v0.99+, remain compatible with older versions
git_blob_rawsize now returns with git_object_size_t (unsigned). This was
git_off_t (signed).
In my current version 1.1.0:
types.h:typedef uint64_t git_object_size_t;
v0.28.5:
https://libgit2.org/libgit2/#v0.28.5/group/blob/git_blob_rawsize
changed from v0.99 onwards:
https://libgit2.org/libgit2/#v0.99.0/group/blob/git_blob_rawsize
Fix: use size_t to remain compatible (with a possible warning in older
versions), since git_object_size_t is a new defined type.
This assumes size_t is atleast uint32_t / uint64_t size.
Adapted from a patch by Augustin Fabre <augustin@augfab.fr>, thanks!
commit 66df204c440de3b0cf3442d3a0c719016cdcf9c6
Author: Oscar Benedito <oscar@oscarbenedito.com>
Date: Mon Nov 16 23:24:32 2020 +0100
add abbreviated commit hash to submodule file
commit a63645a5ea4e60523c0024f69c627f586b601d82
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 21:11:46 2020 +0100
add meta viewport for scaling on mobile
Patch by Augustin Fabre <augustin@augfab.fr>
commit ae41add24a87027343e3a6f7eea19f3902af4a12
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 21:11:10 2020 +0100
style.css: improve contrast
https://webaim.org/resources/contrastchecker/?fcolor=555555&bcolor=FFFFFF
Patch by Augustin Fabre <augustin@augfab.fr> and adapted.
commit fc5ef41165df39d6def252e5230a63cc6839bfc1
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 20:59:34 2020 +0100
use size_t to count lines
commit 4f60446c011b45e862540c97b684c62fd8dc3c60
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 20:58:58 2020 +0100
avoid shadowed `name' global variable
by Augustin Fabre <augustin@augfab.fr>
commit 9467f347a2224ac95b96ef5c74d50a4e2aad5241
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 20:58:41 2020 +0100
refs_cmp: remove unneeded cast
commit 3e7865f8f9ef87f622a7a94e7ae70355753ee66a
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Nov 15 20:58:02 2020 +0100
use LEN() macros for arrays
from Augustin Fabre <augustin@augfab.fr>
commit 75555cd99ee4d5df765f7dd6f0d09f2f925be725
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon Aug 17 16:09:33 2020 +0200
bump version to 0.9.4
commit 5334f3e0009bb7d5835c3bad60db507bfd146930
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon Aug 10 16:09:46 2020 +0200
fix a small memleak in writeatom()
non-tag references were not freed.
commit dc0709f6f4f7e256e27272cb0b8611715caf1f3b
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sat Aug 8 20:01:05 2020 +0200
stagit-index: remove unveil support for argv
This can reach the unveil argument limits and it is not a good case for using
unveil.
commit 174a763058f9a90831ab5a2aeb1c9bfbecdabf48
Author: kst <nil@krj.st>
Date: Wed Aug 5 22:11:18 2020 +0000
fix submodule lookup in bare repos
git_submodule_lookup does not work without a working tree [1], so the
current approach fails to recognize any submodules in bare repos.
Instead, notice that
$ git ls-tree HEAD
lists any submodules as commit objects regardless of a working tree.
This is the only instance commit object is used in a tree, so we will
use this to check for submodules.
[1]: https://github.com/libgit2/libgit2/pull/4305/files
commit f05e6b0fcb3b874180970d06ebcde05fb5aea470
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Mon Jul 20 14:15:12 2020 +0200
regression: do not show unset or empty tags
commit d80a163acd47df2bd9ab145be6b249814aa9eceb
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Jul 19 16:41:10 2020 +0200
refactor get reference, add another feed for tags/releases
A separate Atom feed is helpful to ports maintainers to monitor new
tags/releases.
commit 693c06448972f049d74addbd4942365cd37d92e4
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Sun Jul 19 14:07:54 2020 +0200
sort branches and tags by time (descending)
In general version tags are done in chronological order, so this will have a
better sorting for tagged (versioned) releases.
Request from Caltlgin Stsodaat and others, thanks!
Diffstat:
9 files changed, 267 insertions(+), 160 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,7 +1,6 @@
MIT/X Consortium License
-(c) 2015-2019 Hiltjo Posthuma <hiltjo@codemadness.org>
-(c) 2015-2016 Dimitris Papastamos <sin@2f30.org>
+(c) 2015-2021 Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
.POSIX:
NAME = stagit
-VERSION = 0.9.3
+VERSION = 0.9.5
# paths
PREFIX = /usr/local
diff --git a/README b/README
@@ -173,7 +173,8 @@ Features
- Show references: local branches and tags.
- Detect README and LICENSE file from HEAD and link it as a webpage.
- Detect submodules (.gitmodules file) from HEAD and link it as a webpage.
-- Atom feed log (atom.xml).
+- Atom feed of the commit log (atom.xml).
+- Atom feed of the tags/refs (tags.xml).
- Make index page for multiple repositories with stagit-index.
- After generating the pages (relatively slow) serving the files is very fast,
simple and requires little resources (because the content is static), only
diff --git a/example_create.sh b/example_create.sh
@@ -31,7 +31,7 @@ for dir in "${reposdir}/"*/; do
mkdir -p "${curdir}/${d}"
cd "${curdir}/${d}" || continue
- stagit -c ".cache" "${reposdir}/${r}"
+ stagit -c ".cache" -u "https://git.codemadness.nl/$d/" "${reposdir}/${r}"
# symlinks
ln -sf log.html index.html
diff --git a/example_post-receive.sh b/example_post-receive.sh
@@ -64,7 +64,7 @@ fi
stagit-index "${reposdir}/"*/ > "${destdir}/index.html"
# make pages.
-stagit -c "${cachefile}" "${reposdir}/${r}"
+stagit -c "${cachefile}" -u "https://git.codemadness.nl/$d/" "${reposdir}/${r}"
ln -sf log.html index.html
ln -sf ../style.css style.css
diff --git a/stagit-index.c b/stagit-index.c
@@ -43,7 +43,7 @@ xmlencode(FILE *fp, const char *s, size_t len)
case '\'': fputs("'" , fp); break;
case '&': fputs("&", fp); break;
case '"': fputs(""", fp); break;
- default: fputc(*s, fp);
+ default: putc(*s, fp);
}
}
}
@@ -68,6 +68,7 @@ writeheader(FILE *fp)
fputs("<!DOCTYPE html>\n"
"<html>\n<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n"
"<title>", fp);
xmlencode(fp, description, strlen(description));
fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", rootpath);
@@ -159,10 +160,6 @@ main(int argc, char *argv[])
git_libgit2_init();
#ifdef __OpenBSD__
- for (i = 1; i < argc; i++)
- if (unveil(argv[i], "r") == -1)
- err(1, "unveil: %s", argv[i]);
-
if (pledge("stdio rpath", NULL) == -1)
err(1, "pledge");
#endif
diff --git a/stagit.1 b/stagit.1
@@ -1,4 +1,4 @@
-.Dd February 6, 2019
+.Dd March 5, 2021
.Dt STAGIT 1
.Os
.Sh NAME
@@ -8,6 +8,7 @@
.Nm
.Op Fl c Ar cachefile
.Op Fl l Ar commits
+.Op Fl u Ar baseurl
.Ar repodir
.Sh DESCRIPTION
.Nm
@@ -31,6 +32,9 @@ Write a maximum number of
.Ar commits
to the log.html file only.
However the commit files are written as usual.
+.It Fl u Ar baseurl
+Base URL to make links in the Atom feeds absolute.
+For example: "https://git.codemadness.org/stagit/".
.El
.Pp
The options
@@ -42,7 +46,9 @@ cannot be used at the same time.
The following files will be written:
.Bl -tag -width Ds
.It atom.xml
-Atom XML feed
+Atom XML feed of the last 100 commits.
+.It tags.xml
+Atom XML feed of the tags.
.It files.html
List of files in the latest tree, linking to the file.
.It log.html
@@ -101,6 +107,8 @@ favicon image.
.It style.css
CSS stylesheet.
.El
+.Sh EXIT STATUS
+.Ex -std
.Sh SEE ALSO
.Xr stagit-index 1
.Sh AUTHORS
diff --git a/stagit.c b/stagit.c
@@ -16,6 +16,8 @@
#include "compat.h"
+#define LEN(s) (sizeof(s)/sizeof(*s))
+
struct deltainfo {
git_patch *patch;
@@ -48,9 +50,16 @@ struct commitinfo {
size_t ndeltas;
};
+/* reference and associated data for sorting */
+struct referenceinfo {
+ struct git_reference *ref;
+ struct commitinfo *ci;
+};
+
static git_repository *repo;
static const char *rootpath = "/";
+static const char *baseurl = ""; /* base URL to make absolute RSS/Atom URI */
static const char *relpath = "";
static const char *repodir;
@@ -243,13 +252,110 @@ err:
return NULL;
}
+int
+refs_cmp(const void *v1, const void *v2)
+{
+ const struct referenceinfo *r1 = v1, *r2 = v2;
+ time_t t1, t2;
+ int r;
+
+ if ((r = git_reference_is_tag(r1->ref) - git_reference_is_tag(r2->ref)))
+ return r;
+
+ t1 = r1->ci->author ? r1->ci->author->when.time : 0;
+ t2 = r2->ci->author ? r2->ci->author->when.time : 0;
+ if ((r = t1 > t2 ? -1 : (t1 == t2 ? 0 : 1)))
+ return r;
+
+ return strcmp(git_reference_shorthand(r1->ref),
+ git_reference_shorthand(r2->ref));
+}
+
+int
+getrefs(struct referenceinfo **pris, size_t *prefcount)
+{
+ struct referenceinfo *ris = NULL;
+ struct commitinfo *ci = NULL;
+ git_reference_iterator *it = NULL;
+ const git_oid *id = NULL;
+ git_object *obj = NULL;
+ git_reference *dref = NULL, *r, *ref = NULL;
+ size_t i, refcount;
+
+ *pris = NULL;
+ *prefcount = 0;
+
+ if (git_reference_iterator_new(&it, repo))
+ return -1;
+
+ for (refcount = 0; !git_reference_next(&ref, it); ) {
+ if (!git_reference_is_branch(ref) && !git_reference_is_tag(ref)) {
+ git_reference_free(ref);
+ ref = NULL;
+ continue;
+ }
+
+ switch (git_reference_type(ref)) {
+ case GIT_REF_SYMBOLIC:
+ if (git_reference_resolve(&dref, ref))
+ goto err;
+ r = dref;
+ break;
+ case GIT_REF_OID:
+ r = ref;
+ break;
+ default:
+ continue;
+ }
+ if (!git_reference_target(r) ||
+ git_reference_peel(&obj, r, GIT_OBJ_ANY))
+ goto err;
+ if (!(id = git_object_id(obj)))
+ goto err;
+ if (!(ci = commitinfo_getbyoid(id)))
+ break;
+
+ if (!(ris = reallocarray(ris, refcount + 1, sizeof(*ris))))
+ err(1, "realloc");
+ ris[refcount].ci = ci;
+ ris[refcount].ref = r;
+ refcount++;
+
+ git_object_free(obj);
+ obj = NULL;
+ git_reference_free(dref);
+ dref = NULL;
+ }
+ git_reference_iterator_free(it);
+
+ /* sort by type, date then shorthand name */
+ qsort(ris, refcount, sizeof(*ris), refs_cmp);
+
+ *pris = ris;
+ *prefcount = refcount;
+
+ return 0;
+
+err:
+ git_object_free(obj);
+ git_reference_free(dref);
+ commitinfo_free(ci);
+ for (i = 0; i < refcount; i++) {
+ commitinfo_free(ris[i].ci);
+ git_reference_free(ris[i].ref);
+ }
+ free(ris);
+
+ return -1;
+}
+
FILE *
-efopen(const char *name, const char *flags)
+efopen(const char *filename, const char *flags)
{
FILE *fp;
- if (!(fp = fopen(name, flags)))
- err(1, "fopen: '%s'", name);
+ if (!(fp = fopen(filename, flags)))
+ err(1, "fopen: '%s'", filename);
return fp;
}
@@ -267,7 +373,27 @@ xmlencode(FILE *fp, const char *s, size_t len)
case '\'': fputs("'", fp); break;
case '&': fputs("&", fp); break;
case '"': fputs(""", fp); break;
- default: fputc(*s, fp);
+ default: putc(*s, fp);
+ }
+ }
+}
+
+/* Escape characters below as HTML 2.0 / XML 1.0, ignore printing '\n', '\r' */
+void
+xmlencodeline(FILE *fp, const char *s, size_t len)
+{
+ size_t i;
+
+ for (i = 0; *s && i < len; s++, i++) {
+ switch(*s) {
+ case '<': fputs("<", fp); break;
+ case '>': fputs(">", fp); break;
+ case '\'': fputs("'", fp); break;
+ case '&': fputs("&", fp); break;
+ case '"': fputs(""", fp); break;
+ case '\r': break; /* ignore CR */
+ case '\n': break; /* ignore LF */
+ default: putc(*s, fp);
}
}
}
@@ -345,6 +471,7 @@ writeheader(FILE *fp, const char *title)
fputs("<!DOCTYPE html>\n"
"<html>\n<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
+ "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n"
"<title>", fp);
xmlencode(fp, title, strlen(title));
if (title[0] && strippedname[0])
@@ -395,18 +522,18 @@ writefooter(FILE *fp)
fputs("</div>\n</body>\n</html>\n", fp);
}
-int
+size_t
writeblobhtml(FILE *fp, const git_blob *blob)
{
- size_t n = 0, i, prev;
- const char *nfmt = "<a href=\"#l%d\" class=\"line\" id=\"l%d\">%7d</a> ";
+ size_t n = 0, i, len, prev;
+ const char *nfmt = "<a href=\"#l%zu\" class=\"line\" id=\"l%zu\">%7zu</a> ";
const char *s = git_blob_rawcontent(blob);
- git_off_t len = git_blob_rawsize(blob);
+ len = git_blob_rawsize(blob);
fputs("<pre id=\"blob\">\n", fp);
if (len > 0) {
- for (i = 0, prev = 0; i < (size_t)len; i++) {
+ for (i = 0, prev = 0; i < len; i++) {
if (s[i] != '\n')
continue;
n++;
@@ -446,12 +573,12 @@ printcommit(FILE *fp, struct commitinfo *ci)
xmlencode(fp, ci->author->email, strlen(ci->author->email));
fputs("</a>>\n<b>Date:</b> ", fp);
printtime(fp, &(ci->author->when));
- fputc('\n', fp);
+ putc('\n', fp);
}
if (ci->msg) {
- fputc('\n', fp);
+ putc('\n', fp);
xmlencode(fp, ci->msg, strlen(ci->msg));
- fputc('\n', fp);
+ putc('\n', fp);
}
}
@@ -570,8 +697,9 @@ printshowfile(FILE *fp, struct commitinfo *ci)
fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"d\">-",
i, j, k, i, j, k);
else
- fputc(' ', fp);
- xmlencode(fp, line->content, line->content_len);
+ putc(' ', fp);
+ xmlencodeline(fp, line->content, line->content_len);
+ putc('\n', fp);
if (line->old_lineno == -1 || line->new_lineno == -1)
fputs("</a>", fp);
}
@@ -676,7 +804,7 @@ err:
}
void
-printcommitatom(FILE *fp, struct commitinfo *ci)
+printcommitatom(FILE *fp, struct commitinfo *ci, const char *tag)
{
fputs("<entry>\n", fp);
@@ -693,11 +821,16 @@ printcommitatom(FILE *fp, struct commitinfo *ci)
}
if (ci->summary) {
fputs("<title type=\"text\">", fp);
+ if (tag && tag[0]) {
+ fputs("[", fp);
+ xmlencode(fp, tag, strlen(tag));
+ fputs("] ", fp);
+ }
xmlencode(fp, ci->summary, strlen(ci->summary));
fputs("</title>\n", fp);
}
- fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"commit/%s.html\" />\n",
- ci->oid);
+ fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"%scommit/%s.html\" />\n",
+ baseurl, ci->oid);
if (ci->author) {
fputs("<author>\n<name>", fp);
@@ -718,18 +851,20 @@ printcommitatom(FILE *fp, struct commitinfo *ci)
xmlencode(fp, ci->author->email, strlen(ci->author->email));
fputs(">\nDate: ", fp);
printtime(fp, &(ci->author->when));
- fputc('\n', fp);
+ putc('\n', fp);
}
if (ci->msg) {
- fputc('\n', fp);
+ putc('\n', fp);
xmlencode(fp, ci->msg, strlen(ci->msg));
}
fputs("\n</content>\n</entry>\n", fp);
}
int
-writeatom(FILE *fp)
+writeatom(FILE *fp, int all)
{
+ struct referenceinfo *ris = NULL;
+ size_t refcount = 0;
struct commitinfo *ci;
git_revwalk *w = NULL;
git_oid id;
@@ -742,29 +877,42 @@ writeatom(FILE *fp)
xmlencode(fp, description, strlen(description));
fputs("</subtitle>\n", fp);
- git_revwalk_new(&w, repo);
- git_revwalk_push_head(w);
- git_revwalk_simplify_first_parent(w);
-
- for (i = 0; i < m && !git_revwalk_next(&id, w); i++) {
- if (!(ci = commitinfo_getbyoid(&id)))
- break;
- printcommitatom(fp, ci);
- commitinfo_free(ci);
+ /* all commits or only tags? */
+ if (all) {
+ git_revwalk_new(&w, repo);
+ git_revwalk_push_head(w);
+ git_revwalk_simplify_first_parent(w);
+ for (i = 0; i < m && !git_revwalk_next(&id, w); i++) {
+ if (!(ci = commitinfo_getbyoid(&id)))
+ break;
+ printcommitatom(fp, ci, "");
+ commitinfo_free(ci);
+ }
+ git_revwalk_free(w);
+ } else if (getrefs(&ris, &refcount) != -1) {
+ /* references: tags */
+ for (i = 0; i < refcount; i++) {
+ if (git_reference_is_tag(ris[i].ref))
+ printcommitatom(fp, ris[i].ci,
+ git_reference_shorthand(ris[i].ref));
+
+ commitinfo_free(ris[i].ci);
+ git_reference_free(ris[i].ref);
+ }
+ free(ris);
}
- git_revwalk_free(w);
fputs("</feed>\n", fp);
return 0;
}
-int
-writeblob(git_object *obj, const char *fpath, const char *filename, git_off_t filesize)
+size_t
+writeblob(git_object *obj, const char *fpath, const char *filename, size_t filesize)
{
char tmp[PATH_MAX] = "", *d;
const char *p;
- int lc = 0;
+ size_t lc = 0;
FILE *fp;
if (strlcpy(tmp, fpath, sizeof(tmp)) >= sizeof(tmp))
@@ -784,7 +932,7 @@ writeblob(git_object *obj, const char *fpath, const char *filename, git_off_t fi
writeheader(fp, filename);
fputs("<p> ", fp);
xmlencode(fp, filename, strlen(filename));
- fprintf(fp, " (%juB)", (uintmax_t)filesize);
+ fprintf(fp, " (%zuB)", filesize);
fputs("</p><hr/>", fp);
if (git_blob_is_binary((git_blob *)obj)) {
@@ -848,13 +996,11 @@ int
writefilestree(FILE *fp, git_tree *tree, const char *path)
{
const git_tree_entry *entry = NULL;
- git_submodule *module = NULL;
git_object *obj = NULL;
- git_off_t filesize;
const char *entryname;
- char filepath[PATH_MAX], entrypath[PATH_MAX];
- size_t count, i;
- int lc, r, ret;
+ char filepath[PATH_MAX], entrypath[PATH_MAX], oid[8];
+ size_t count, i, lc, filesize;
+ int r, ret;
count = git_tree_entrycount(tree);
for (i = 0; i < count; i++) {
@@ -896,17 +1042,20 @@ writefilestree(FILE *fp, git_tree *tree, const char *path)
xmlencode(fp, entrypath, strlen(entrypath));
fputs("</a></td><td class=\"num\" align=\"right\">", fp);
if (lc > 0)
- fprintf(fp, "%dL", lc);
+ fprintf(fp, "%zuL", lc);
else
- fprintf(fp, "%juB", (uintmax_t)filesize);
+ fprintf(fp, "%zuB", filesize);
fputs("</td></tr>\n", fp);
git_object_free(obj);
- } else if (!git_submodule_lookup(&module, repo, entryname)) {
+ } else if (git_tree_entry_type(entry) == GIT_OBJ_COMMIT) {
+ /* commit object in tree is a submodule */
fprintf(fp, "<tr><td>m---------</td><td><a href=\"%sfile/.gitmodules.html\">",
relpath);
xmlencode(fp, entrypath, strlen(entrypath));
- git_submodule_free(module);
- fputs("</a></td><td class=\"num\" align=\"right\"></td></tr>\n", fp);
+ fputs("</a> @ ", fp);
+ git_oid_tostr(oid, sizeof(oid), git_tree_entry_id(entry));
+ xmlencode(fp, oid, strlen(oid));
+ fputs("</td><td class=\"num\" align=\"right\"></td></tr>\n", fp);
}
}
@@ -938,115 +1087,58 @@ writefiles(FILE *fp, const git_oid *id)
}
int
-refs_cmp(const void *v1, const void *v2)
-{
- git_reference *r1 = (*(git_reference **)v1);
- git_reference *r2 = (*(git_reference **)v2);
- int r;
-
- if ((r = git_reference_is_branch(r1) - git_reference_is_branch(r2)))
- return r;
-
- return strcmp(git_reference_shorthand(r1),
- git_reference_shorthand(r2));
-}
-
-int
writerefs(FILE *fp)
{
+ struct referenceinfo *ris = NULL;
struct commitinfo *ci;
- const git_oid *id = NULL;
- git_object *obj = NULL;
- git_reference *dref = NULL, *r, *ref = NULL;
- git_reference_iterator *it = NULL;
- git_reference **refs = NULL;
size_t count, i, j, refcount;
const char *titles[] = { "Branches", "Tags" };
const char *ids[] = { "branches", "tags" };
- const char *name;
+ const char *s;
- if (git_reference_iterator_new(&it, repo))
+ if (getrefs(&ris, &refcount) == -1)
return -1;
- for (refcount = 0; !git_reference_next(&ref, it); refcount++) {
- if (!(refs = reallocarray(refs, refcount + 1, sizeof(git_reference *))))
- err(1, "realloc");
- refs[refcount] = ref;
- }
- git_reference_iterator_free(it);
-
- /* sort by type then shorthand name */
- qsort(refs, refcount, sizeof(git_reference *), refs_cmp);
-
- for (j = 0; j < 2; j++) {
- for (i = 0, count = 0; i < refcount; i++) {
- if (!(git_reference_is_branch(refs[i]) && j == 0) &&
- !(git_reference_is_tag(refs[i]) && j == 1))
- continue;
-
- switch (git_reference_type(refs[i])) {
- case GIT_REF_SYMBOLIC:
- if (git_reference_resolve(&dref, refs[i]))
- goto err;
- r = dref;
- break;
- case GIT_REF_OID:
- r = refs[i];
- break;
- default:
- continue;
- }
- if (!git_reference_target(r) ||
- git_reference_peel(&obj, r, GIT_OBJ_ANY))
- goto err;
- if (!(id = git_object_id(obj)))
- goto err;
- if (!(ci = commitinfo_getbyoid(id)))
- break;
-
- /* print header if it has an entry (first). */
- if (++count == 1) {
- fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
- "<thead>\n<tr><td><b>Name</b></td>"
- "<td><b>Last commit date</b></td>"
- "<td><b>Author</b></td>\n</tr>\n"
- "</thead><tbody>\n",
- titles[j], ids[j]);
- }
-
- relpath = "";
- name = git_reference_shorthand(r);
-
- fputs("<tr><td>", fp);
- xmlencode(fp, name, strlen(name));
- fputs("</td><td>", fp);
- if (ci->author)
- printtimeshort(fp, &(ci->author->when));
- fputs("</td><td>", fp);
- if (ci->author)
- xmlencode(fp, ci->author->name, strlen(ci->author->name));
- fputs("</td></tr>\n", fp);
-
- relpath = "../";
+ for (i = 0, j = 0, count = 0; i < refcount; i++) {
+ if (j == 0 && git_reference_is_tag(ris[i].ref)) {
+ if (count)
+ fputs("</tbody></table><br/>\n", fp);
+ count = 0;
+ j = 1;
+ }
- commitinfo_free(ci);
- git_object_free(obj);
- obj = NULL;
- git_reference_free(dref);
- dref = NULL;
+ /* print header if it has an entry (first). */
+ if (++count == 1) {
+ fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
+ "<thead>\n<tr><td><b>Name</b></td>"
+ "<td><b>Last commit date</b></td>"
+ "<td><b>Author</b></td>\n</tr>\n"
+ "</thead><tbody>\n",
+ titles[j], ids[j]);
}
- /* table footer */
- if (count)
- fputs("</tbody></table><br/>", fp);
- }
-err:
- git_object_free(obj);
- git_reference_free(dref);
+ ci = ris[i].ci;
+ s = git_reference_shorthand(ris[i].ref);
+
+ fputs("<tr><td>", fp);
+ xmlencode(fp, s, strlen(s));
+ fputs("</td><td>", fp);
+ if (ci->author)
+ printtimeshort(fp, &(ci->author->when));
+ fputs("</td><td>", fp);
+ if (ci->author)
+ xmlencode(fp, ci->author->name, strlen(ci->author->name));
+ fputs("</td></tr>\n", fp);
+ }
+ /* table footer */
+ if (count)
+ fputs("</tbody></table><br/>\n", fp);
- for (i = 0; i < refcount; i++)
- git_reference_free(refs[i]);
- free(refs);
+ for (i = 0; i < refcount; i++) {
+ commitinfo_free(ris[i].ci);
+ git_reference_free(ris[i].ref);
+ }
+ free(ris);
return 0;
}
@@ -1054,7 +1146,8 @@ err:
void
usage(char *argv0)
{
- fprintf(stderr, "%s [-c cachefile | -l commits] repodir\n", argv0);
+ fprintf(stderr, "%s [-c cachefile | -l commits] "
+ "[-u baseurl] repodir\n", argv0);
exit(1);
}
@@ -1087,6 +1180,10 @@ main(int argc, char *argv[])
if (argv[i][0] == '\0' || *p != '\0' ||
nlogcommits <= 0 || errno)
usage(argv[0]);
+ } else if (argv[i][1] == 'u') {
+ if (i + 1 >= argc)
+ usage(argv[0]);
+ baseurl = argv[++i];
}
}
if (!repodir)
@@ -1164,7 +1261,7 @@ main(int argc, char *argv[])
}
/* check LICENSE */
- for (i = 0; i < sizeof(licensefiles) / sizeof(*licensefiles) && !license; i++) {
+ for (i = 0; i < LEN(licensefiles) && !license; i++) {
if (!git_revparse_single(&obj, repo, licensefiles[i]) &&
git_object_type(obj) == GIT_OBJ_BLOB)
license = licensefiles[i] + strlen("HEAD:");
@@ -1172,7 +1269,7 @@ main(int argc, char *argv[])
}
/* check README */
- for (i = 0; i < sizeof(readmefiles) / sizeof(*readmefiles) && !readme; i++) {
+ for (i = 0; i < LEN(readmefiles) && !readme; i++) {
if (!git_revparse_single(&obj, repo, readmefiles[i]) &&
git_object_type(obj) == GIT_OBJ_BLOB)
readme = readmefiles[i] + strlen("HEAD:");
@@ -1254,7 +1351,12 @@ main(int argc, char *argv[])
/* Atom feed */
fp = efopen("atom.xml", "w");
- writeatom(fp);
+ writeatom(fp, 1);
+ fclose(fp);
+
+ /* Atom feed for tags / releases */
+ fp = efopen("tags.xml", "w");
+ writeatom(fp, 0);
fclose(fp);
/* rename new cache file on success */
diff --git a/style.css b/style.css
@@ -29,7 +29,7 @@ a.line {
}
#blob a {
- color: #777;
+ color: #555;
}
#blob a:hover {
@@ -70,12 +70,12 @@ td.num {
}
.desc {
- color: #777;
+ color: #555;
}
hr {
border: 0;
- border-top: 1px solid #777;
+ border-top: 1px solid #555;
height: 1px;
}