Commit: d80a163acd47df2bd9ab145be6b249814aa9eceb
Parent: 693c06448972f049d74addbd4942365cd37d92e4
Author: Hiltjo Posthuma
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:
M | stagit.1 | | | 6 | ++++-- |
M | stagit.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 */