refactor get reference, add another feed for tags/releases
authorHiltjo Posthuma <hiltjo@codemadness.org>
Sun, 19 Jul 2020 14:41:10 +0000 (16:41 +0200)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Sun, 19 Jul 2020 14:41:10 +0000 (16:41 +0200)
A separate Atom feed is helpful to ports maintainers to monitor new
tags/releases.

stagit.1
stagit.c

index 360f7166826423c27b98044f285669ddfbe25820..f5adaf26e4514f58034537d39cdb2b1f25c9d187 100644 (file)
--- 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
index b4f3b22961e67e13fceb2d38c7e8c7bd60c8ab26..ff81b53221eaae64de22a35e292f9157331b1d2c 100644 (file)
--- 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);
 
@@ -941,86 +1065,19 @@ writefiles(FILE *fp, const git_oid *id)
        return ret;
 }
 
-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 */