stagit

use git_reference for tags and branches, sort branches also

this removes some lines and somewhat simplifies it

Hiltjo Posthuma contact@arjunchoudhary.com

commit: cbf921a parent: b73724e
1 files changed, 113 insertions(+), 172 deletions(-)
Mstagit.c+113-172
M · stagit.c +113, -172
  1@@ -775,199 +775,140 @@ err:
  2 }
  3 
  4 int
  5-writebranches(FILE *fp)
  6+refs_cmp(const void *v1, const void *v2)
  7 {
  8-	struct commitinfo *ci;
  9-	git_branch_iterator *it = NULL;
 10-	git_branch_t branch;
 11-	git_reference *ref = NULL, *dref = NULL;
 12-	const git_oid *id = NULL;
 13-	const char *branchname = NULL;
 14-	size_t len;
 15-	int ret = -1;
 16-
 17-	/* log for local branches */
 18-	if (git_branch_iterator_new(&it, repo, GIT_BRANCH_LOCAL))
 19-		return -1;
 20-
 21-	fputs("<h2>Branches</h2><table id=\"branches\"><thead>\n<tr><td>Branch</td><td>Age</td>"
 22-		  "<td>Commit message</td>"
 23-		  "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
 24-		  "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp);
 25-
 26-	while (!git_branch_next(&ref, &branch, it)) {
 27-		if (git_branch_name(&branchname, ref))
 28-			continue;
 29-
 30-		id = NULL;
 31-		switch (git_reference_type(ref)) {
 32-		case GIT_REF_SYMBOLIC:
 33-			if (git_reference_resolve(&dref, ref))
 34-				goto err;
 35-			id = git_reference_target(dref);
 36-			break;
 37-		case GIT_REF_OID:
 38-			id = git_reference_target(ref);
 39-			break;
 40-		default:
 41-			continue;
 42-		}
 43-		if (!id)
 44-			goto err;
 45-		if (!(ci = commitinfo_getbyoid(id)))
 46-			break;
 47-
 48-		relpath = "";
 49-
 50-		fputs("<tr><td>", fp);
 51-		xmlencode(fp, branchname, strlen(branchname));
 52-		fputs("</td><td>", fp);
 53-		if (ci->author)
 54-			printtimeshort(fp, &(ci->author->when));
 55-		fputs("</td><td>", fp);
 56-		if (ci->summary) {
 57-			if ((len = strlen(ci->summary)) > summarylen) {
 58-				xmlencode(fp, ci->summary, summarylen - 1);
 59-				fputs("…", fp);
 60-			} else {
 61-				xmlencode(fp, ci->summary, len);
 62-			}
 63-		}
 64-		fputs("</td><td>", fp);
 65-		if (ci->author)
 66-			xmlencode(fp, ci->author->name, strlen(ci->author->name));
 67-		fputs("</td><td class=\"num\">", fp);
 68-		fprintf(fp, "%zu", ci->filecount);
 69-		fputs("</td><td class=\"num\">", fp);
 70-		fprintf(fp, "+%zu", ci->addcount);
 71-		fputs("</td><td class=\"num\">", fp);
 72-		fprintf(fp, "-%zu", ci->delcount);
 73-		fputs("</td></tr>\n", fp);
 74-
 75-		relpath = "../";
 76+	git_reference *r1 = (*(git_reference **)v1);
 77+	git_reference *r2 = (*(git_reference **)v2);
 78+	int t1, t2;
 79 
 80-		commitinfo_free(ci);
 81-		git_reference_free(ref);
 82-		git_reference_free(dref);
 83-		ref = NULL;
 84-		dref = NULL;
 85-	}
 86-	ret = 0;
 87+	t1 = git_reference_is_branch(r1);
 88+	t2 = git_reference_is_branch(r2);
 89 
 90-err:
 91-	fputs("</tbody></table>", fp);
 92-	git_reference_free(ref);
 93-	git_reference_free(dref);
 94-	git_branch_iterator_free(it);
 95+	if (t1 != t2)
 96+		return t1 - t2;
 97 
 98-	return ret;
 99+	return strcmp(git_reference_shorthand(r1),
100+	              git_reference_shorthand(r2));
101 }
102 
103 int
104-tagcompare(void *s1, void *s2)
105-{
106-	return strcmp(*(char **)s1, *(char **)s2);
107-}
108-
109-int
110-writetags(FILE *fp)
111+writerefs(FILE *fp)
112 {
113 	struct commitinfo *ci;
114-	git_strarray tagnames;
115-	git_object *obj = NULL;
116-	git_tag *tag = NULL;
117 	const git_oid *id = NULL;
118-	size_t i, len;
119-
120-	/* summary page with branches and tags */
121-	memset(&tagnames, 0, sizeof(tagnames));
122-	if (git_tag_list(&tagnames, repo))
123+	git_object *obj = NULL;
124+	git_reference *dref = NULL, *r, *ref = NULL;
125+	git_reference_iterator *it = NULL;
126+	git_reference **refs = NULL;
127+	size_t count, i, j, len, refcount = 0;
128+	const char *cols[] = { "Branch", "Tag" }; /* first column title */
129+	const char *titles[] = { "Branches", "Tags" };
130+	const char *ids[] = { "branches", "tags" };
131+	const char *name;
132+
133+	if (git_reference_iterator_new(&it, repo))
134 		return -1;
135-	if (!tagnames.count) {
136-		git_strarray_free(&tagnames);
137-		return 0;
138-	}
139-
140-	/* sort names */
141-	qsort(tagnames.strings, tagnames.count, sizeof(char *),
142-	      (int (*)(const void *, const void *))&tagcompare);
143-
144-	fputs("<h2>Tags</h2><table id=\"tags\"><thead>\n<tr><td>Tag</td>"
145-	      "<td>Age</td><td>Commit message</td>"
146-	      "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
147-	      "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp);
148-
149-	for (i = 0; i < tagnames.count; i++) {
150-		if (git_revparse_single(&obj, repo, tagnames.strings[i]))
151-			continue;
152-		id = git_object_id(obj);
153 
154-		/* lookup actual commit (from annotated tag etc) */
155-		if (!git_tag_lookup(&tag, repo, id)) {
156-			git_object_free(obj);
157-			obj = NULL;
158-			if (git_tag_peel(&obj, tag))
159+	for (refcount = 0; !git_reference_next(&ref, it); refcount++) {
160+		if (!(refs = reallocarray(refs, refcount + 1, sizeof(git_reference *))))
161+			err(1, "realloc");
162+		refs[refcount] = ref;
163+	}
164+	git_reference_iterator_free(it);
165+
166+	/* sort by type then shorthand name */
167+	qsort(refs, refcount, sizeof(git_reference *), refs_cmp);
168+
169+	for (j = 0; j < 2; j++) {
170+		for (i = 0, count = 0; i < refcount; i++) {
171+			if (git_reference_is_branch(refs[i]) && j == 0)
172+				;
173+			else if (git_reference_is_tag(refs[i]) && j == 1)
174+				;
175+			else
176+				continue;
177+
178+			id = NULL;
179+			r = NULL;
180+			switch (git_reference_type(refs[i])) {
181+			case GIT_REF_SYMBOLIC:
182+				if (git_reference_resolve(&dref, refs[i]))
183+					goto err;
184+				r = dref;
185+				break;
186+			case GIT_REF_OID:
187+				r = refs[i];
188+				break;
189+			default:
190+				continue;
191+			}
192+			if (!(id = git_reference_target(r)))
193+				goto err;
194+			if (git_reference_peel(&obj, r, GIT_OBJ_ANY))
195+				goto err;
196+			if (!(id = git_object_id(obj)))
197+				goto err;
198+			if (!(ci = commitinfo_getbyoid(id)))
199 				break;
200-			git_tag_free(tag);
201-			tag = NULL;
202-			id = git_object_id(obj);
203-		}
204-
205-		if (!(ci = commitinfo_getbyoid(id)))
206-			break;
207 
208-		relpath = "";
209+			/* print header if it has an entry (first). */
210+			if (++count == 1) {
211+				fprintf(fp, "<h2>%s</h2><table id=\"%s\"><thead>\n<tr><td>%s</td>"
212+				      "<td>Age</td><td>Commit message</td>"
213+				      "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
214+				      "<td class=\"num\">-</td></tr>\n</thead><tbody>\n",
215+				      titles[j], ids[j], cols[j]);
216+			}
217 
218-		fputs("<tr><td>", fp);
219-		xmlencode(fp, tagnames.strings[i], strlen(tagnames.strings[i]));
220-		fputs("</td><td>", fp);
221-		if (ci->author)
222-			printtimeshort(fp, &(ci->author->when));
223-		fputs("</td><td>", fp);
224-		if (ci->summary) {
225-			fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
226-			if ((len = strlen(ci->summary)) > summarylen) {
227-				xmlencode(fp, ci->summary, summarylen - 1);
228-				fputs("…", fp);
229-			} else {
230-				xmlencode(fp, ci->summary, len);
231+			relpath = "";
232+			name = git_reference_shorthand(r);
233+
234+			fputs("<tr><td>", fp);
235+			xmlencode(fp, name, strlen(name));
236+			fputs("</td><td>", fp);
237+			if (ci->author)
238+				printtimeshort(fp, &(ci->author->when));
239+			fputs("</td><td>", fp);
240+			if (ci->summary) {
241+				fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
242+				if ((len = strlen(ci->summary)) > summarylen) {
243+					xmlencode(fp, ci->summary, summarylen - 1);
244+					fputs("…", fp);
245+				} else {
246+					xmlencode(fp, ci->summary, len);
247+				}
248+				fputs("</a>", fp);
249 			}
250-			fputs("</a>", fp);
251+			fputs("</td><td>", fp);
252+			if (ci->author)
253+				xmlencode(fp, ci->author->name, strlen(ci->author->name));
254+			fputs("</td><td class=\"num\">", fp);
255+			fprintf(fp, "%zu", ci->filecount);
256+			fputs("</td><td class=\"num\">", fp);
257+			fprintf(fp, "+%zu", ci->addcount);
258+			fputs("</td><td class=\"num\">", fp);
259+			fprintf(fp, "-%zu", ci->delcount);
260+			fputs("</td></tr>\n", fp);
261+
262+			relpath = "../";
263+
264+			commitinfo_free(ci);
265+			git_reference_free(dref);
266+			dref = NULL;
267 		}
268-		fputs("</td><td>", fp);
269-		if (ci->author)
270-			xmlencode(fp, ci->author->name, strlen(ci->author->name));
271-		fputs("</td><td class=\"num\">", fp);
272-		fprintf(fp, "%zu", ci->filecount);
273-		fputs("</td><td class=\"num\">", fp);
274-		fprintf(fp, "+%zu", ci->addcount);
275-		fputs("</td><td class=\"num\">", fp);
276-		fprintf(fp, "-%zu", ci->delcount);
277-		fputs("</td></tr>\n", fp);
278-
279-		relpath = "../";
280-
281-		commitinfo_free(ci);
282-		git_object_free(obj);
283-		obj = NULL;
284+		/* table footer */
285+		if (count)
286+			fputs("</tbody></table>", fp);
287 	}
288-	fputs("</tbody></table>", fp);
289-	git_strarray_free(&tagnames);
290-	git_tag_free(tag);
291-	git_object_free(obj);
292 
293-	return 0;
294-}
295+err:
296+	git_reference_free(dref);
297 
298-int
299-writerefs(FILE *fp)
300-{
301-	int ret;
302+	for (i = 0; i < refcount; i++)
303+		git_reference_free(refs[i]);
304+	free(refs);
305 
306-	if ((ret = writebranches(fp)))
307-		return ret;
308-	fputs("<br/>", fp);
309-	return writetags(fp);
310+	return 0;
311 }
312 
313 int