refactor get reference, add another feed for tags/releases
A separate Atom feed is helpful to ports maintainers to monitor new tags/releases.
This commit is contained in:
parent
693c064489
commit
d80a163acd
2 changed files with 146 additions and 86 deletions
6
stagit.1
6
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
|
||||
|
|
226
stagit.c
226
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 */
|
||||
|
|
Loading…
Reference in a new issue