stagit

git site generator
Contents

refactor get reference, add another feed for tags/releases

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

Hiltjo Posthuma hiltjo@codemadness.org

commit: ed5ebde parent: e654152
2 files changed, 146 insertions(+), 86 deletions(-)
Mstagit.1+4-2
Mstagit.c+142-84
M · stagit.1 +4, -2
 1@@ -1,4 +1,4 @@
 2-.Dd February 6, 2019
 3+.Dd July 19, 2020
 4 .Dt STAGIT 1
 5 .Os
 6 .Sh NAME
 7@@ -42,7 +42,9 @@ cannot be used at the same time.
 8 The following files will be written:
 9 .Bl -tag -width Ds
10 .It atom.xml
11-Atom XML feed
12+Atom XML feed of the
last 100 commits.
13+.It tags.xml
14+Atom XML feed of the
tags.
15 .It files.html
16 List of files in
the latest tree, linking to the file.
17 .It log.html
M · stagit.c +142, -84
 1@@ -248,6 +248,104 @@ err:
 2 return NULL;
 3 }
 4
 5+int
 6+refs_cmp(const void
*v1, const void *v2)
 7+{
 8+ struct referenceinfo
*r1 = (struct referenceinfo *)v1;
 9+ struct referenceinfo
*r2 = (struct referenceinfo *)v2;
 10+ time_t t1, t2;
 11+ int r;
 12+
 13+ if ((r =
git_reference_is_tag(r1->ref) - git_reference_is_tag(r2->ref)))
 14+ return r;
 15+
 16+ t1 =
r1->ci->author ? r1->ci->author->when.time : 0;
 17+ t2 =
r2->ci->author ? r2->ci->author->when.time : 0;
 18+ if ((r = t1 >
t2 ? -1 : (t1 == t2 ? 0 : 1)))
 19+ return r;
 20+
 21+ return
strcmp(git_reference_shorthand(r1->ref),
 22+
git_reference_shorthand(r2->ref));
 23+}
 24+
 25+int
 26+getrefs(struct
referenceinfo **pris, size_t *prefcount)
 27+{
 28+ struct referenceinfo
*ris = NULL;
 29+ struct commitinfo *ci
= NULL;
 30+
git_reference_iterator *it = NULL;
 31+ const git_oid *id =
NULL;
 32+ git_object *obj =
NULL;
 33+ git_reference *dref =
NULL, *r, *ref = NULL;
 34+ size_t i, refcount;
 35+
 36+ *pris = NULL;
 37+ *prefcount = 0;
 38+
 39+ if
(git_reference_iterator_new(&it, repo))
 40+ return -1;
 41+
 42+ for (refcount = 0;
!git_reference_next(&ref, it); ) {
 43+ if
(!git_reference_is_branch(ref) && !git_reference_is_tag(ref)) {
 44+
git_reference_free(ref);
 45+ ref = NULL;
 46+ continue;
 47+ }
 48+
 49+ switch
(git_reference_type(ref)) {
 50+ case
GIT_REF_SYMBOLIC:
 51+ if
(git_reference_resolve(&dref, ref))
 52+ goto err;
 53+ r = dref;
 54+ break;
 55+ case GIT_REF_OID:
 56+ r = ref;
 57+ break;
 58+ default:
 59+ continue;
 60+ }
 61+ if
(!git_reference_target(r) ||
 62+
git_reference_peel(&obj, r, GIT_OBJ_ANY))
 63+ goto err;
 64+ if (!(id =
git_object_id(obj)))
 65+ goto err;
 66+ if (!(ci =
commitinfo_getbyoid(id)))
 67+ break;
 68+
 69+ if (!(ris =
reallocarray(ris, refcount + 1, sizeof(*ris))))
 70+ err(1,
"realloc");
 71+ ris[refcount].ci =
ci;
 72+ ris[refcount].ref =
r;
 73+ refcount++;
 74+
 75+ git_object_free(obj);
 76+ obj = NULL;
 77+
git_reference_free(dref);
 78+ dref = NULL;
 79+ }
 80+
git_reference_iterator_free(it);
 81+
 82+ /* sort by type, date
then shorthand name */
 83+ qsort(ris, refcount,
sizeof(*ris), refs_cmp);
 84+
 85+ *pris = ris;
 86+ *prefcount =
refcount;
 87+
 88+ return 0;
 89+
 90+err:
 91+ git_object_free(obj);
 92+
git_reference_free(dref);
 93+ commitinfo_free(ci);
 94+ for (i = 0; i
< refcount; i++) {
 95+
commitinfo_free(ris[i].ci);
 96+
git_reference_free(ris[i].ref);
 97+ }
 98+ free(ris);
 99+
100+ return -1;
101+}
102+
103 FILE *
104 efopen(const
char *name, const char *flags)
105 {
106@@ -361,6 +459,8 @@ writeheader(FILE *fp, const char *title)
107 fprintf(fp,
"</title>\n<link rel=\"icon\" type=\"image/png\"
href=\"%sfavicon.png\" />\n", relpath);
108 fprintf(fp,
"<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s
Atom Feed\" href=\"%satom.xml\" />\n",
109 name, relpath);
110+ fprintf(fp, "<link rel=\"alternate\"
type=\"application/atom+xml\" title=\"%s Atom Feed (tags)\"
href=\"%stags.xml\" />\n",
111+ name, relpath);
112 fprintf(fp, "<link
rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\"
/>\n", relpath);
113
fputs("</head>\n<body>\n<table><tr><td>",
fp);
114 fprintf(fp,
"<a href=\"../%s\"><img src=\"%slogo.png\"
alt=\"\" width=\"32\" height=\"32\"
/></a>",
115@@ -680,7 +780,7 @@ err:
116 }
117
118 void
119-printcommitatom(FILE *fp, struct commitinfo *ci)
120+printcommitatom(FILE
*fp, struct commitinfo *ci, const char *tag)
121 {
122
fputs("<entry>\n", fp);
123
124@@ -697,6 +797,11 @@ printcommitatom(FILE *fp, struct commitinfo *ci)
125 }
126 if
(ci->summary) {
127
fputs("<title type=\"text\">", fp);
128+ if (tag) {
129+
fputs("[", fp);
130+ xmlencode(fp, tag,
strlen(tag));
131+ fputs("]
", fp);
132+ }
133 xmlencode(fp, ci->summary,
strlen(ci->summary));
134
fputs("</title>\n", fp);
135 }
136@@ -732,8 +837,10 @@ printcommitatom(FILE *fp, struct commitinfo *ci)
137 }
138
139 int
140-writeatom(FILE *fp)
141+writeatom(FILE *fp,
int all)
142 {
143+ struct referenceinfo *ris = NULL;
144+ size_t refcount = 0;
145 struct commitinfo *ci;
146 git_revwalk *w
= NULL;
147 git_oid id;
148@@ -746,17 +853,34 @@ writeatom(FILE *fp)
149 xmlencode(fp, description, strlen(description));
150
fputs("</subtitle>\n", fp);
151
152- git_revwalk_new(&w, repo);
153-
git_revwalk_push_head(w);
154-
git_revwalk_simplify_first_parent(w);
155+ /* all commits or
only tags? */
156+ if (all) {
157+
git_revwalk_new(&w, repo);
158+
git_revwalk_push_head(w);
159+
git_revwalk_simplify_first_parent(w);
160+ for (i = 0; i
< m && !git_revwalk_next(&id, w); i++) {
161+ if (!(ci =
commitinfo_getbyoid(&id)))
162+ break;
163+ printcommitatom(fp,
ci, "");
164+ commitinfo_free(ci);
165+ }
166+ git_revwalk_free(w);
167+ } else {
168+ /* references: tags
*/
169+ if
(getrefs(&ris, &refcount) != -1) {
170+ for (i = 0; i
< refcount; i++) {
171+ if
(!git_reference_is_tag(ris[i].ref))
172+ continue;
173
174- for (i = 0; i < m && !git_revwalk_next(&id, w); i++) {
175- if (!(ci =
commitinfo_getbyoid(&id)))
176- break;
177- printcommitatom(fp,
ci);
178- commitinfo_free(ci);
179+ printcommitatom(fp,
ris[i].ci,
180+
git_reference_shorthand(ris[i].ref));
181+
182+
commitinfo_free(ris[i].ci);
183+
git_reference_free(ris[i].ref);
184+ }
185+ free(ris);
186+ }
187 }
188- git_revwalk_free(w);
189
190
fputs("</feed>\n", fp);
191
192@@ -941,86 +1065,19 @@ writefiles(FILE *fp, const git_oid *id)
193 return ret;
194 }
195
196-int
197-refs_cmp(const void
*v1, const void *v2)
198-{
199- struct referenceinfo
*r1 = (struct referenceinfo *)v1;
200- struct referenceinfo
*r2 = (struct referenceinfo *)v2;
201- time_t t1, t2;
202- int r;
203-
204- if ((r =
git_reference_is_tag(r1->ref) - git_reference_is_tag(r2->ref)))
205- return r;
206-
207- t1 =
r1->ci->author ? r1->ci->author->when.time : 0;
208- t2 =
r2->ci->author ? r2->ci->author->when.time : 0;
209- if ((r = t1 >
t2 ? -1 : (t1 == t2 ? 0 : 1)))
210- return r;
211-
212- return
strcmp(git_reference_shorthand(r1->ref),
213-
git_reference_shorthand(r2->ref));
214-}
215-
216 int
217 writerefs(FILE
*fp)
218 {
219 struct
referenceinfo *ris = NULL;
220 struct
commitinfo *ci;
221- const git_oid *id = NULL;
222- git_object *obj =
NULL;
223- git_reference *dref =
NULL, *r, *ref = NULL;
224-
git_reference_iterator *it = NULL;
225 size_t count, i, j, refcount;
226 const char
*titles[] = { "Branches", "Tags" };
227 const char
*ids[] = { "branches", "tags" };
228 const char *s;
229
230- if (git_reference_iterator_new(&it, repo))
231+ if
(getrefs(&ris, &refcount) == -1)
232 return -1;
233
234- for (refcount = 0; !git_reference_next(&ref, it); ) {
235- if
(!git_reference_is_branch(ref) && !git_reference_is_tag(ref)) {
236-
git_reference_free(ref);
237- ref = NULL;
238- continue;
239- }
240-
241- switch
(git_reference_type(ref)) {
242- case
GIT_REF_SYMBOLIC:
243- if
(git_reference_resolve(&dref, ref))
244- goto err;
245- r = dref;
246- break;
247- case GIT_REF_OID:
248- r = ref;
249- break;
250- default:
251- continue;
252- }
253- if
(!git_reference_target(r) ||
254-
git_reference_peel(&obj, r, GIT_OBJ_ANY))
255- goto err;
256- if (!(id =
git_object_id(obj)))
257- goto err;
258- if (!(ci =
commitinfo_getbyoid(id)))
259- break;
260-
261- if (!(ris =
reallocarray(ris, refcount + 1, sizeof(*ris))))
262- err(1,
"realloc");
263- ris[refcount].ci =
ci;
264- ris[refcount].ref =
r;
265- refcount++;
266-
267- git_object_free(obj);
268- obj = NULL;
269-
git_reference_free(dref);
270- dref = NULL;
271- }
272-
git_reference_iterator_free(it);
273-
274- /* sort by type, date
then shorthand name */
275- qsort(ris, refcount,
sizeof(*ris), refs_cmp);
276-
277 for (i = 0, j = 0, count = 0; i < refcount;
i++) {
278 if (j == 0
&& git_reference_is_tag(ris[i].ref)) {
279 if (count)
280@@ -1056,10 +1113,6 @@ writerefs(FILE *fp)
281 if (count)
282
fputs("</tbody></table><br/>\n", fp);
283
284-err:
285- git_object_free(obj);
286-
git_reference_free(dref);
287-
288 for (i = 0; i < refcount; i++) {
289
commitinfo_free(ris[i].ci);
290
git_reference_free(ris[i].ref);
291@@ -1272,7 +1325,12 @@ main(int argc, char *argv[])
292
293 /* Atom feed */
294 fp =
efopen("atom.xml", "w");
295- writeatom(fp);
296+ writeatom(fp, 1);
297+ fclose(fp);
298+
299+ /* Atom feed for tags
/ releases */
300+ fp =
efopen("tags.xml", "w");
301+ writeatom(fp, 0);
302 fclose(fp);
303
304 /* rename new
cache file on success */