stagit

static git page generator
git clone git://git.codemadness.org/stagit
Log | Files | Refs | README | LICENSE

commit d80a163acd47df2bd9ab145be6b249814aa9eceb
parent 693c06448972f049d74addbd4942365cd37d92e4
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sun, 19 Jul 2020 16:41:10 +0200

refactor get reference, add another feed for tags/releases

A separate Atom feed is helpful to ports maintainers to monitor new
tags/releases.

Diffstat:
Mstagit.1 | 6++++--
Mstagit.c | 226++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
2 files changed, 146 insertions(+), 86 deletions(-)

diff --git a/stagit.1 b/stagit.1 @@ -1,4 +1,4 @@ -.Dd February 6, 2019 +.Dd July 19, 2020 .Dt STAGIT 1 .Os .Sh NAME @@ -42,7 +42,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 diff --git a/stagit.c b/stagit.c @@ -248,6 +248,104 @@ err: return NULL; } +int +refs_cmp(const void *v1, const void *v2) +{ + struct referenceinfo *r1 = (struct referenceinfo *)v1; + struct referenceinfo *r2 = (struct referenceinfo *)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) { @@ -361,6 +459,8 @@ writeheader(FILE *fp, const char *title) fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\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); fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); fputs("</head>\n<body>\n<table><tr><td>", fp); fprintf(fp, "<a href=\"../%s\"><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></a>", @@ -680,7 +780,7 @@ err: } void -printcommitatom(FILE *fp, struct commitinfo *ci) +printcommitatom(FILE *fp, struct commitinfo *ci, const char *tag) { fputs("<entry>\n", fp); @@ -697,6 +797,11 @@ printcommitatom(FILE *fp, struct commitinfo *ci) } if (ci->summary) { fputs("<title type=\"text\">", fp); + if (tag) { + fputs("[", fp); + xmlencode(fp, tag, strlen(tag)); + fputs("] ", fp); + } xmlencode(fp, ci->summary, strlen(ci->summary)); fputs("</title>\n", fp); } @@ -732,8 +837,10 @@ printcommitatom(FILE *fp, struct commitinfo *ci) } 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; @@ -746,17 +853,34 @@ 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); + /* 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 { + /* references: tags */ + if (getrefs(&ris, &refcount) != -1) { + for (i = 0; i < refcount; i++) { + if (!git_reference_is_tag(ris[i].ref)) + continue; - for (i = 0; i < m && !git_revwalk_next(&id, w); i++) { - if (!(ci = commitinfo_getbyoid(&id))) - break; - printcommitatom(fp, ci); - commitinfo_free(ci); + 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); @@ -942,85 +1066,18 @@ writefiles(FILE *fp, const git_oid *id) } int -refs_cmp(const void *v1, const void *v2) -{ - struct referenceinfo *r1 = (struct referenceinfo *)v1; - struct referenceinfo *r2 = (struct referenceinfo *)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 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; size_t count, i, j, refcount; const char *titles[] = { "Branches", "Tags" }; const char *ids[] = { "branches", "tags" }; 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); ) { - 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); - for (i = 0, j = 0, count = 0; i < refcount; i++) { if (j == 0 && git_reference_is_tag(ris[i].ref)) { if (count) @@ -1056,10 +1113,6 @@ writerefs(FILE *fp) if (count) fputs("</tbody></table><br/>\n", fp); -err: - git_object_free(obj); - git_reference_free(dref); - for (i = 0; i < refcount; i++) { commitinfo_free(ris[i].ci); git_reference_free(ris[i].ref); @@ -1272,7 +1325,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 */