|
|
sort branches and tags by time (descending) - stagit - static git page generator |
|
|
 |
git clone git://git.codemadness.org/stagit (git://git.codemadness.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
 |
commit 693c06448972f049d74addbd4942365cd37d92e4 |
|
|
 |
parent 467dfeb8f4bf2dd1ddb69e5c9592147acb425aab |
|
|
 |
Author: Hiltjo Posthuma <hiltjo@codemadness.org> (mailto://) |
application/vnd.lotus-organizer |
|
|
Date: Sun, 19 Jul 2020 14:07:54 +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: |
|
|
|
M stagit.c | 164 +++++++++++++++++-------------- |
|
|
|
|
|
|
|
1 file changed, 92 insertions(+), 72 deletions(-) |
|
|
|
--- |
|
|
 |
diff --git a/stagit.c b/stagit.c |
|
|
|
@@ -48,6 +48,12 @@ 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 *relpath = ""; |
|
|
|
@@ -938,113 +944,127 @@ 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); |
|
|
|
+ struct referenceinfo *r1 = (struct referenceinfo *)v1; |
|
|
|
+ struct referenceinfo *r2 = (struct referenceinfo *)v2; |
|
|
|
+ time_t t1, t2; |
|
|
|
int r; |
|
|
|
|
|
|
|
- if ((r = git_reference_is_branch(r1) - git_reference_is_branch(r2))) |
|
|
|
+ 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), |
|
|
|
- git_reference_shorthand(r2)); |
|
|
|
+ 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; |
|
|
|
- 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)) |
|
|
|
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; |
|
|
|
+ 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(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)) |
|
|
|
+ switch (git_reference_type(ref)) { |
|
|
|
+ case GIT_REF_SYMBOLIC: |
|
|
|
+ if (git_reference_resolve(&dref, ref)) |
|
|
|
goto err; |
|
|
|
- if (!(id = git_object_id(obj))) |
|
|
|
- goto err; |
|
|
|
- if (!(ci = commitinfo_getbyoid(id))) |
|
|
|
- break; |
|
|
|
+ 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; |
|
|
|
|
|
|
|
- /* 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]); |
|
|
|
- } |
|
|
|
+ if (!(ris = reallocarray(ris, refcount + 1, sizeof(*ris)))) |
|
|
|
+ err(1, "realloc"); |
|
|
|
+ ris[refcount].ci = ci; |
|
|
|
+ ris[refcount].ref = r; |
|
|
|
+ refcount++; |
|
|
|
|
|
|
|
- relpath = ""; |
|
|
|
- name = git_reference_shorthand(r); |
|
|
|
+ git_object_free(obj); |
|
|
|
+ obj = NULL; |
|
|
|
+ git_reference_free(dref); |
|
|
|
+ dref = NULL; |
|
|
|
+ } |
|
|
|
+ git_reference_iterator_free(it); |
|
|
|
|
|
|
|
- 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); |
|
|
|
+ /* sort by type, date then shorthand name */ |
|
|
|
+ qsort(ris, refcount, sizeof(*ris), refs_cmp); |
|
|
|
|
|
|
|
- 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); |
|
|
|
+ |
|
|
|
+ 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); |
|
|
|
|
|
|
|
err: |
|
|
|
git_object_free(obj); |
|
|
|
git_reference_free(dref); |
|
|
|
|
|
|
|
- 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; |
|
|
|
} |
|